diff --git a/.clang-format b/.clang-format index 7b0fda27c99..cfd991e64ba 100644 --- a/.clang-format +++ b/.clang-format @@ -1,5 +1,5 @@ --- -Language: Cpp +Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: AlwaysBreak AlignConsecutiveAssignments: false @@ -19,52 +19,52 @@ AlwaysBreakTemplateDeclarations: true BinPackArguments: false BinPackParameters: false BraceWrapping: - AfterClass: true + AfterClass: true AfterControlStatement: true - AfterEnum: false - AfterFunction: true - AfterNamespace: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false AfterObjCDeclaration: true - AfterStruct: true - AfterUnion: true - BeforeCatch: true - BeforeElse: true - IndentBraces: false + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false BreakBeforeBinaryOperators: false BreakBeforeBraces: Custom BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: true -ColumnLimit: 80 -CommentPragmas: '^ IWYU pragma:' +ColumnLimit: 80 +CommentPragmas: "^ IWYU pragma:" ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false -DisableFormat: false +DisableFormat: false ExperimentalAutoDetectBinPacking: false -ForEachMacros: [ Q_FOREACH, BOOST_FOREACH ] -IncludeBlocks: Regroup +ForEachMacros: [Q_FOREACH, BOOST_FOREACH] +IncludeBlocks: Regroup IncludeCategories: - - Regex: '^<(test)/' - Priority: 0 - - Regex: '^<(xrpld)/' - Priority: 1 - - Regex: '^<(xrpl)/' - Priority: 2 - - Regex: '^<(boost)/' - Priority: 3 - - Regex: '^.*/' - Priority: 4 - - Regex: '^.*\.h' - Priority: 5 - - Regex: '.*' - Priority: 6 -IncludeIsMainRegex: '$' + - Regex: "^<(test)/" + Priority: 0 + - Regex: "^<(xrpld)/" + Priority: 1 + - Regex: "^<(xrpl)/" + Priority: 2 + - Regex: "^<(boost)/" + Priority: 3 + - Regex: "^.*/" + Priority: 4 + - Regex: '^.*\.h' + Priority: 5 + - Regex: ".*" + Priority: 6 +IncludeIsMainRegex: "$" IndentCaseLabels: true IndentFunctionDeclarationAfterType: false IndentRequiresClause: true -IndentWidth: 4 +IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 1 @@ -78,20 +78,25 @@ PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left -ReflowComments: true +ReflowComments: true RequiresClausePosition: OwnLine -SortIncludes: true +SortIncludes: true SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 -SpacesInAngles: false +SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp11 -TabWidth: 8 -UseTab: Never -QualifierAlignment: Right \ No newline at end of file +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +QualifierAlignment: Right +--- +Language: JavaScript +--- +Language: Json +IndentWidth: 2 diff --git a/.codecov.yml b/.codecov.yml index b97039e8b69..d28d7c80dfe 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -27,7 +27,7 @@ github_checks: parsers: cobertura: partials_as_hits: true - handle_missing_conditions : true + handle_missing_conditions: true slack_app: false diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index a72fc4afd83..a9805e705c0 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -11,3 +11,4 @@ b9d007813378ad0ff45660dc07285b823c7e9855 fe9a5365b8a52d4acc42eb27369247e6f238a4f9 9a93577314e6a8d4b4a8368cc9d2b15a5d8303e8 552377c76f55b403a1c876df873a23d780fcc81c +97f0747e103f13e26e45b731731059b32f7679ac diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index e2df996005d..cc921f5a556 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,30 +2,35 @@ name: Bug Report about: Create a report to help us improve rippled title: "[Title with short description] (Version: [rippled version])" -labels: '' -assignees: '' - +labels: "" +assignees: "" --- + ## Issue Description + ## Steps to Reproduce + ## Expected Result + ## Actual Result + ## Environment + ## Supporting Files + - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 2e19746f520..967b3c18175 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -3,19 +3,23 @@ name: Feature Request about: Suggest a new feature for the rippled project title: "[Title with short description] (Version: [rippled version])" labels: Feature Request -assignees: '' - +assignees: "" --- + ## Summary + ## Motivation + ## Solution + ## Paths Not Taken + diff --git a/.github/actions/dependencies/action.yml b/.github/actions/dependencies/action.yml index afce1557d3b..0bd28f15ddf 100644 --- a/.github/actions/dependencies/action.yml +++ b/.github/actions/dependencies/action.yml @@ -2,56 +2,37 @@ name: dependencies inputs: configuration: required: true -# An implicit input is the environment variable `build_dir`. +# Implicit inputs are the environment variables `build_dir`, CONAN_REMOTE_URL, +# CONAN_REMOTE_USERNAME, and CONAN_REMOTE_PASSWORD. The latter two are only +# used to upload newly built dependencies to the Conan remote. runs: using: composite steps: - - name: unlock Conan - shell: bash - run: conan remove --locks - - name: export custom recipes - shell: bash - run: | - conan config set general.revisions_enabled=1 - conan export external/snappy snappy/1.1.10@ - conan export external/rocksdb rocksdb/9.7.3@ - conan export external/soci soci/4.0.3@ - conan export external/nudb nudb/2.0.8@ - - name: add Ripple Conan remote + - name: add Conan remote + if: ${{ env.CONAN_REMOTE_URL != '' }} shell: bash run: | + echo "Adding Conan remote 'xrplf' at ${{ env.CONAN_REMOTE_URL }}." + conan remote add --index 0 --force xrplf ${{ env.CONAN_REMOTE_URL }} + echo "Listing Conan remotes." conan remote list - conan remote remove ripple || true - # Do not quote the URL. An empty string will be accepted (with - # a non-fatal warning), but a missing argument will not. - conan remote add ripple ${{ env.CONAN_URL }} --insert 0 - - name: try to authenticate to Ripple Conan remote - id: remote - shell: bash - run: | - # `conan user` implicitly uses the environment variables - # CONAN_LOGIN_USERNAME_ and CONAN_PASSWORD_. - # https://docs.conan.io/1/reference/commands/misc/user.html#using-environment-variables - # https://docs.conan.io/1/reference/env_vars.html#conan-login-username-conan-login-username-remote-name - # https://docs.conan.io/1/reference/env_vars.html#conan-password-conan-password-remote-name - echo outcome=$(conan user --remote ripple --password >&2 \ - && echo success || echo failure) | tee ${GITHUB_OUTPUT} - - name: list missing binaries - id: binaries - shell: bash - # Print the list of dependencies that would need to be built locally. - # A non-empty list means we have "failed" to cache binaries remotely. - run: | - echo missing=$(conan info . --build missing --settings build_type=${{ inputs.configuration }} --json 2>/dev/null | grep '^\[') | tee ${GITHUB_OUTPUT} - name: install dependencies shell: bash run: | - mkdir ${build_dir} - cd ${build_dir} + mkdir -p ${{ env.build_dir }} + cd ${{ env.build_dir }} conan install \ --output-folder . \ --build missing \ - --options tests=True \ - --options xrpld=True \ - --settings build_type=${{ inputs.configuration }} \ + --options:host "&:tests=True" \ + --options:host "&:xrpld=True" \ + --settings:all build_type=${{ inputs.configuration }} \ .. + - name: upload dependencies + if: ${{ env.CONAN_REMOTE_URL != '' && env.CONAN_REMOTE_USERNAME != '' && env.CONAN_REMOTE_PASSWORD != '' && github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch }} + shell: bash + run: | + echo "Logging into Conan remote 'xrplf' at ${{ env.CONAN_REMOTE_URL }}." + conan remote login xrplf "${{ env.CONAN_REMOTE_USERNAME }}" --password "${{ env.CONAN_REMOTE_PASSWORD }}" + echo "Uploading dependencies." + conan upload '*' --confirm --check --remote xrplf diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index ac6154ab9f8..0d81f877914 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -9,24 +9,25 @@ jobs: check: if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }} runs-on: ubuntu-24.04 - env: - CLANG_VERSION: 18 + container: ghcr.io/xrplf/ci/tools-rippled-clang-format 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 - - name: Install clang-format - run: | - codename=$( lsb_release --codename --short ) - sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null <&2 \ + echo outcome=$(conan user --remote xrplf --password >&2 \ && echo success || echo failure) | tee ${GITHUB_OUTPUT} - name: Upload new package id: upload diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 63d54175ea6..73e25c357f4 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -11,13 +11,27 @@ on: - release - master # Branches that opt-in to running - - 'ci/**' + - "ci/**" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# This part of Conan configuration is specific to this workflow only; we do not want +# to pollute conan/profiles directory with settings which might not work for others +env: + CONAN_REMOTE_URL: https://conan.ripplex.io + CONAN_REMOTE_USERNAME: ${{ secrets.CONAN_REMOTE_USERNAME }} + CONAN_REMOTE_PASSWORD: ${{ secrets.CONAN_REMOTE_PASSWORD }} + # This part of the Conan configuration is specific to this workflow only; we + # do not want to pollute the 'conan/profiles' directory with settings that + # might not work for other workflows. + CONAN_GLOBAL_CONF: | + core.download:parallel={{os.cpu_count()}} + core.upload:parallel={{os.cpu_count()}} + tools.build:jobs={{ (os.cpu_count() * 4/5) | int }} + tools.build:verbosity=verbose + tools.compilation:verbosity=verbose jobs: - test: if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }} strategy: @@ -28,23 +42,22 @@ jobs: - Ninja configuration: - Release - runs-on: [self-hosted, macOS] + runs-on: [self-hosted, macOS, mac-runner-m1] env: # The `build` action requires these variables. build_dir: .build NUM_PROCESSORS: 12 steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: install Conan run: | - brew install conan@1 - echo '/opt/homebrew/opt/conan@1/bin' >> $GITHUB_PATH + brew install conan - name: install Ninja if: matrix.generator == 'Ninja' run: brew install ninja - name: install python - run: | + run: | if which python > /dev/null 2>&1; then echo "Python executable exists" else @@ -75,15 +88,12 @@ jobs: sysctl -n hw.logicalcpu clang --version - name: configure Conan - run : | - conan profile new default --detect || true - conan profile update settings.compiler.cppstd=20 default + run: | + echo "${CONAN_GLOBAL_CONF}" > $(conan config home)/global.conf + conan config install conan/profiles/ -tf $(conan config home)/profiles/ + conan profile show - name: build dependencies uses: ./.github/actions/dependencies - env: - CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod - CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }} - CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }} with: configuration: ${{ matrix.configuration }} - name: build @@ -96,4 +106,7 @@ jobs: run: | n=$(nproc) echo "Using $n test jobs" - ${build_dir}/rippled --unittest --unittest-jobs $n + + cd ${build_dir} + ./rippled --unittest --unittest-jobs $n + ctest -j $n --output-on-failure diff --git a/.github/workflows/missing-commits.yml b/.github/workflows/missing-commits.yml index 8715671f33f..ed478a2327a 100644 --- a/.github/workflows/missing-commits.yml +++ b/.github/workflows/missing-commits.yml @@ -12,49 +12,49 @@ jobs: up_to_date: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Check for missing commits - id: commits - env: - SUGGESTION: | + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Check for missing commits + id: commits + env: + SUGGESTION: | - If you are reading this, then the commits indicated above are - missing from "develop" and/or "release". Do a reverse-merge - as soon as possible. See CONTRIBUTING.md for instructions. - run: | - set -o pipefail - # Branches ordered by how "canonical" they are. Every commit in - # one branch should be in all the branches behind it - order=( master release develop ) - branches=() - for branch in "${order[@]}" - do - # Check that the branches exist so that this job will work on - # forked repos, which don't necessarily have master and - # release branches. - if git ls-remote --exit-code --heads origin \ - refs/heads/${branch} > /dev/null - then - branches+=( origin/${branch} ) - fi - done + If you are reading this, then the commits indicated above are + missing from "develop" and/or "release". Do a reverse-merge + as soon as possible. See CONTRIBUTING.md for instructions. + run: | + set -o pipefail + # Branches ordered by how "canonical" they are. Every commit in + # one branch should be in all the branches behind it + order=( master release develop ) + branches=() + for branch in "${order[@]}" + do + # Check that the branches exist so that this job will work on + # forked repos, which don't necessarily have master and + # release branches. + if git ls-remote --exit-code --heads origin \ + refs/heads/${branch} > /dev/null + then + branches+=( origin/${branch} ) + fi + done - prior=() - for branch in "${branches[@]}" - do - if [[ ${#prior[@]} -ne 0 ]] + prior=() + for branch in "${branches[@]}" + do + if [[ ${#prior[@]} -ne 0 ]] + then + echo "Checking ${prior[@]} for commits missing from ${branch}" + git log --oneline --no-merges "${prior[@]}" \ + ^$branch | tee -a "missing-commits.txt" + echo + fi + prior+=( "${branch}" ) + done + if [[ $( cat missing-commits.txt | wc -l ) -ne 0 ]] then - echo "Checking ${prior[@]} for commits missing from ${branch}" - git log --oneline --no-merges "${prior[@]}" \ - ^$branch | tee -a "missing-commits.txt" - echo + echo "${SUGGESTION}" + exit 1 fi - prior+=( "${branch}" ) - done - if [[ $( cat missing-commits.txt | wc -l ) -ne 0 ]] - then - echo "${SUGGESTION}" - exit 1 - fi diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index de59e077612..395bd72b8dc 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -16,6 +16,20 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + CONAN_REMOTE_URL: https://conan.ripplex.io + CONAN_REMOTE_USERNAME: ${{ secrets.CONAN_REMOTE_USERNAME }} + CONAN_REMOTE_PASSWORD: ${{ secrets.CONAN_REMOTE_PASSWORD }} + # This part of the Conan configuration is specific to this workflow only; we + # do not want to pollute the 'conan/profiles' directory with settings that + # might not work for other workflows. + CONAN_GLOBAL_CONF: | + core.download:parallel={{ os.cpu_count() }} + core.upload:parallel={{ os.cpu_count() }} + tools.build:jobs={{ (os.cpu_count() * 4/5) | int }} + tools.build:verbosity=verbose + tools.compilation:verbosity=verbose + # This workflow has multiple job matrixes. # They can be considered phases because most of the matrices ("test", # "coverage", "conan", ) depend on the first ("dependencies"). @@ -54,59 +68,45 @@ jobs: - Release include: - compiler: gcc - profile: - version: 11 - cc: /usr/bin/gcc - cxx: /usr/bin/g++ + compiler_version: 12 + distro: ubuntu + codename: jammy - compiler: clang - profile: - version: 14 - cc: /usr/bin/clang-14 - cxx: /usr/bin/clang++-14 + compiler_version: 16 + distro: debian + codename: bookworm runs-on: [self-hosted, heavy] - container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e + container: ghcr.io/xrplf/ci/${{ matrix.distro }}-${{ matrix.codename }}:${{ matrix.compiler }}-${{ matrix.compiler_version }} env: build_dir: .build steps: - - name: upgrade conan - run: | - pip install --upgrade "conan<2" - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: check environment run: | echo ${PATH} | tr ':' '\n' lsb_release -a || true - ${{ matrix.profile.cc }} --version + ${{ matrix.compiler }}-${{ matrix.compiler_version }} --version conan --version cmake --version env | sort - name: configure Conan run: | - conan profile new default --detect - conan profile update settings.compiler.cppstd=20 default - conan profile update settings.compiler=${{ matrix.compiler }} default - conan profile update settings.compiler.version=${{ matrix.profile.version }} default - conan profile update settings.compiler.libcxx=libstdc++11 default - conan profile update env.CC=${{ matrix.profile.cc }} default - conan profile update env.CXX=${{ matrix.profile.cxx }} default - conan profile update conf.tools.build:compiler_executables='{"c": "${{ matrix.profile.cc }}", "cpp": "${{ matrix.profile.cxx }}"}' default + echo "${CONAN_GLOBAL_CONF}" >> $(conan config home)/global.conf + conan config install conan/profiles/ -tf $(conan config home)/profiles/ + conan profile show - name: archive profile # Create this archive before dependencies are added to the local cache. - run: tar -czf conan.tar -C ~/.conan . + run: tar -czf conan.tar.gz -C ${CONAN_HOME} . - name: build dependencies uses: ./.github/actions/dependencies - env: - CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod - CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }} - CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }} with: configuration: ${{ matrix.configuration }} - name: upload archive - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} - path: conan.tar + path: conan.tar.gz if-no-files-found: error test: @@ -121,26 +121,32 @@ jobs: configuration: - Debug - Release + include: + - compiler: gcc + compiler_version: 12 + distro: ubuntu + codename: jammy + - compiler: clang + compiler_version: 16 + distro: debian + codename: bookworm cmake-args: - - "-Dunity=ON" needs: dependencies runs-on: [self-hosted, heavy] - container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e + container: ghcr.io/xrplf/ci/${{ matrix.distro }}-${{ matrix.codename }}:${{ matrix.compiler }}-${{ matrix.compiler_version }} env: build_dir: .build steps: - - name: upgrade conan - run: | - pip install --upgrade "conan<2" - name: download cache - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} - name: extract cache run: | - mkdir -p ~/.conan - tar -xzf conan.tar -C ~/.conan + mkdir -p ${CONAN_HOME} + tar -xzf conan.tar.gz -C ${CONAN_HOME} - name: check environment run: | env | sort @@ -148,11 +154,9 @@ jobs: conan --version cmake --version - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: dependencies uses: ./.github/actions/dependencies - env: - CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod with: configuration: ${{ matrix.configuration }} - name: build @@ -161,9 +165,21 @@ jobs: generator: Ninja configuration: ${{ matrix.configuration }} cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}" + - name: check linking + run: | + cd ${build_dir} + ldd ./rippled + if [ "$(ldd ./rippled | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then + echo 'The binary is statically linked.' + else + echo 'The binary is dynamically linked.' + exit 1 + fi - name: test run: | - ${build_dir}/rippled --unittest --unittest-jobs $(nproc) + cd ${build_dir} + ./rippled --unittest --unittest-jobs $(nproc) + ctest -j $(nproc) --output-on-failure reference-fee-test: strategy: @@ -180,21 +196,18 @@ jobs: - "-DUNIT_TEST_REFERENCE_FEE=1000" needs: dependencies runs-on: [self-hosted, heavy] - container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e + container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12 env: build_dir: .build steps: - - name: upgrade conan - run: | - pip install --upgrade "conan<2" - name: download cache - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} - name: extract cache run: | - mkdir -p ~/.conan - tar -xzf conan.tar -C ~/.conan + mkdir -p ${CONAN_HOME} + tar -xzf conan.tar.gz -C ${CONAN_HOME} - name: check environment run: | env | sort @@ -202,11 +215,9 @@ jobs: conan --version cmake --version - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: dependencies uses: ./.github/actions/dependencies - env: - CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod with: configuration: ${{ matrix.configuration }} - name: build @@ -217,7 +228,9 @@ jobs: cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}" - name: test run: | - ${build_dir}/rippled --unittest --unittest-jobs $(nproc) + cd ${build_dir} + ./rippled --unittest --unittest-jobs $(nproc) + ctest -j $(nproc) --output-on-failure coverage: strategy: @@ -231,23 +244,18 @@ jobs: - Debug needs: dependencies runs-on: [self-hosted, heavy] - container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e + container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12 env: build_dir: .build steps: - - name: upgrade conan - run: | - pip install --upgrade "conan<2" - name: download cache - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} - name: extract cache run: | - mkdir -p ~/.conan - tar -xzf conan.tar -C ~/.conan - - name: install gcovr - run: pip install "gcovr>=7,<9" + mkdir -p ${CONAN_HOME} + tar -xzf conan.tar.gz -C ${CONAN_HOME} - name: check environment run: | echo ${PATH} | tr ':' '\n' @@ -255,13 +263,11 @@ jobs: cmake --version gcovr --version env | sort - ls ~/.conan + ls ${CONAN_HOME} - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: dependencies uses: ./.github/actions/dependencies - env: - CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod with: configuration: ${{ matrix.configuration }} - name: build @@ -283,7 +289,7 @@ jobs: run: | mv "${build_dir}/coverage.xml" ./ - name: archive coverage report - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: coverage.xml path: coverage.xml @@ -305,22 +311,23 @@ jobs: conan: needs: dependencies runs-on: [self-hosted, heavy] - container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e + container: + image: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12 env: build_dir: .build + platform: linux + compiler: gcc + compiler_version: 12 configuration: Release steps: - - name: upgrade conan - run: | - pip install --upgrade "conan<2" - name: download cache - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: - name: linux-gcc-${{ env.configuration }} + name: ${{ env.platform }}-${{ env.compiler }}-${{ env.configuration }} - name: extract cache run: | - mkdir -p ~/.conan - tar -xzf conan.tar -C ~/.conan + mkdir -p ${CONAN_HOME} + tar -xzf conan.tar.gz -C ${CONAN_HOME} - name: check environment run: | env | sort @@ -328,116 +335,88 @@ jobs: conan --version cmake --version - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: dependencies uses: ./.github/actions/dependencies - env: - CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod with: configuration: ${{ env.configuration }} - name: export run: | - version=$(conan inspect --raw version .) - reference="xrpl/${version}@local/test" - conan remove -f ${reference} || true - conan export . local/test - echo "reference=${reference}" >> "${GITHUB_ENV}" + conan export . --version head - name: build run: | cd tests/conan - mkdir ${build_dir} - cd ${build_dir} - conan install .. --output-folder . \ - --require-override ${reference} --build missing + mkdir ${build_dir} && cd ${build_dir} + conan install .. \ + --settings:all build_type=${configuration} \ + --output-folder . \ + --build missing cmake .. \ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=./build/${configuration}/generators/conan_toolchain.cmake \ -DCMAKE_BUILD_TYPE=${configuration} cmake --build . ./example | grep '^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+' - # NOTE we are not using dependencies built above because it lags with - # compiler versions. Instrumentation requires clang version 16 or - # later - instrumentation-build: - if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }} - env: - CLANG_RELEASE: 16 - strategy: - fail-fast: false + needs: dependencies runs-on: [self-hosted, heavy] - container: debian:bookworm + container: ghcr.io/xrplf/ci/debian-bookworm:clang-16 + env: + build_dir: .build steps: - - name: install prerequisites - env: - DEBIAN_FRONTEND: noninteractive - run: | - apt-get update - apt-get install --yes --no-install-recommends \ - clang-${CLANG_RELEASE} clang++-${CLANG_RELEASE} \ - python3-pip python-is-python3 make cmake git wget - apt-get clean - update-alternatives --install \ - /usr/bin/clang clang /usr/bin/clang-${CLANG_RELEASE} 100 \ - --slave /usr/bin/clang++ clang++ /usr/bin/clang++-${CLANG_RELEASE} - update-alternatives --auto clang - pip install --no-cache --break-system-packages "conan<2" + - name: download cache + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 + with: + name: linux-clang-Debug + + - name: extract cache + run: | + mkdir -p ${CONAN_HOME} + tar -xzf conan.tar.gz -C ${CONAN_HOME} - - name: checkout - uses: actions/checkout@v4 + - name: check environment + run: | + echo ${PATH} | tr ':' '\n' + conan --version + cmake --version + env | sort + ls ${CONAN_HOME} - - name: prepare environment - run: | - mkdir ${GITHUB_WORKSPACE}/.build - echo "SOURCE_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV - echo "BUILD_DIR=$GITHUB_WORKSPACE/.build" >> $GITHUB_ENV - echo "CC=/usr/bin/clang" >> $GITHUB_ENV - echo "CXX=/usr/bin/clang++" >> $GITHUB_ENV + - name: checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - name: configure Conan - run: | - conan profile new --detect default - conan profile update settings.compiler=clang default - conan profile update settings.compiler.version=${CLANG_RELEASE} default - conan profile update settings.compiler.libcxx=libstdc++11 default - conan profile update settings.compiler.cppstd=20 default - conan profile update options.rocksdb=False default - conan profile update \ - 'conf.tools.build:compiler_executables={"c": "/usr/bin/clang", "cpp": "/usr/bin/clang++"}' default - conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default - conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default - conan export external/snappy snappy/1.1.10@ - conan export external/soci soci/4.0.3@ + - name: dependencies + uses: ./.github/actions/dependencies + with: + configuration: Debug - - name: build dependencies - run: | - cd ${BUILD_DIR} - conan install ${SOURCE_DIR} \ - --output-folder ${BUILD_DIR} \ - --install-folder ${BUILD_DIR} \ - --build missing \ - --settings build_type=Debug + - name: prepare environment + run: | + mkdir -p ${build_dir} + echo "SOURCE_DIR=$(pwd)" >> $GITHUB_ENV + echo "BUILD_DIR=$(pwd)/${build_dir}" >> $GITHUB_ENV - - name: build with instrumentation - run: | - cd ${BUILD_DIR} - cmake -S ${SOURCE_DIR} -B ${BUILD_DIR} \ - -Dvoidstar=ON \ - -Dtests=ON \ - -Dxrpld=ON \ - -DCMAKE_BUILD_TYPE=Debug \ - -DSECP256K1_BUILD_BENCHMARK=OFF \ - -DSECP256K1_BUILD_TESTS=OFF \ - -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ - -DCMAKE_TOOLCHAIN_FILE=${BUILD_DIR}/build/generators/conan_toolchain.cmake - cmake --build . --parallel $(nproc) + - name: build with instrumentation + run: | + cd ${BUILD_DIR} + cmake -S ${SOURCE_DIR} -B ${BUILD_DIR} \ + -Dvoidstar=ON \ + -Dtests=ON \ + -Dxrpld=ON \ + -DCMAKE_BUILD_TYPE=Debug \ + -DSECP256K1_BUILD_BENCHMARK=OFF \ + -DSECP256K1_BUILD_TESTS=OFF \ + -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ + -DCMAKE_TOOLCHAIN_FILE=${BUILD_DIR}/build/generators/conan_toolchain.cmake + cmake --build . --parallel $(nproc) - - name: verify instrumentation enabled - run: | - cd ${BUILD_DIR} - ./rippled --version | grep libvoidstar + - name: verify instrumentation enabled + run: | + cd ${BUILD_DIR} + ./rippled --version | grep libvoidstar - - name: run unit tests - run: | - cd ${BUILD_DIR} - ./rippled -u --unittest-jobs $(( $(nproc)/4 )) + - name: run unit tests + run: | + cd ${BUILD_DIR} + ./rippled -u --unittest-jobs $(( $(nproc)/4 )) + ctest -j $(nproc) --output-on-failure diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 1d90c2ef58c..b81ffc8d3a1 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -12,15 +12,27 @@ on: - release - master # Branches that opt-in to running - - 'ci/**' + - "ci/**" # https://docs.github.com/en/actions/using-jobs/using-concurrency concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + CONAN_REMOTE_URL: https://conan.ripplex.io + CONAN_REMOTE_USERNAME: ${{ secrets.CONAN_REMOTE_USERNAME }} + CONAN_REMOTE_PASSWORD: ${{ secrets.CONAN_REMOTE_PASSWORD }} + # This part of the Conan configuration is specific to this workflow only; we + # do not want to pollute the 'conan/profiles' directory with settings that + # might not work for other workflows. + CONAN_GLOBAL_CONF: | + core.download:parallel={{os.cpu_count()}} + core.upload:parallel={{os.cpu_count()}} + tools.build:jobs=24 + tools.build:verbosity=verbose + tools.compilation:verbosity=verbose jobs: - test: if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }} strategy: @@ -42,11 +54,11 @@ jobs: build_dir: .build steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: choose Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 with: - python-version: 3.9 + python-version: 3.13 - name: learn Python cache directory id: pip-cache shell: bash @@ -54,12 +66,12 @@ jobs: python -m pip install --upgrade pip echo "dir=$(pip cache dir)" | tee ${GITHUB_OUTPUT} - name: restore Python cache directory - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-${{ hashFiles('.github/workflows/windows.yml') }} + path: ${{ steps.pip-cache.outputs.dir }} + key: ${{ runner.os }}-${{ hashFiles('.github/workflows/windows.yml') }} - name: install Conan - run: pip install wheel 'conan<2' + run: pip install wheel conan - name: check environment run: | dir env: @@ -70,30 +82,25 @@ jobs: - name: configure Conan shell: bash run: | - conan profile new default --detect - conan profile update settings.compiler.cppstd=20 default - conan profile update \ - settings.compiler.runtime=MT${{ matrix.configuration.runtime }} \ - default + echo "${CONAN_GLOBAL_CONF}" > $(conan config home)/global.conf + conan config install conan/profiles/ -tf $(conan config home)/profiles/ + conan profile show - name: build dependencies uses: ./.github/actions/dependencies - env: - CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod - CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }} - CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }} with: configuration: ${{ matrix.configuration.type }} - name: build uses: ./.github/actions/build with: - generator: '${{ matrix.version.generator }}' + generator: "${{ matrix.version.generator }}" configuration: ${{ matrix.configuration.type }} # Hard code for now. Move to the matrix if varied options are needed - cmake-args: '-Dassert=TRUE -Dwerr=TRUE -Dreporting=OFF -Dunity=ON' + cmake-args: "-Dassert=TRUE -Dwerr=TRUE -Dreporting=OFF -Dunity=ON" cmake-target: install - name: test shell: bash if: ${{ matrix.configuration.tests }} run: | - ${build_dir}/${{ matrix.configuration.type }}/rippled --unittest \ - --unittest-jobs $(nproc) + cd ${build_dir}/${{ matrix.configuration.type }} + ./rippled --unittest --unittest-jobs $(nproc) + ctest -j $(nproc) --output-on-failure diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9f69d413797..7daecdb5ec3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ # .pre-commit-config.yaml repos: -- repo: https://github.com/pre-commit/mirrors-clang-format - rev: v18.1.3 - hooks: - - id: clang-format + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v18.1.8 + hooks: + - id: clang-format diff --git a/BUILD.md b/BUILD.md index 1ba767cd887..c8ec31f826d 100644 --- a/BUILD.md +++ b/BUILD.md @@ -3,29 +3,29 @@ | These instructions assume you have a C++ development environment ready with Git, Python, Conan, CMake, and a C++ compiler. For help setting one up on Linux, macOS, or Windows, [see this guide](./docs/build/environment.md). | > These instructions also assume a basic familiarity with Conan and CMake. -> If you are unfamiliar with Conan, -> you can read our [crash course](./docs/build/conan.md) -> or the official [Getting Started][3] walkthrough. +> If you are unfamiliar with Conan, you can read our +> [crash course](./docs/build/conan.md) or the official [Getting Started][3] +> walkthrough. ## Branches For a stable release, choose the `master` branch or one of the [tagged releases](https://github.com/ripple/rippled/releases). -``` +```bash git checkout master ``` For the latest release candidate, choose the `release` branch. -``` +```bash git checkout release ``` For the latest set of untested features, or to contribute, choose the `develop` branch. -``` +```bash git checkout develop ``` @@ -33,176 +33,323 @@ git checkout develop See [System Requirements](https://xrpl.org/system-requirements.html). -Building rippled generally requires git, Python, Conan, CMake, and a C++ compiler. Some guidance on setting up such a [C++ development environment can be found here](./docs/build/environment.md). +Building rippled generally requires git, Python, Conan, CMake, and a C++ +compiler. Some guidance on setting up such a [C++ development environment can be +found here](./docs/build/environment.md). + +- [Python 3.11](https://www.python.org/downloads/), or higher +- [Conan 2.17](https://conan.io/downloads.html)[^1], or higher +- [CMake 3.22](https://cmake.org/download/)[^2], or higher -- [Python 3.7](https://www.python.org/downloads/) -- [Conan 1.60](https://conan.io/downloads.html)[^1] -- [CMake 3.16](https://cmake.org/download/) +[^1]: + It is possible to build with Conan 1.60+, but the instructions are + significantly different, which is why we are not recommending it. -[^1]: It is possible to build with Conan 2.x, -but the instructions are significantly different, -which is why we are not recommending it yet. -Notably, the `conan profile update` command is removed in 2.x. -Profiles must be edited by hand. +[^2]: + CMake 4 is not yet supported by all dependencies required by this project. + If you are affected by this issue, follow [conan workaround for cmake + 4](#workaround-for-cmake-4) `rippled` is written in the C++20 dialect and includes the `` header. The [minimum compiler versions][2] required are: -| Compiler | Version | -|-------------|---------| -| GCC | 11 | -| Clang | 13 | -| Apple Clang | 13.1.6 | -| MSVC | 19.23 | +| Compiler | Version | +| ----------- | --------- | +| GCC | 12 | +| Clang | 16 | +| Apple Clang | 16 | +| MSVC | 19.44[^3] | ### Linux -The Ubuntu operating system has received the highest level of -quality assurance, testing, and support. +The Ubuntu Linux distribution has received the highest level of quality +assurance, testing, and support. We also support Red Hat and use Debian +internally. -Here are [sample instructions for setting up a C++ development environment on Linux](./docs/build/environment.md#linux). +Here are [sample instructions for setting up a C++ development environment on +Linux](./docs/build/environment.md#linux). ### Mac Many rippled engineers use macOS for development. -Here are [sample instructions for setting up a C++ development environment on macOS](./docs/build/environment.md#macos). +Here are [sample instructions for setting up a C++ development environment on +macOS](./docs/build/environment.md#macos). ### Windows -Windows is not recommended for production use at this time. +Windows is used by some engineers for development only. -- Additionally, 32-bit Windows development is not supported. - -[Boost]: https://www.boost.org/ +[^3]: Windows is not recommended for production use. ## Steps ### Set Up Conan -After you have a [C++ development environment](./docs/build/environment.md) ready with Git, Python, Conan, CMake, and a C++ compiler, you may need to set up your Conan profile. +After you have a [C++ development environment](./docs/build/environment.md) ready with Git, Python, +Conan, CMake, and a C++ compiler, you may need to set up your Conan profile. -These instructions assume a basic familiarity with Conan and CMake. +These instructions assume a basic familiarity with Conan and CMake. If you are +unfamiliar with Conan, then please read [this crash course](./docs/build/conan.md) or the official +[Getting Started][3] walkthrough. -If you are unfamiliar with Conan, then please read [this crash course](./docs/build/conan.md) or the official [Getting Started][3] walkthrough. +#### Default profile -You'll need at least one Conan profile: +We recommend that you import the provided `conan/profiles/default` profile: - ``` - conan profile new default --detect - ``` +```bash +conan config install conan/profiles/ -tf $(conan config home)/profiles/ +``` -Update the compiler settings: +You can check your Conan profile by running: - ``` - conan profile update settings.compiler.cppstd=20 default - ``` +```bash +conan profile show +``` -Configure Conan (1.x only) to use recipe revisions: +#### Custom profile - ``` - conan config set general.revisions_enabled=1 - ``` +If the default profile does not work for you and you do not yet have a Conan +profile, you can create one by running: + +```bash +conan profile detect +``` -**Linux** developers will commonly have a default Conan [profile][] that compiles -with GCC and links with libstdc++. -If you are linking with libstdc++ (see profile setting `compiler.libcxx`), -then you will need to choose the `libstdc++11` ABI: +You may need to make changes to the profile to suit your environment. You can +refer to the provided `conan/profiles/default` profile for inspiration, and you +may also need to apply the required [tweaks](#conan-profile-tweaks) to this +default profile. - ``` - conan profile update settings.compiler.libcxx=libstdc++11 default - ``` +### Patched recipes +The recipes in Conan Center occasionally need to be patched for compatibility +with the latest version of `rippled`. We maintain a fork of the Conan Center +[here](https://github.com/XRPLF/conan-center-index/) containing the patches. -Ensure inter-operability between `boost::string_view` and `std::string_view` types: +To ensure our patched recipes are used, you must add our Conan remote at a +higher index than the default Conan Center remote, so it is consulted first. You +can do this by running: +```bash +conan remote add --index 0 xrplf "https://conan.ripplex.io" ``` -conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_BEAST_USE_STD_STRING_VIEW"]' default -conan profile update 'env.CXXFLAGS="-DBOOST_BEAST_USE_STD_STRING_VIEW"' default + +Alternatively, you can pull the patched recipes into the repository and use them +locally: + +```bash +cd external +git init +git remote add origin git@github.com:XRPLF/conan-center-index.git +git sparse-checkout init +git sparse-checkout set recipes/snappy +git sparse-checkout add recipes/soci +git fetch origin master +git checkout master +conan export --version 1.1.10 recipes/snappy/all +conan export --version 4.0.3 recipes/soci/all +rm -rf .git ``` -If you have other flags in the `conf.tools.build` or `env.CXXFLAGS` sections, make sure to retain the existing flags and append the new ones. You can check them with: +In the case we switch to a newer version of a dependency that still requires a +patch, it will be necessary for you to pull in the changes and re-export the +updated dependencies with the newer version. However, if we switch to a newer +version that no longer requires a patch, no action is required on your part, as +the new recipe will be automatically pulled from the official Conan Center. + +### Conan profile tweaks + +#### Missing compiler version + +If you see an error similar to the following after running `conan profile show`: + +```bash +ERROR: Invalid setting '17' is not a valid 'settings.compiler.version' value. +Possible values are ['5.0', '5.1', '6.0', '6.1', '7.0', '7.3', '8.0', '8.1', +'9.0', '9.1', '10.0', '11.0', '12.0', '13', '13.0', '13.1', '14', '14.0', '15', +'15.0', '16', '16.0'] +Read "http://docs.conan.io/2/knowledge/faq.html#error-invalid-setting" ``` -conan profile show default + +you need to amend the list of compiler versions in +`$(conan config home)/settings.yml`, by appending the required version number(s) +to the `version` array specific for your compiler. For example: + +```yaml +apple-clang: + version: + [ + "5.0", + "5.1", + "6.0", + "6.1", + "7.0", + "7.3", + "8.0", + "8.1", + "9.0", + "9.1", + "10.0", + "11.0", + "12.0", + "13", + "13.0", + "13.1", + "14", + "14.0", + "15", + "15.0", + "16", + "16.0", + "17", + "17.0", + ] ``` +#### Multiple compilers -**Windows** developers may need to use the x64 native build tools. -An easy way to do that is to run the shortcut "x64 Native Tools Command -Prompt" for the version of Visual Studio that you have installed. +If you have multiple compilers installed, make sure to select the one to use in +your default Conan configuration **before** running `conan profile detect`, by +setting the `CC` and `CXX` environment variables. - Windows developers must also build `rippled` and its dependencies for the x64 - architecture: +For example, if you are running MacOS and have [homebrew +LLVM@18](https://formulae.brew.sh/formula/llvm@18), and want to use it as a +compiler in the new Conan profile: - ``` - conan profile update settings.arch=x86_64 default - ``` +```bash +export CC=$(brew --prefix llvm@18)/bin/clang +export CXX=$(brew --prefix llvm@18)/bin/clang++ +conan profile detect +``` -### Multiple compilers +You should also explicitly set the path to the compiler in the profile file, +which helps to avoid errors when `CC` and/or `CXX` are set and disagree with the +selected Conan profile. For example: -When `/usr/bin/g++` exists on a platform, it is the default cpp compiler. This -default works for some users. +```text +[conf] +tools.build:compiler_executables={'c':'/usr/bin/gcc','cpp':'/usr/bin/g++'} +``` -However, if this compiler cannot build rippled or its dependencies, then you can -install another compiler and set Conan and CMake to use it. -Update the `conf.tools.build:compiler_executables` setting in order to set the correct variables (`CMAKE__COMPILER`) in the -generated CMake toolchain file. -For example, on Ubuntu 20, you may have gcc at `/usr/bin/gcc` and g++ at `/usr/bin/g++`; if that is the case, you can select those compilers with: +#### Multiple profiles + +You can manage multiple Conan profiles in the directory +`$(conan config home)/profiles`, for example renaming `default` to a different +name and then creating a new `default` profile for a different compiler. + +#### Select language + +The default profile created by Conan will typically select different C++ dialect +than C++20 used by this project. You should set `20` in the profile line +starting with `compiler.cppstd=`. For example: + +```bash +sed -i.bak -e 's|^compiler\.cppstd=.*$|compiler.cppstd=20|' $(conan config home)/profiles/default ``` -conan profile update 'conf.tools.build:compiler_executables={"c": "/usr/bin/gcc", "cpp": "/usr/bin/g++"}' default + +#### Select standard library in Linux + +**Linux** developers will commonly have a default Conan [profile][] that +compiles with GCC and links with libstdc++. If you are linking with libstdc++ +(see profile setting `compiler.libcxx`), then you will need to choose the +`libstdc++11` ABI: + +```bash +sed -i.bak -e 's|^compiler\.libcxx=.*$|compiler.libcxx=libstdc++11|' $(conan config home)/profiles/default ``` -Replace `/usr/bin/gcc` and `/usr/bin/g++` with paths to the desired compilers. +#### Select architecture and runtime in Windows -It should choose the compiler for dependencies as well, -but not all of them have a Conan recipe that respects this setting (yet). -For the rest, you can set these environment variables. -Replace `` with paths to the desired compilers: +**Windows** developers may need to use the x64 native build tools. An easy way +to do that is to run the shortcut "x64 Native Tools Command Prompt" for the +version of Visual Studio that you have installed. -- `conan profile update env.CC= default` -- `conan profile update env.CXX= default` +Windows developers must also build `rippled` and its dependencies for the x64 +architecture: -Export our [Conan recipe for Snappy](./external/snappy). -It does not explicitly link the C++ standard library, -which allows you to statically link it with GCC, if you want. +```bash +sed -i.bak -e 's|^arch=.*$|arch=x86_64|' $(conan config home)/profiles/default +``` - ``` - # Conan 1.x - conan export external/snappy snappy/1.1.10@ - # Conan 2.x - conan export --version 1.1.10 external/snappy - ``` +**Windows** developers also must select static runtime: -Export our [Conan recipe for RocksDB](./external/rocksdb). -It does not override paths to dependencies when building with Visual Studio. +```bash +sed -i.bak -e 's|^compiler\.runtime=.*$|compiler.runtime=static|' $(conan config home)/profiles/default +``` - ``` - # Conan 1.x - conan export external/rocksdb rocksdb/9.7.3@ - # Conan 2.x - conan export --version 9.7.3 external/rocksdb - ``` +#### Workaround for CMake 4 -Export our [Conan recipe for SOCI](./external/soci). -It patches their CMake to correctly import its dependencies. +If your system CMake is version 4 rather than 3, you may have to configure Conan +profile to use CMake version 3 for dependencies, by adding the following two +lines to your profile: - ``` - # Conan 1.x - conan export external/soci soci/4.0.3@ - # Conan 2.x - conan export --version 4.0.3 external/soci - ``` +```text +[tool_requires] +!cmake/*: cmake/[>=3 <4] +``` -Export our [Conan recipe for NuDB](./external/nudb). -It fixes some source files to add missing `#include`s. +This will force Conan to download and use a locally cached CMake 3 version, and +is needed because some of the dependencies used by this project do not support +CMake 4. +#### Clang workaround for grpc - ``` - # Conan 1.x - conan export external/nudb nudb/2.0.8@ - # Conan 2.x - conan export --version 2.0.8 external/nudb - ``` +If your compiler is clang, version 19 or later, or apple-clang, version 17 or +later, you may encounter a compilation error while building the `grpc` +dependency: + +```text +In file included from .../lib/promise/try_seq.h:26: +.../lib/promise/detail/basic_seq.h:499:38: error: a template argument list is expected after a name prefixed by the template keyword [-Wmissing-template-arg-list-after-template-kw] + 499 | Traits::template CallSeqFactory(f_, *cur_, std::move(arg))); + | ^ +``` + +The workaround for this error is to add two lines to profile: + +```text +[conf] +tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw'] +``` + +#### Workaround for gcc 12 + +If your compiler is gcc, version 12, and you have enabled `werr` option, you may +encounter a compilation error such as: + +```text +/usr/include/c++/12/bits/char_traits.h:435:56: error: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' accessing 9223372036854775810 or more bytes at offsets [2, 9223372036854775807] and 1 may overlap up to 9223372036854775813 bytes at offset -3 [-Werror=restrict] + 435 | return static_cast(__builtin_memcpy(__s1, __s2, __n)); + | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~ +cc1plus: all warnings being treated as errors +``` + +The workaround for this error is to add two lines to your profile: + +```text +[conf] +tools.build:cxxflags=['-Wno-restrict'] +``` + +#### Workaround for clang 16 + +If your compiler is clang, version 16, you may encounter compilation error such +as: + +```text +In file included from .../boost/beast/websocket/stream.hpp:2857: +.../boost/beast/websocket/impl/read.hpp:695:17: error: call to 'async_teardown' is ambiguous + async_teardown(impl.role, impl.stream(), + ^~~~~~~~~~~~~~ +``` + +The workaround for this error is to add two lines to your profile: + +```text +[conf] +tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS'] +``` ### Build and Test @@ -224,71 +371,70 @@ It fixes some source files to add missing `#include`s. 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=Debug - ``` + ``` + conan install .. --output-folder . --build missing --settings build_type=Release + 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`, - you only need to run this command once. - For a multi-configuration generator, e.g. `Visual Studio`, you may want to - run it more than once. + For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`, + you only need to run this command once. + For a multi-configuration generator, e.g. `Visual Studio`, you may want to + run it more than once. - 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 - 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, - under the section `[settings]` with the key `build_type`. + 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 + 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, + under the section `[settings]` with the key `build_type`. - If you are using a Microsoft Visual C++ compiler, - then you will need to ensure consistency between the `build_type` setting - and the `compiler.runtime` setting. + If you are using a Microsoft Visual C++ compiler, + then you will need to ensure consistency between the `build_type` 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=Debug --settings compiler.runtime=MTd - ``` + ``` + 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 + ``` 3. Configure CMake and pass the toolchain file generated by Conan, located at `$OUTPUT_FOLDER/build/generators/conan_toolchain.cmake`. - Single-config generators: - - Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type] - and make sure it matches the one of the `build_type` settings - you chose in the previous step. + Single-config generators: - For example, to build Debug, in the next command, replace "Release" with "Debug" + Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type] + and make sure it matches the one of the `build_type` settings + you chose in the previous step. - ``` - cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -Dxrpld=ON -Dtests=ON .. - ``` + 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 .. + ``` - 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 `rippled` in this step. + **Note:** You can pass build options for `rippled` in this step. -5. Build `rippled`. +4. Build `rippled`. For a single-configuration generator, it will build whatever configuration - you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator, - you must pass the option `--config` to select the build configuration. + you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator, you + must pass the option `--config` to select the build configuration. Single-config generators: ``` - cmake --build . -j $(nproc) + cmake --build . ``` Multi-config generators: @@ -298,24 +444,27 @@ It fixes some source files to add missing `#include`s. cmake --build . --config Debug ``` -6. Test rippled. +5. Test rippled. Single-config generators: ``` - ./rippled --unittest + ./rippled --unittest --unittest-jobs N ``` Multi-config generators: ``` - ./Release/rippled --unittest - ./Debug/rippled --unittest + ./Release/rippled --unittest --unittest-jobs N + ./Debug/rippled --unittest --unittest-jobs N ``` - The location of `rippled` in your build directory depends on your CMake - generator. Pass `--help` to see the rest of the command line options. + Replace the `--unittest-jobs` parameter N with the desired unit tests + concurrency. Recommended setting is half of the number of available CPU + cores. + The location of `rippled` binary in your build directory depends on your + CMake generator. Pass `--help` to see the rest of the command line options. ## Coverage report @@ -356,7 +505,7 @@ variable in `cmake`. The specific command line used to run the `gcovr` tool will displayed if the `CODE_COVERAGE_VERBOSE` variable is set. By default, the code coverage tool runs parallel unit tests with `--unittest-jobs` - set to the number of available CPU cores. This may cause spurious test +set to the number of available CPU cores. This may cause spurious test errors on Apple. Developers can override the number of unit test jobs with the `coverage_test_parallelism` variable in `cmake`. @@ -372,45 +521,56 @@ cmake --build . --target coverage After the `coverage` target is completed, the generated coverage report will be 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. - ## Options -| Option | Default Value | Description | -| --- | ---| ---| -| `assert` | OFF | Enable assertions. -| `coverage` | OFF | Prepare the coverage report. | -| `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. | -| `tests` | OFF | Build tests. | -| `unity` | ON | Configure a unity build. | -| `xrpld` | OFF | Build the xrpld (`rippled`) application, and not just the libxrpl library. | +| Option | Default Value | Description | +| ---------- | ------------- | -------------------------------------------------------------------------- | +| `assert` | OFF | Enable assertions. | +| `coverage` | OFF | Prepare the coverage report. | +| `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. | +| `tests` | OFF | Build tests. | +| `unity` | OFF | Configure a unity build. | +| `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 (at the cost of much more memory) since they concatenate sources into fewer translation units. Non-unity builds may be faster for incremental builds, and can be helpful for detecting `#include` omissions. - ## Troubleshooting - ### Conan After any updates or changes to dependencies, you may need to do the following: 1. Remove your build directory. -2. Remove the Conan cache: +2. Remove individual libraries from the Conan cache, e.g. + + ```bash + conan remove 'grpc/*' ``` - rm -rf ~/.conan/data + + **or** + + Remove all libraries from Conan cache: + + ```bash + conan remove '*' ``` -4. Re-run [conan install](#build-and-test). +3. Re-run [conan export](#patched-recipes) if needed. +4. Re-run [conan install](#build-and-test). -### 'protobuf/port_def.inc' file not found +### `protobuf/port_def.inc` file not found -If `cmake --build .` results in an error due to a missing a protobuf file, then you might have generated CMake files for a different `build_type` than the `CMAKE_BUILD_TYPE` you passed to conan. +If `cmake --build .` results in an error due to a missing a protobuf file, then +you might have generated CMake files for a different `build_type` than the +`CMAKE_BUILD_TYPE` you passed to Conan. ``` /rippled/.build/pb-xrpl.libpb/xrpl/proto/ripple.pb.h:10:10: fatal error: 'google/protobuf/port_def.inc' file not found @@ -424,70 +584,21 @@ For example, if you want to build Debug: 1. For conan install, pass `--settings build_type=Debug` 2. For cmake, pass `-DCMAKE_BUILD_TYPE=Debug` - -### no std::result_of - -If your compiler version is recent enough to have removed `std::result_of` as -part of C++20, e.g. Apple Clang 15.0, then you might need to add a preprocessor -definition to your build. - -``` -conan profile update 'options.boost:extra_b2_flags="define=BOOST_ASIO_HAS_STD_INVOKE_RESULT"' default -conan profile update 'env.CFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"' default -conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"' default -conan profile update 'conf.tools.build:cflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"]' default -conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"]' default -``` - - -### call to 'async_teardown' is ambiguous - -If you are compiling with an early version of Clang 16, then you might hit -a [regression][6] when compiling C++20 that manifests as an [error in a Boost -header][7]. You can workaround it by adding this preprocessor definition: - -``` -conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default -conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default -``` - - -### recompile with -fPIC - -If you get a linker error suggesting that you recompile Boost with -position-independent code, such as: - -``` -/usr/bin/ld.gold: error: /home/username/.conan/data/boost/1.77.0/_/_/package/.../lib/libboost_container.a(alloc_lib.o): - requires unsupported dynamic reloc 11; recompile with -fPIC -``` - -Conan most likely downloaded a bad binary distribution of the dependency. -This seems to be a [bug][1] in Conan just for Boost 1.77.0 compiled with GCC -for Linux. The solution is to build the dependency locally by passing -`--build boost` when calling `conan install`. - -``` -conan install --build boost ... -``` - - ## Add a Dependency If you want to experiment with a new package, follow these steps: 1. Search for the package on [Conan Center](https://conan.io/center/). 2. Modify [`conanfile.py`](./conanfile.py): - - Add a version of the package to the `requires` property. - - Change any default options for the package by adding them to the - `default_options` property (with syntax `'$package:$option': $value`). + - Add a version of the package to the `requires` property. + - Change any default options for the package by adding them to the + `default_options` property (with syntax `'$package:$option': $value`). 3. Modify [`CMakeLists.txt`](./CMakeLists.txt): - - Add a call to `find_package($package REQUIRED)`. - - Link a library from the package to the target `ripple_libs` - (search for the existing call to `target_link_libraries(ripple_libs INTERFACE ...)`). + - Add a call to `find_package($package REQUIRED)`. + - Link a library from the package to the target `ripple_libs` + (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. - [1]: https://github.com/conan-io/conan-center-index/issues/13168 [2]: https://en.cppreference.com/w/cpp/compiler_support/20 [3]: https://docs.conan.io/en/latest/getting_started.html diff --git a/Builds/levelization/README.md b/Builds/levelization/README.md index 4ff3a54236a..93aa316b613 100644 --- a/Builds/levelization/README.md +++ b/Builds/levelization/README.md @@ -25,28 +25,28 @@ more dependencies listed later. **tl;dr:** The modules listed first are more independent than the modules listed later. -| Level / Tier | Module(s) | -|--------------|-----------------------------------------------| -| 01 | ripple/beast ripple/unity -| 02 | ripple/basics -| 03 | ripple/json ripple/crypto -| 04 | ripple/protocol -| 05 | ripple/core ripple/conditions ripple/consensus ripple/resource ripple/server -| 06 | ripple/peerfinder ripple/ledger ripple/nodestore ripple/net -| 07 | ripple/shamap ripple/overlay -| 08 | ripple/app -| 09 | ripple/rpc -| 10 | ripple/perflog -| 11 | test/jtx test/beast test/csf -| 12 | test/unit_test -| 13 | test/crypto test/conditions test/json test/resource test/shamap test/peerfinder test/basics test/overlay -| 14 | test -| 15 | test/net test/protocol test/ledger test/consensus test/core test/server test/nodestore -| 16 | test/rpc test/app +| Level / Tier | Module(s) | +| ------------ | -------------------------------------------------------------------------------------------------------- | +| 01 | ripple/beast ripple/unity | +| 02 | ripple/basics | +| 03 | ripple/json ripple/crypto | +| 04 | ripple/protocol | +| 05 | ripple/core ripple/conditions ripple/consensus ripple/resource ripple/server | +| 06 | ripple/peerfinder ripple/ledger ripple/nodestore ripple/net | +| 07 | ripple/shamap ripple/overlay | +| 08 | ripple/app | +| 09 | ripple/rpc | +| 10 | ripple/perflog | +| 11 | test/jtx test/beast test/csf | +| 12 | test/unit_test | +| 13 | test/crypto test/conditions test/json test/resource test/shamap test/peerfinder test/basics test/overlay | +| 14 | test | +| 15 | test/net test/protocol test/ledger test/consensus test/core test/server test/nodestore | +| 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 -that `test` code should *never* be included in `ripple` code.) +that `test` code should _never_ be included in `ripple` code.) ## 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. It generates many files of [results](results): -* `rawincludes.txt`: The raw dump of the `#includes` -* `paths.txt`: A second dump grouping the source module +- `rawincludes.txt`: The raw dump of the `#includes` +- `paths.txt`: A second dump grouping the source module 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_. -* `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 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 desired as described above. In a perfect repo, this file will be empty. This file is committed to the repo, and is used by the [levelization Github workflow](../../.github/workflows/levelization.yml) to validate 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 opposed to how they are desired as described above. This file is committed to the repo, and is used by the [levelization Github workflow](../../.github/workflows/levelization.yml) to validate 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 - 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 done anything else to improve levelization, run `levelization.sh`, 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 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. These results can be included in both `loops.txt` and `ordering.txt`. Because `ordering.txt`only includes relationships where B is not 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 definitively say that one should be above the other. These results 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 will only be included in `loops.txt`. @@ -110,5 +110,5 @@ get those details locally. 1. Run `levelization.sh` 2. Grep the modules in `paths.txt`. - * For example, if a cycle is found `A ~= B`, simply `grep -w - A Builds/levelization/results/paths.txt | grep -w B` + - For example, if a cycle is found `A ~= B`, simply `grep -w +A Builds/levelization/results/paths.txt | grep -w B` diff --git a/Builds/levelization/results/ordering.txt b/Builds/levelization/results/ordering.txt index eca7fc6dc29..ce22d8edb0a 100644 --- a/Builds/levelization/results/ordering.txt +++ b/Builds/levelization/results/ordering.txt @@ -132,6 +132,7 @@ test.shamap > xrpl.protocol test.toplevel > test.csf test.toplevel > xrpl.json test.unit_test > xrpl.basics +tests.libxrpl > xrpl.basics xrpl.json > xrpl.basics xrpl.protocol > xrpl.basics xrpl.protocol > xrpl.json diff --git a/CMakeLists.txt b/CMakeLists.txt index a9f063db57b..c71fb685990 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,11 @@ set_target_properties(OpenSSL::SSL PROPERTIES INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2 ) 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_library(secp256k1::secp256k1 ALIAS secp256k1) add_subdirectory(external/ed25519-donna) @@ -144,3 +149,8 @@ set(PROJECT_EXPORT_SET RippleExports) include(RippledCore) include(RippledInstall) include(RippledValidatorKeys) + +if(tests) + include(CTest) + add_subdirectory(src/tests/libxrpl) +endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cb3eb6f0481..b0ae72ae54d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,13 +8,12 @@ We assume you are familiar with the general practice of [making contributions on GitHub][contrib]. This file includes only special instructions specific to this project. - ## Before you start The following branches exist in the main project repository: - `develop`: The latest set of unreleased features, and the most common - starting point for contributions. + starting point for contributions. - `release`: The latest beta release or release candidate. - `master`: The latest stable release. - `gh-pages`: The documentation for this project, built by Doxygen. @@ -27,18 +26,18 @@ In general, external contributions should be developed in your personal [fork][forking]. Contributions from developers with write permissions should be done in [the main repository][rippled] in a branch with a permitted prefix. Permitted prefixes are: -* XLS-[a-zA-Z0-9]+/.+ - * e.g. XLS-0033d/mpt-clarify-STEitherAmount -* [GitHub username]/.+ - * e.g. JoelKatz/fix-rpc-webhook-queue -* [Organization name]/.+ - * e.g. ripple/antithesis - -Regardless of where the branch is created, please open a *draft* pull + +- XLS-[a-zA-Z0-9]+/.+ + - e.g. XLS-0033d/mpt-clarify-STEitherAmount +- [GitHub username]/.+ + - e.g. JoelKatz/fix-rpc-webhook-queue +- [Organization name]/.+ + - e.g. ripple/antithesis + +Regardless of where the branch is created, please open a _draft_ pull request as soon as possible after pushing the branch to Github, to increase visibility, and ease feedback during the development process. - ## Major contributions If your contribution is a major feature or breaking change, then you @@ -55,8 +54,8 @@ responsibility of the XLS author to update the draft to match the final implementation when its corresponding pull request is merged, unless the author delegates that responsibility to others. - ## Before making a pull request + (Or marking a draft pull request as ready.) Changes that alter transaction processing must be guarded by an @@ -73,11 +72,12 @@ automatic test run by `rippled --unittest`. Otherwise, it must be a manual test. If you create new source files, they must be organized as follows: -* If the files are in any of the `libxrpl` modules, the headers (`.h`) must go + +- If the files are in any of the `libxrpl` modules, the headers (`.h`) must go under `include/xrpl`, and source (`.cpp`) files must go under `src/libxrpl`. -* All other non-test files must go under `src/xrpld`. -* All test source files must go under `src/test`. +- All other non-test files must go under `src/xrpld`. +- All test source files must go under `src/test`. The source must be formatted according to the style guide below. @@ -87,16 +87,17 @@ Changes should be usually squashed down into a single commit. Some larger or more complicated change sets make more sense, and are easier to review if organized into multiple logical commits. 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. Specifically, chronological commits that simply reflect the history of how the author implemented the change, "warts and all", are not useful to 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. -* Every commit should be signed. -* Every commit should be well-formed (builds successfully, +- Every commit should be signed. +- Every commit should be well-formed (builds successfully, unit tests passing), as this helps to resolve merge conflicts, and makes it easier to use `git bisect` to find bugs. @@ -108,13 +109,14 @@ Refer to for general rules on writing a good commit message. tl;dr + > 1. Separate subject from body with a blank line. > 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. > 4. Do not end the subject line with a period. > 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 > _your subject line here_". > 6. Wrap the body at 72 characters. @@ -122,16 +124,17 @@ tl;dr In addition to those guidelines, please add one of the following prefixes to the subject line if appropriate. -* `fix:` - The primary purpose is to fix an existing bug. -* `perf:` - The primary purpose is performance improvements. -* `refactor:` - The changes refactor code without affecting + +- `fix:` - The primary purpose is to fix an existing bug. +- `perf:` - The primary purpose is performance improvements. +- `refactor:` - The changes refactor code without affecting functionality. -* `test:` - The changes _only_ affect unit tests. -* `docs:` - The changes _only_ affect documentation. This can +- `test:` - The changes _only_ affect unit tests. +- `docs:` - The changes _only_ affect documentation. This can 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. -* `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 Github Actions jobs. @@ -143,9 +146,10 @@ unit tests for Feature X (#1234)`. In general, pull requests use `develop` as the base branch. The exceptions are -* Fixes and improvements to a release candidate use `release` as the + +- Fixes and improvements to a release candidate use `release` as the base. -* Hotfixes use `master` as the base. +- Hotfixes use `master` as the base. If your changes are not quite ready, but you want to make it easily available for preliminary examination or review, you can create a "Draft" pull request. @@ -182,11 +186,11 @@ meets a few criteria: 2. All CI checks must be complete and passed. (One-off failures may be acceptable if they are related to a known issue.) 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. - * Any contributor, preferably the author, can leave a comment + - Any contributor, preferably the author, can leave a comment 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 as well. 4. The PR branch must be up to date with the base branch (usually @@ -208,7 +212,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 coherent rather than a set of _thou shalt not_ commandments. - ## Formatting All code must conform to `clang-format` version 18, @@ -237,6 +240,7 @@ To download the patch file: 5. Commit and push. You can install a pre-commit hook to automatically run `clang-format` before every commit: + ``` pip3 install pre-commit pre-commit install @@ -267,49 +271,51 @@ locations, where the reporting of contract violations on the Antithesis platform is either not possible or not useful. For this reason: -* The locations where `assert` or `assert(false)` contracts should continue to be used: - * `constexpr` functions - * unit tests i.e. files under `src/test` - * 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, + +- The locations where `assert` or `assert(false)` contracts should continue to be used: + - `constexpr` functions + - unit tests i.e. files under `src/test` + - 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. -* 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 condition being violated -* 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 +- 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 (typically at most five words) description. `UNREACHABLE` contracts 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 name. NOTE: the purpose of name is to provide stable means of unique identification of every contract; for this reason try to avoid elements 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". -* 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. -* Example good name for an +- Example good name for an `UNREACHABLE` macro `"Json::operator==(Value, Value) : invalid type"`; example 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"` (missing namespace, unnecessary full function signature, description too verbose). 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`) -* 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) -* Do not use `std::unreachable` -* Do not put contracts where they can be violated by an external condition +- Do not use `std::unreachable` +- 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 bogus bug reports (and causes crashes of Debug builds) ## Unit Tests + To execute all unit tests: -```rippled --unittest --unittest-jobs=``` +`rippled --unittest --unittest-jobs=` -(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.) To run a specific set of test suites: @@ -317,10 +323,11 @@ To run a specific set of test suites: ``` rippled --unittest TestSuiteName ``` + Note: In this example, all tests with prefix `TestSuiteName` will be run, so if -`TestSuiteName1` and `TestSuiteName2` both exist, then both tests will run. -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` +`TestSuiteName1` and `TestSuiteName2` both exist, then both tests will run. +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` exists, then no other unit test will be executed, apart from `TestSuiteName`. ## Avoid @@ -336,7 +343,6 @@ exists, then no other unit test will be executed, apart from `TestSuiteName`. explanatory comments. 8. Importing new libraries unless there is a very good reason to do so. - ## Seek to 9. Extend functionality of existing code rather than creating new code. @@ -351,14 +357,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 would need to understand what your code does. - # Maintainers 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 made, etc. - ## Adding and removing New maintainers can be proposed by two existing maintainers, subject to a vote @@ -373,47 +377,41 @@ A minimum of 60% agreement and 50% participation are required. The XRP Ledger Foundation will have the ability, for cause, to remove an existing maintainer without a vote. - ## Current Maintainers Maintainers are users with maintain or admin access to the repo. -* [bthomee](https://github.com/bthomee) (Ripple) -* [intelliot](https://github.com/intelliot) (Ripple) -* [JoelKatz](https://github.com/JoelKatz) (Ripple) -* [nixer89](https://github.com/nixer89) (XRP Ledger Foundation) -* [RichardAH](https://github.com/RichardAH) (XRP Ledger Foundation) -* [Silkjaer](https://github.com/Silkjaer) (XRP Ledger Foundation) -* [WietseWind](https://github.com/WietseWind) (XRPL Labs + XRP Ledger Foundation) -* [ximinez](https://github.com/ximinez) (Ripple) - +- [bthomee](https://github.com/bthomee) (Ripple) +- [intelliot](https://github.com/intelliot) (Ripple) +- [JoelKatz](https://github.com/JoelKatz) (Ripple) +- [legleux](https://github.com/legleux) (Ripple) +- [mankins](https://github.com/mankins) (XRP Ledger Foundation) +- [WietseWind](https://github.com/WietseWind) (XRPL Labs + XRP Ledger Foundation) +- [ximinez](https://github.com/ximinez) (Ripple) ## Current Code Reviewers Code Reviewers are developers who have the ability to review, approve, and in some cases merge source code changes. -* [HowardHinnant](https://github.com/HowardHinnant) (Ripple) -* [scottschurr](https://github.com/scottschurr) (Ripple) -* [seelabs](https://github.com/seelabs) (Ripple) -* [Ed Hennis](https://github.com/ximinez) (Ripple) -* [mvadari](https://github.com/mvadari) (Ripple) -* [thejohnfreeman](https://github.com/thejohnfreeman) (Ripple) -* [Bronek](https://github.com/Bronek) (Ripple) -* [manojsdoshi](https://github.com/manojsdoshi) (Ripple) -* [godexsoft](https://github.com/godexsoft) (Ripple) -* [mDuo13](https://github.com/mDuo13) (Ripple) -* [ckniffen](https://github.com/ckniffen) (Ripple) -* [arihantkothari](https://github.com/arihantkothari) (Ripple) -* [pwang200](https://github.com/pwang200) (Ripple) -* [sophiax851](https://github.com/sophiax851) (Ripple) -* [shawnxie999](https://github.com/shawnxie999) (Ripple) -* [gregtatcam](https://github.com/gregtatcam) (Ripple) -* [mtrippled](https://github.com/mtrippled) (Ripple) -* [ckeshava](https://github.com/ckeshava) (Ripple) -* [nbougalis](https://github.com/nbougalis) None -* [RichardAH](https://github.com/RichardAH) (XRPL Labs + XRP Ledger Foundation) -* [dangell7](https://github.com/dangell7) (XRPL Labs) +- [a1q123456](https://github.com/a1q123456) (Ripple) +- [Bronek](https://github.com/Bronek) (Ripple) +- [bthomee](https://github.com/bthomee) (Ripple) +- [ckeshava](https://github.com/ckeshava) (Ripple) +- [dangell7](https://github.com/dangell7) (XRPL Labs) +- [godexsoft](https://github.com/godexsoft) (Ripple) +- [gregtatcam](https://github.com/gregtatcam) (Ripple) +- [kuznetsss](https://github.com/kuznetsss) (Ripple) +- [lmaisons](https://github.com/lmaisons) (Ripple) +- [mathbunnyru](https://github.com/mathbunnyru) (Ripple) +- [mvadari](https://github.com/mvadari) (Ripple) +- [oleks-rip](https://github.com/oleks-rip) (Ripple) +- [PeterChen13579](https://github.com/PeterChen13579) (Ripple) +- [pwang200](https://github.com/pwang200) (Ripple) +- [q73zhao](https://github.com/q73zhao) (Ripple) +- [shawnxie999](https://github.com/shawnxie999) (Ripple) +- [Tapanito](https://github.com/Tapanito) (Ripple) +- [ximinez](https://github.com/ximinez) (Ripple) Developers not on this list are able and encouraged to submit feedback on pending code changes (open pull requests). @@ -423,6 +421,7 @@ on pending code changes (open pull requests). These instructions assume you have your git upstream remotes configured to avoid accidental pushes to the main repo, and a remote group specifying both of them. e.g. + ``` $ git remote -v | grep upstream upstream https://github.com/XRPLF/rippled.git (fetch) @@ -437,6 +436,7 @@ upstream upstream-push You can use the [setup-upstreams] script to set this up. It also assumes you have a default gpg signing key set up in git. e.g. + ``` $ git config user.signingkey 968479A1AFF927E37D1A566BB5690EEEBB952194 @@ -461,8 +461,8 @@ the suggested commit message, or modify it as needed. #### Slightly more complicated pull requests Some pull requests need to be pushed to `develop` as more than one -commit. A PR author may *request* to merge as separate commits. They -must *justify* why separate commits are needed, and *specify* how they +commit. A PR author may _request_ to merge as separate commits. They +must _justify_ why separate commits are needed, and _specify_ how they would like the commits to be merged. If you disagree with the author, discuss it with them directly. @@ -471,20 +471,22 @@ fast forward only merge (`--ff-only`) on the command line and push to `develop`. Some examples of when separate commits are worthwhile are: + 1. PRs where source files are reorganized in multiple steps. -2. PRs where the commits are mostly independent and *could* be separate +2. PRs where the commits are mostly independent and _could_ be separate PRs, but are pulled together into one PR under a commit theme or issue. 3. PRs that are complicated enough that `git bisect` would not be much help if it determined this PR introduced a problem. Either way, check that: -* The commits are based on the current tip of `develop`. -* The commits are clean: No merge commits (except when reverse + +- The commits are based on the current tip of `develop`. +- The commits are clean: No merge commits (except when reverse merging), no "[FOLD]" or "fixup!" messages. -* All commits are signed. If the commits are not signed by the author, use +- All commits are signed. If the commits are not signed by the author, use `git commit --amend -S` to sign them yourself. -* At least one (but preferably all) of the commits has the PR number +- At least one (but preferably all) of the commits has the PR number in the commit message. The "Create a merge commit" and "Rebase and merge" options should be @@ -502,13 +504,13 @@ Rippled uses a linear workflow model that can be summarized as: 1. In between releases, developers work against the `develop` branch. 2. Periodically, a maintainer will build and tag a beta version from `develop`, which is pushed to `release`. - * Betas are usually released every two to three weeks, though that + - Betas are usually released every two to three weeks, though that schedule can vary depending on progress, availability, and other factors. 3. When the changes in `develop` are considered stable and mature enough to be ready to release, a release candidate (RC) is built and tagged from `develop`, and merged to `release`. - * Further development for that release (primarily fixes) then + - Further development for that release (primarily fixes) then continues against `release`, while other development continues on `develop`. Effectively, `release` is forked from `develop`. Changes to `release` must be reverse merged to `develop`. @@ -543,6 +545,7 @@ Rippled uses a linear workflow model that can be summarized as: the version number, etc. The workflow may look something like: + ``` git fetch --multiple upstreams user1 user2 user3 [...] git checkout -B release-next --no-track upstream/develop @@ -581,8 +584,9 @@ This includes, betas, and the first release candidate (RC). 1. If you didn't create one [preparing the `develop` branch](#preparing-the-develop-branch), Ensure there is no old - `release-next` branch hanging around. Then make a `release-next` + `release-next` branch hanging around. Then make a `release-next` branch that only changes the version number. e.g. + ``` git fetch upstreams @@ -603,25 +607,30 @@ git push upstream-push git fetch upstreams git branch --set-upstream-to=upstream/release-next ``` - You can also use the [update-version] script. -2. Create a Pull Request for `release-next` with **`develop`** as - the base branch. - 1. Use the title "[TRIVIAL] Set version to X.X.X-bX". - 2. Instead of the default description template, use the following: + +You can also use the [update-version] script. 2. Create a Pull Request for `release-next` with **`develop`** as +the base branch. + +1. Use the title "[TRIVIAL] Set version to X.X.X-bX". +2. Instead of the default description template, use the following: + ``` ## High Level Overview of Change This PR only changes the version number. It will be merged as soon as Github CI actions successfully complete. ``` + 3. Wait for CI to successfully complete, and get someone to approve the PR. (It is safe to ignore known CI issues.) 4. Push the updated `develop` branch using your `release-next` branch. **Do not use the Github UI. It's important to preserve commit IDs.** + ``` git push upstream-push release-next:develop ``` + 5. In the unlikely event that the push fails because someone has merged something else in the meantime, rebase your branch onto the updated `develop` branch, push again, and go back to step 3. @@ -630,22 +639,25 @@ git push upstream-push release-next:develop 7. Once this is done, forward progress on `develop` can continue (other PRs may be merged). 8. Now create a Pull Request for `release-next` with **`release`** as - the base branch. Instead of the default template, reuse and update + the base branch. Instead of the default template, reuse and update the message from the previous release. Include the following verbiage somewhere in the description: + ``` The base branch is `release`. [All releases (including betas)](https://github.com/XRPLF/rippled/blob/develop/CONTRIBUTING.md#before-you-start) go in `release`. This PR branch will be pushed directly to `release` (not squashed or rebased, and not using the GitHub UI). ``` + 7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur offline, but at least one approval will be needed on the PR. - * If issues are discovered during testing, simply abandon the - release. It's easy to start a new release, it should be easy to + - If issues are discovered during testing, simply abandon the + release. It's easy to start a new release, it should be easy to abandon one. **DO NOT REUSE THE VERSION NUMBER.** e.g. If you abandon 2.4.0-b1, the next attempt will be 2.4.0-b2. 8. Once everything is ready to go, push to `release`. + ``` git fetch upstreams @@ -666,23 +678,28 @@ git log -1 --oneline # Other branches, including some from upstream-push, may also be # present. ``` + 9. Tag the release, too. + ``` git tag git push upstream-push ``` + 10. Delete the `release-next` branch on the repo. Use the Github UI or: + ``` git push --delete upstream-push release-next ``` + 11. Finally [create a new release on Github](https://github.com/XRPLF/rippled/releases). #### Release candidates after the first Once the first release candidate is [merged into -release](#making-the-release), then `release` and `develop` *are allowed -to diverge*. +release](#making-the-release), then `release` and `develop` _are allowed +to diverge_. If a bug or issue is discovered in a version that has a release candidate being tested, any fix and new version will need to be applied @@ -690,7 +707,7 @@ against `release`, then reverse-merged to `develop`. This helps keep git history as linear as possible. A `release-next` branch will be created from `release`, and any further -work for that release must be based on `release-next`. Specifically, +work for that release must be based on `release-next`. Specifically, PRs must use `release-next` as the base, and those PRs will be merged directly to `release-next` when approved. Changes should be restricted to bug fixes, but other changes may be necessary from time to time. @@ -713,17 +730,21 @@ Once the RC is merged and tagged, it needs to be reverse merged into 1. Create a branch, based on `upstream/develop`. The branch name is not important, but could include "mergeNNNrcN". E.g. For release A.B.C-rcD, use `mergeABCrcD`. + ``` git fetch upstreams git checkout --no-track -b mergeABCrcD upstream/develop ``` + 2. Merge `release` into your branch. + ``` # I like the "--edit --log --verbose" parameters, but they are # not required. git merge upstream/release ``` + 3. `BuildInfo.cpp` will have a conflict with the version number. Resolve it with the version from `develop` - the higher version. 4. Push your branch to your repo (or `upstream` if you have permission), @@ -731,22 +752,27 @@ git merge upstream/release simply indicate that this is a merge of the RC. The "Context" should summarize the changes from the RC. Include the following text prominently: + ``` This PR must be merged manually using a push. Do not use the Github UI. ``` + 5. Depending on the complexity of the changes, and/or merge conflicts, the PR may need a thorough review, or just a sign-off that the merge was done correctly. 6. If `develop` is updated before this PR is merged, do not merge `develop` back into your branch. Instead rebase preserving merges, or do the merge again. (See also the `rerere` git config setting.) + ``` git rebase --rebase-merges upstream/develop # OR git reset --hard upstream/develop git merge upstream/release ``` + 7. When the PR is ready, push it to `develop`. + ``` git fetch upstreams @@ -757,8 +783,8 @@ git push upstream-push mergeABCrcD:develop git fetch upstreams ``` -Development on `develop` can proceed as normal. +Development on `develop` can proceed as normal. #### Final releases @@ -773,7 +799,7 @@ internally as if they were RCs (at minimum, ensuring unit tests pass, and the app starts, syncs, and stops cleanly across all three platforms.) -*If in doubt, make an RC first.* +_If in doubt, make an RC first._ The process for building a final release is very similar to [the process for building a beta](#making-the-release), except the code will be @@ -785,20 +811,23 @@ moving from `release` to `master` instead of from `develop` to number. As above, or using the [update-version] script. 2. Create a Pull Request for `master-next` with **`master`** as - the base branch. Instead of the default template, reuse and update + the base branch. Instead of the default template, reuse and update the message from the previous final release. Include the following verbiage somewhere in the description: + ``` The base branch is `master`. This PR branch will be pushed directly to `release` and `master` (not squashed or rebased, and not using the GitHub UI). ``` + 7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur offline, but at least one approval will be needed on the PR. - * If issues are discovered during testing, close the PR, delete + - If issues are discovered during testing, close the PR, delete `master-next`, and move development back to `release`, [issuing more RCs as necessary](#release-candidates-after-the-first) 8. Once everything is ready to go, push to `release` and `master`. + ``` git fetch upstreams @@ -821,15 +850,20 @@ git log -1 --oneline # Other branches, including some from upstream-push, may also be # present. ``` + 9. Tag the release, too. + ``` git tag git push upstream-push ``` + 10. Delete the `master-next` branch on the repo. Use the Github UI or: + ``` git push --delete upstream-push master-next ``` + 11. [Create a new release on Github](https://github.com/XRPLF/rippled/releases). Be sure that "Set as the latest release" is checked. @@ -856,11 +890,13 @@ any branch. When it's ready to merge, jump to step 3 using your branch instead of `master-next`. 1. Create a `master-next` branch from `master`. + ``` git checkout --no-track -b master-next upstream/master git push upstream-push git fetch upstreams ``` + 2. Open any PRs for the pending hotfix using `master-next` as the base, so they can be merged directly in to it. Unlike `develop`, though, `master-next` can be thrown away and recreated if necessary. @@ -868,19 +904,22 @@ git fetch upstreams steps as above, or use the [update-version] script. 4. Create a Pull Request for `master-next` with **`master`** as - the base branch. Instead of the default template, reuse and update + the base branch. Instead of the default template, reuse and update the message from the previous final release. Include the following verbiage somewhere in the description: + ``` The base branch is `master`. This PR branch will be pushed directly to `master` (not squashed or rebased, and not using the GitHub UI). ``` + 7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur offline, but at least one approval will be needed on the PR. - * If issues are discovered during testing, update `master-next` as + - If issues are discovered during testing, update `master-next` as needed, but ensure that the changes are properly squashed, and the version setting commit remains last 8. Once everything is ready to go, push to `master` **only**. + ``` git fetch upstreams @@ -901,15 +940,20 @@ git log -1 --oneline # Other branches, including some from upstream-push, may also be # present. ``` + 9. Tag the release, too. + ``` git tag git push upstream-push ``` + 9. Delete the `master-next` branch on the repo. + ``` git push --delete upstream-push master-next ``` + 10. [Create a new release on Github](https://github.com/XRPLF/rippled/releases). Be sure that "Set as the latest release" is checked. @@ -921,17 +965,21 @@ Once the hotfix is released, it needs to be reverse merged into 1. Create a branch in your own repo, based on `upstream/develop`. The branch name is not important, but could include "mergeNNN". E.g. For release 2.2.3, use `merge223`. + ``` git fetch upstreams git checkout --no-track -b merge223 upstream/develop ``` + 2. Merge master into your branch. + ``` # I like the "--edit --log --verbose" parameters, but they are # not required. git merge upstream/master ``` + 3. `BuildInfo.cpp` will have a conflict with the version number. Resolve it with the version from `develop` - the higher version. 4. Push your branch to your repo, and open a normal PR against @@ -939,22 +987,27 @@ git merge upstream/master is a merge of the hotfix version. The "Context" should summarize the changes from the hotfix. Include the following text prominently: + ``` This PR must be merged manually using a --ff-only merge. Do not use the Github UI. ``` + 5. Depending on the complexity of the hotfix, and/or merge conflicts, the PR may need a thorough review, or just a sign-off that the merge was done correctly. 6. If `develop` is updated before this PR is merged, do not merge `develop` back into your branch. Instead rebase preserving merges, or do the merge again. (See also the `rerere` git config setting.) + ``` git rebase --rebase-merges upstream/develop # OR git reset --hard upstream/develop git merge upstream/master ``` + 7. When the PR is ready, push it to `develop`. + ``` git fetch upstreams @@ -963,6 +1016,7 @@ git log --show-signature "upstream/develop..HEAD" git push upstream-push HEAD:develop ``` + Development on `develop` can proceed as normal. It is recommended to create a beta (or RC) immediately to ensure that everything worked as expected. @@ -977,12 +1031,13 @@ a significant fraction of users, which would necessitate a hotfix / point release to that version as well as any later versions. This scenario would follow the same basic procedure as above, -except that *none* of `develop`, `release`, or `master` +except that _none_ of `develop`, `release`, or `master` would be touched during the release process. In this example, consider if version 2.1.1 needed to be patched. 1. Create two branches in the main (`upstream`) repo. + ``` git fetch upstreams @@ -996,6 +1051,7 @@ git push upstream-push git fetch upstreams ``` + 2. Work continues as above, except using `master-2.1.2`as the base branch for any merging, packaging, etc. 3. After the release is tagged and packages are built, you could diff --git a/LICENSE.md b/LICENSE.md index 9282ed78baf..8aca84866fd 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -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) 2012-2020, the XRP Ledger developers. @@ -14,4 +14,3 @@ 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. - diff --git a/README.md b/README.md index 0315c37428e..4fdb89dffae 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,19 @@ The [XRP Ledger](https://xrpl.org/) is a decentralized cryptographic ledger powered by a network of peer-to-peer nodes. The XRP Ledger uses a novel Byzantine Fault Tolerant consensus algorithm to settle and record transactions in a secure distributed database without a central operator. ## XRP + [XRP](https://xrpl.org/xrp.html) is a public, counterparty-free asset native to the XRP Ledger, and is designed to bridge the many different currencies in use worldwide. XRP is traded on the open-market and is available for anyone to access. The XRP Ledger was created in 2012 with a finite supply of 100 billion units of XRP. ## rippled + The server software that powers the XRP Ledger is called `rippled` and is available in this repository under the permissive [ISC open-source license](LICENSE.md). The `rippled` server software is written primarily in C++ and runs on a variety of platforms. The `rippled` server software can run in several modes depending on its [configuration](https://xrpl.org/rippled-server-modes.html). If you are interested in running an **API Server** (including a **Full History Server**), take a look at [Clio](https://github.com/XRPLF/clio). (rippled Reporting Mode has been replaced by Clio.) ### Build from Source -* [Read the build instructions in `BUILD.md`](BUILD.md) -* If you encounter any issues, please [open an issue](https://github.com/XRPLF/rippled/issues) +- [Read the build instructions in `BUILD.md`](BUILD.md) +- If you encounter any issues, please [open an issue](https://github.com/XRPLF/rippled/issues) ## Key Features of the XRP Ledger @@ -35,7 +37,6 @@ If you are interested in running an **API Server** (including a **Full History S [Modern Features for Smart Contracts]: https://xrpl.org/xrp-ledger-overview.html#modern-features-for-smart-contracts [On-Ledger Decentralized Exchange]: https://xrpl.org/xrp-ledger-overview.html#on-ledger-decentralized-exchange - ## Source Code Here are some good places to start learning the source code: @@ -47,7 +48,7 @@ Here are some good places to start learning the source code: ### Repository Contents | Folder | Contents | -|:-----------|:-------------------------------------------------| +| :--------- | :----------------------------------------------- | | `./bin` | Scripts and data files for Ripple integrators. | | `./Builds` | Platform-specific guides for building `rippled`. | | `./docs` | Source documentation files and doxygen config. | @@ -57,15 +58,14 @@ Here are some good places to start learning the source code: Some of the directories under `src` are external repositories included using git-subtree. See those directories' README files for more details. - ## Additional Documentation -* [XRP Ledger Dev Portal](https://xrpl.org/) -* [Setup and Installation](https://xrpl.org/install-rippled.html) -* [Source Documentation (Doxygen)](https://xrplf.github.io/rippled/) +- [XRP Ledger Dev Portal](https://xrpl.org/) +- [Setup and Installation](https://xrpl.org/install-rippled.html) +- [Source Documentation (Doxygen)](https://xrplf.github.io/rippled/) ## See Also -* [Clio API Server for the XRP Ledger](https://github.com/XRPLF/clio) -* [Mailing List for Release Announcements](https://groups.google.com/g/ripple-server) -* [Learn more about the XRP Ledger (YouTube)](https://www.youtube.com/playlist?list=PLJQ55Tj1hIVZtJ_JdTvSum2qMTsedWkNi) +- [Clio API Server for the XRP Ledger](https://github.com/XRPLF/clio) +- [Mailing List for Release Announcements](https://groups.google.com/g/ripple-server) +- [Learn more about the XRP Ledger (YouTube)](https://www.youtube.com/playlist?list=PLJQ55Tj1hIVZtJ_JdTvSum2qMTsedWkNi) diff --git a/RELEASENOTES.md b/RELEASENOTES.md deleted file mode 100644 index 6bc7beccc7b..00000000000 --- a/RELEASENOTES.md +++ /dev/null @@ -1,4817 +0,0 @@ -# Release Notes - -![XRP](docs/images/xrp-text-mark-black-small@2x.png) - -This document contains the release notes for `rippled`, the reference server implementation of the XRP Ledger protocol. To learn more about how to build, run or update a `rippled` server, visit https://xrpl.org/install-rippled.html - -Have new ideas? Need help with setting up your node? [Please open an issue here](https://github.com/xrplf/rippled/issues/new/choose). -## Full Changelog - -### Amendments - -The following amendments are open for voting with this release: - -- **DynamicNFT (XLS-46)** - Adds the ability to mint mutable `NFToken` objects whose URI can be changed. ([#5048](https://github.com/XRPLF/rippled/pull/5048)) -- **PermissionedDomains (XLS-80)** - Adds Permissioned Domains, which act as part of broader systems on the XRP Ledger to restrict access to satisfy compliance rules. ([#5161](https://github.com/XRPLF/rippled/pull/5161)) -- **DeepFreeze (XLS-77)** - Adds the ability to deep freeze trust lines, enabling token issuers to block the transfer of assets for holders who have been deep frozen. ([#5187](https://github.com/XRPLF/rippled/pull/5187)) -- **fixFrozenLPTokenTransfer** - Prohibits the transfer of LP tokens when the associated liquidity pool contains at least one frozen asset. ([#5227](https://github.com/XRPLF/rippled/pull/5227)) -- **fixInvalidTxFlags** - Adds transaction flag checking for `CredentialCreate`, `CredentialAccept`, and `CredentialDelete` transactions. ([#5250](https://github.com/XRPLF/rippled/pull/5250)) - - -### New Features - -- Added a new `simulate` API method to execute dry runs of transactions and see the simulated metadata. ([#5069](https://github.com/XRPLF/rippled/pull/5069), [#5265](https://github.com/XRPLF/rippled/pull/5265)) -- Added the ability to specify MPTs when defining assets in transactions. ([#5200](https://github.com/XRPLF/rippled/pull/5200)) -- Added a `state` alias for `ripple_state` in the `ledger_entry` API method. Also refactored `LedgerEntry.cpp` to make it easier to read. ([#5199](https://github.com/XRPLF/rippled/pull/5199)) -- Improved UNL security by enabling validators to set a minimum number of UNL publishers to agree on validators. ([#5112](https://github.com/XRPLF/rippled/pull/5112)) -- Updated the XRPL Foundation UNL keys. ([#5289](https://github.com/XRPLF/rippled/pull/5289)) -- Added a new XRPL Foundation subdomain to enable a staged migration without modifying the key for the current UNL list. ([#5326](https://github.com/XRPLF/rippled/pull/5326)) -- Added support to filter ledger entry types by their canonical names in the `ledger`, `ledger_data`, and `account_objects` API methods. ([#5271](https://github.com/XRPLF/rippled/pull/5271)) -- Added detailed logging for each validation and proposal received from the network. ([#5291](https://github.com/XRPLF/rippled/pull/5291)) -- Improved git commit hash lookups when checking the version of a `rippled` debug build. Also added git commit hash info when using the `server_info` API method on an admin connection. ([#5225](https://github.com/XRPLF/rippled/pull/5225)) - - -### Bug fixes - -- Fixed an issue with overlapping data types in the `Expected` class. ([#5218](https://github.com/XRPLF/rippled/pull/5218)) -- Fixed an issue that prevented `rippled` from building on Windows with VS2022. ([#5197](https://github.com/XRPLF/rippled/pull/5197)) -- Fixed `server_definitions` prefixes. ([#5231](https://github.com/XRPLF/rippled/pull/5231)) -- Added missing dependency installations for generic MasOS runners. ([#5233](https://github.com/XRPLF/rippled/pull/5233)) -- Updated deprecated Github actions. ([#5241](https://github.com/XRPLF/rippled/pull/5241)) -- Fixed a failing assert scenario when submitting the `connect` admin RPC. ([#5235](https://github.com/XRPLF/rippled/pull/5235)) -- Fixed the levelization script to ignore single-line comments during dependency analysis. ([#5194](https://github.com/XRPLF/rippled/pull/5194)) -- Fixed the assert name used in `PermissionedDomainDelete`. ([#5245](https://github.com/XRPLF/rippled/pull/5245)) -- Fixed macOS unit tests. ([#5196](https://github.com/XRPLF/rippled/pull/5196)) -- Fixed an issue with validators not accurately reflecting amendment votes. Also added debug logging of amendment votes. ([#5173](https://github.com/XRPLF/rippled/pull/5173), [#5312](https://github.com/XRPLF/rippled/pull/5312)) -- Fixed a potential issue with double-charging fees. ([#5269](https://github.com/XRPLF/rippled/pull/5269)) -- Removed the `new parent hash` assert and replaced it with a log message. ([#5313](https://github.com/XRPLF/rippled/pull/5313)) -- Fixed an issue that prevented previously-failed inbound ledgers to not be acquired if a new trusted proposal arrived. ([#5318](https://github.com/XRPLF/rippled/pull/5318)) - - -### Other Improvements - -- Added unit tests for `AccountID` handling. ([#5174](https://github.com/XRPLF/rippled/pull/5174)) -- Added enforced levelization in `libxrpl` with CMake. ([#5199](https://github.com/XRPLF/rippled/pull/5111)) -- Updated `libxrpl` and all submodules to use the same compiler options. ([#5228](https://github.com/XRPLF/rippled/pull/5228)) -- Added Antithesis instrumentation. ([#5042](https://github.com/XRPLF/rippled/pull/5042), [#5213](https://github.com/XRPLF/rippled/pull/5213)) -- Added `rpcName` to the `LEDGER_ENTRY` macro to help prevent future bugs. ([#5202](https://github.com/XRPLF/rippled/pull/5202)) -- Updated the contribution guidelines to introduce a new workflow that avoids code freezes. Also added scripts that can be used by maintainers in branch management, and a CI job to check that code is consistent across the three main branches: `master`, `release`, and `develop`. ([#5215](https://github.com/XRPLF/rippled/pull/5215)) -- Added unit tests to check for caching issues fixed in `rippled 2.3.0`. ([#5242](https://github.com/XRPLF/rippled/pull/5242)) -- Cleaned up the API changelog. ([#5207](https://github.com/XRPLF/rippled/pull/5207)) -- Improved logs readability. ([#5251](https://github.com/XRPLF/rippled/pull/5251)) -- Updated Visual Studio CI to VS 2022, and added VS Debug builds. ([#5240](https://github.com/XRPLF/rippled/pull/5240)) -- Updated the `secp256k1` library to version 0.6.0. ([#5254](https://github.com/XRPLF/rippled/pull/5254)) -- Changed the `[port_peer]` parameter in `rippled` example config back to `51235`; also added the recommendation to use the default port of `2459` for new deployments. ([#5290](https://github.com/XRPLF/rippled/pull/5290), [#5299](https://github.com/XRPLF/rippled/pull/5299)) -- Improved CI management. ([#5268](https://github.com/XRPLF/rippled/pull/5268)) -- Updated the git commit message rules for contributors. ([#5283](https://github.com/XRPLF/rippled/pull/5283)) -- Fixed unnecessary `setCurrentThreadName` calls. ([#5280](https://github.com/XRPLF/rippled/pull/5280)) -- Added a check to prevent permissioned domains from being created in the event the Permissioned Domains amendement is enabled before the Credentials amendement. ([#5275](https://github.com/XRPLF/rippled/pull/5275)) -- Updated Conan dependencies. ([#5256](https://github.com/XRPLF/rippled/pull/5256)) -- Fixed minor typos in code comments. ([#5279](https://github.com/XRPLF/rippled/pull/5279)) -- Fixed incorrect build instructions. ([#5274](https://github.com/XRPLF/rippled/pull/5274)) -- Refactored `rotateWithLock()` to not hold a lock during callbacks. ([#5276](https://github.com/XRPLF/rippled/pull/5276)) -- Cleaned up debug logging by combining multiple data points into a single message. ([#5302](https://github.com/XRPLF/rippled/pull/5302)) -- Updated build flags to fix performance regressions. ([#5325](https://github.com/XRPLF/rippled/pull/5325)) - - -## Credits - -The following people contributed directly to this release: - -- Aanchal Malhotra -- Bart Thomee <11445373+bthomee@users.noreply.github.com> -- Bronek Kozicki -- code0xff -- Darius Tumas -- David Fuelling -- Donovan Hide -- Ed Hennis -- Elliot Lee -- Javier Romero -- Kenny Lei -- Mark Travis <7728157+mtrippled@users.noreply.github.com> -- Mayukha Vadari -- Michael Legleux -- Oleksandr <115580134+oleks-rip@users.noreply.github.com> -- Qi Zhao -- Ramkumar Srirengaram Gunasegharan -- Shae Wang -- Shawn Xie -- Sophia Xie -- Vijay Khanna Raviraj -- Vladislav Vysokikh -- Xun Zhao - -## Bug Bounties and Responsible Disclosures - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - -# Version 2.3.1 - -Version 2.3.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. -This is a hotfix release that includes the following updates: -- Fix an erroneous high fee penalty that peers could incur for sending older transactions. -- Update to the fees charged for imposing a load on the server. -- Prevent the relaying of internal pseudo-transactions. - - Before: Pseudo-transactions received from a peer will fail the signature check, even if they were requested (using TMGetObjectByHash) because they have no signature. This causes the peer to be charged for an invalid signature. - - After: Pseudo-transactions, are put into the global cache (TransactionMaster) only. If the transaction is not part of a TMTransactions batch, the peer is charged an unwanted data fee. These fees will not be a problem in the normal course of operations but should dissuade peers from behaving badly by sending a bunch of junk. -- Improved logging now specifies the reason for the fee charged to the peer. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Action Required - -If you run an XRP Ledger validator, upgrade to version 2.3.1 as soon as possible to ensure stable and uninterrupted network behavior. - -## Changelog - -### Amendments and New Features - -- None - -### Bug Fixes and Performance Improvements - -- Change the charged fee for sending older transactions from feeInvalidSignature to feeUnwantedData. [#5243](https://github.com/XRPLF/rippled/pull/5243) - -### Docs and Build System - -- None - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -Ed Hennis -JoelKatz -Sophia Xie <106177003+sophiax851@users.noreply.github.com> -Valentin Balaschenko <13349202+vlntb@users.noreply.github.com> - - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - -# Version 2.3.0 - -Version 2.3.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes 8 new amendments, including Multi-Purpose Tokens, Credentials, Clawback support for AMMs, and the ability to make offers as part of minting NFTs. Additionally, this release includes important fixes for stability, so server operators are encouraged to upgrade as soon as possible. - - -## Action Required - -If you run an XRP Ledger server, upgrade to version 2.3.0 as soon as possible to ensure service continuity. - -Additionally, new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - -## Full Changelog - -### Amendments - -The following amendments are open for voting with this release: - -- **XLS-70 Credentials** - Users can issue Credentials on the ledger and use Credentials to pre-approve incoming payments when using Deposit Authorization instead of individually approving payers. ([#5103](https://github.com/XRPLF/rippled/pull/5103)) - - related fix: #5189 (https://github.com/XRPLF/rippled/pull/5189) -- **XLS-33 Multi-Purpose Tokens** - A new type of fungible token optimized for institutional DeFi including stablecoins. ([#5143](https://github.com/XRPLF/rippled/pull/5143)) -- **XLS-37 AMM Clawback** - Allows clawback-enabled tokens to be used in AMMs, with appropriate guardrails. ([#5142](https://github.com/XRPLF/rippled/pull/5142)) -- **XLS-52 NFTokenMintOffer** - Allows creating an NFT sell offer as part of minting a new NFT. ([#4845](https://github.com/XRPLF/rippled/pull/4845)) -- **fixAMMv1_2** - Fixes two bugs in Automated Market Maker (AMM) transaction processing. ([#5176](https://github.com/XRPLF/rippled/pull/5176)) -- **fixNFTokenPageLinks** - Fixes a bug that can cause NFT directories to have missing links, and introduces a transaction to repair corrupted ledger state. ([#4945](https://github.com/XRPLF/rippled/pull/4945)) -- **fixEnforceNFTokenTrustline** - Fixes two bugs in the interaction between NFT offers and trust lines. ([#4946](https://github.com/XRPLF/rippled/pull/4946)) -- **fixInnerObjTemplate2** - Standardizes the way inner objects are enforced across all transaction and ledger data. ([#5047](https://github.com/XRPLF/rippled/pull/5047)) - -The following amendment is partially implemented but not open for voting: - -- **InvariantsV1_1** - Adds new invariants to ensure transactions process as intended, starting with an invariant to ensure that ledger entries owned by an account are deleted when the account is deleted. ([#4663](https://github.com/XRPLF/rippled/pull/4663)) - -### New Features - -- Allow configuration of SQLite database page size. ([#5135](https://github.com/XRPLF/rippled/pull/5135), [#5140](https://github.com/XRPLF/rippled/pull/5140)) -- In the `libxrpl` C++ library, provide a list of known amendments. ([#5026](https://github.com/XRPLF/rippled/pull/5026)) - -### Deprecations - -- History Shards are removed. ([#5066](https://github.com/XRPLF/rippled/pull/5066)) -- Reporting mode is removed. ([#5092](https://github.com/XRPLF/rippled/pull/5092)) - -For users wanting to store more ledger history, it is recommended to run a Clio server instead. - -### Bug fixes - -- Fix a crash in debug builds when amm_info request contains an invalid AMM account ID. ([#5188](https://github.com/XRPLF/rippled/pull/5188)) -- Fix a crash caused by a race condition in peer-to-peer code. ([#5071](https://github.com/XRPLF/rippled/pull/5071)) -- Fix a crash in certain situations -- Fix several bugs in the book_changes API method. ([#5096](https://github.com/XRPLF/rippled/pull/5096)) -- Fix bug triggered by providing an invalid marker to the account_nfts API method. ([#5045](https://github.com/XRPLF/rippled/pull/5045)) -- Accept lower-case hexadecimal in compact transaction identifier (CTID) parameters in API methods. ([#5049](https://github.com/XRPLF/rippled/pull/5049)) -- Disallow filtering by types that an account can't own in the account_objects API method. ([#5056](https://github.com/XRPLF/rippled/pull/5056)) -- Fix error code returned by the feature API method when providing an invalid parameter. ([#5063](https://github.com/XRPLF/rippled/pull/5063)) -- (API v3) Fix error code returned by amm_info when providing invalid parameters. ([#4924](https://github.com/XRPLF/rippled/pull/4924)) - -### Other Improvements - -- Adds a new default hub, hubs.xrpkuwait.com, to the config file and bootstrapping code. ([#5169](https://github.com/XRPLF/rippled/pull/5169)) -- Improve error message when commandline interface fails with `rpcInternal` because there was no response from the server. ([#4959](https://github.com/XRPLF/rippled/pull/4959)) -- Add tools for debugging specific transactions via replay. ([#5027](https://github.com/XRPLF/rippled/pull/5027), [#5087](https://github.com/XRPLF/rippled/pull/5087)) -- Major reorganization of source code files. ([#4997](https://github.com/XRPLF/rippled/pull/4997)) -- Add new unit tests. ([#4886](https://github.com/XRPLF/rippled/pull/4886)) -- Various improvements to build tools and contributor documentation. ([#5001](https://github.com/XRPLF/rippled/pull/5001), [#5028](https://github.com/XRPLF/rippled/pull/5028), [#5052](https://github.com/XRPLF/rippled/pull/5052), [#5091](https://github.com/XRPLF/rippled/pull/5091), [#5084](https://github.com/XRPLF/rippled/pull/5084), [#5120](https://github.com/XRPLF/rippled/pull/5120), [#5010](https://github.com/XRPLF/rippled/pull/5010). [#5055](https://github.com/XRPLF/rippled/pull/5055), [#5067](https://github.com/XRPLF/rippled/pull/5067), [#5061](https://github.com/XRPLF/rippled/pull/5061), [#5072](https://github.com/XRPLF/rippled/pull/5072), [#5044](https://github.com/XRPLF/rippled/pull/5044) ) -- Various code cleanup and refactoring. ([#4509](https://github.com/XRPLF/rippled/pull/4509), [#4521](https://github.com/XRPLF/rippled/pull/4521), [#4856](https://github.com/XRPLF/rippled/pull/4856), [#5190](https://github.com/XRPLF/rippled/pull/5190), [#5081](https://github.com/XRPLF/rippled/pull/5081), [#5053](https://github.com/XRPLF/rippled/pull/5053), [#5058](https://github.com/XRPLF/rippled/pull/5058), [#5122](https://github.com/XRPLF/rippled/pull/5122), [#5059](https://github.com/XRPLF/rippled/pull/5059), [#5041](https://github.com/XRPLF/rippled/pull/5041)) - - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - -# Version 2.2.3 - -Version 2.2.3 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes a problem that can cause full-history servers to run out of space in their SQLite databases, depending on configuration. There are no new amendments in this release. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Background - -The `rippled` server uses a SQLite database for tracking transactions, in addition to the main data store (usually NuDB) for ledger data. In servers keeping a large amount of history, this database can run out of space based on the configured number and size of database pages, even if the machine has disk space available. Based on the size of full history on Mainnet, servers with the default SQLite page size of 4096 may now run out of space if they store full history. In this case, your server may shut down with an error such as the following: - -```text -Free SQLite space for transaction db is less than 512MB. To fix this, rippled - must be executed with the vacuum parameter before restarting. - Note that this activity can take multiple days, depending on database size. -``` - -The exact timing of when a server runs out of space can vary based on a few factors. Server operators who encountered a similar problem in 2018 and followed steps to [increase the SQLite transaction database page size issue](../../../docs/infrastructure/troubleshooting/fix-sqlite-tx-db-page-size-issue) may not encounter this problem at all. The `--vacuum` commandline option to `rippled` from that time may work to free up space in the database, but requires extended downtime. - -Version 2.2.3 of `rippled` reconfigures the maximum number of SQLite pages so that the issue does not occur. - -Clio servers providing full history are not affected by this issue. - - -## Action Required - -If you run an [XRP Ledger full history server](https://xrpl.org/docs/infrastructure/configuration/data-retention/configure-full-history), upgrading to version 2.2.3 may prevent the server from crashing when `transaction.db` exceeds approximately 8.7 terabytes. - -Additionally, five amendments introduced in version 2.2.0 are open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. If you operate an XRP Ledger server older than version 2.2.0, upgrade by Sep 23, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - -## Changelog - -### Bug Fixes - -- Update SQLite3 max_page_count to match current defaults ([#5114](https://github.com/XRPLF/rippled/pull/5114)) - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -J. Scott Branson - - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - -# Version 2.2.2 - -Version 2.2.2 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes an ongoing issue with Mainnet where validators can stall during consensus processing due to lock contention, preventing ledgers from being validated for up to two minutes. There are no new amendments in this release. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Action Required - -If you run an XRP Ledger validator, upgrade to version 2.2.2 as soon as possible to ensure stable and uninterrupted network behavior. - -Additionally, five amendments introduced in version 2.2.0 are open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. If you operate an XRP Ledger server older than version 2.2.0, upgrade by September 17, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. Version 2.2.2 is recommended because of known bugs affecting stability of versions 2.2.0 and 2.2.1. - -If you operate a Clio server, Clio needs to be updated to 2.1.2 before updating to rippled 2.2.0. Clio will be blocked if it is not updated. - -## Changelog - -### Amendments and New Features - -- None - -### Bug Fixes and Performance Improvements - -- Allow only 1 job queue slot for acquiring inbound ledger [#5115](https://github.com/XRPLF/rippled/pull/5115) ([7741483](https://github.com/XRPLF/rippled/commit/774148389467781aca7c01bac90af2fba870570c)) - -- Allow only 1 job queue slot for each validation ledger check [#5115](https://github.com/XRPLF/rippled/pull/5115) ([fbbea9e](https://github.com/XRPLF/rippled/commit/fbbea9e6e25795a8a6bd1bf64b780771933a9579)) - -### Other improvements - - - Track latencies of certain code blocks, and log if they take too long [#5115](https://github.com/XRPLF/rippled/pull/5115) ([00ed7c9](https://github.com/XRPLF/rippled/commit/00ed7c942436f02644a13169002b5123f4e2a116)) - -### Docs and Build System - -- None - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -Mark Travis -Valentin Balaschenko <13349202+vlntb@users.noreply.github.com> - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - -# Version 2.2.1 - -Version 2.2.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes a critical bug introduced in 2.2.0 handling some types of RPC requests. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Action Required - -If you run an XRP Ledger validator, upgrade to version 2.2.1 as soon as possible to ensure stable and uninterrupted network behavior. - -Additionally, five amendments introduced in version 2.2.0 are open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. If you operate an XRP Ledger server older than version 2.2.0, upgrade by August 14, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. Version 2.2.1 is recommended because of known bugs affecting stability of versions 2.2.0. - -If you operate a Clio server, Clio needs to be updated to 2.2.2 before updating to rippled 2.2.1. Clio will be blocked if it is not updated. - -## Changelog - -### Amendments and New Features - -- None - -### Bug Fixes and Performance Improvements - -- Improve error handling in some RPC commands. [#5078](https://github.com/XRPLF/rippled/pull/5078) - -- Use error codes throughout fast Base58 implementation. [#5078](https://github.com/XRPLF/rippled/pull/5078) - -### Docs and Build System - -- None - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -John Freeman -Mayukha Vadari - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - -# Version 2.2.0 - -Version 2.2.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds performance optimizations, several bug fixes, and introduces the `featurePriceOracle`, `fixEmptyDID`, `fixXChainRewardRounding`, `fixPreviousTxnID`, and `fixAMMv1_1` amendments. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Action Required - -Five new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, upgrade to version 2.2.0 by June 17, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - -If you operate a Clio server, Clio needs to be updated to 2.1.2 before updating to rippled 2.2.0. Clio will be blocked if it is not updated. - -## Changelog - -### Amendments and New Features -(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) - -- **featurePriceOracle** amendment: Implements a price oracle as defined in the [XLS-47](https://github.com/XRPLF/XRPL-Standards/blob/master/XLS-47d-PriceOracles/README.md) spec. A Price Oracle is used to bring real-world data, such as market prices, onto the blockchain, enabling dApps to access and utilize information that resides outside the blockchain. [#4789](https://github.com/XRPLF/rippled/pull/4789) - -- **fixEmptyDID** amendment: Modifies the behavior of the DID amendment: adds an additional check to ensure that DIDs are non-empty when created, and returns a `tecEMPTY_DID` error if the DID would be empty. [#4950](https://github.com/XRPLF/rippled/pull/4950) - -- **fixXChainRewardRounding** amendment: Modifies the behavior of the XChainBridge amendment: fixes rounding so reward shares are always rounded down, even when the `fixUniversalNumber` amendment is active. [#4933](https://github.com/XRPLF/rippled/pull/4933) - -- **fixPreviousTxnID** amendment: Adds `PreviousTxnID` and `PreviousTxnLgrSequence` as fields to all ledger entries that did not already have them included (`DirectoryNode`, `Amendments`, `FeeSettings`, `NegativeUNL`, and `AMM`). Existing ledger entries will gain the fields whenever transactions modify those entries. [#4751](https://github.com/XRPLF/rippled/pull/4751). - -- **fixAMMv1_1** amendment: Fixes AMM offer rounding and low quality order book offers from blocking the AMM. [#4983](https://github.com/XRPLF/rippled/pull/4983) - -- Add a non-admin version of `feature` API method. [#4781](https://github.com/XRPLF/rippled/pull/4781) - -### Bug Fixes and Performance Improvements -(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) - -- Optimize the base58 encoder and decoder. The algorithm is now about 10 times faster for encoding and 15 times faster for decoding. [#4327](https://github.com/XRPLF/rippled/pull/4327) - -- Optimize the `account_tx` SQL query. [#4955](https://github.com/XRPLF/rippled/pull/4955) - -- Don't reach consensus as quickly if no other proposals are seen. [#4763](https://github.com/XRPLF/rippled/pull/4763) - -- Fix a potential deadlock in the database module. [#4989](https://github.com/XRPLF/rippled/pull/4989) - -- Enforce no duplicate slots from incoming connections. [#4944](https://github.com/XRPLF/rippled/pull/4944) - -- Fix an order book update variable swap. [#4890](https://github.com/XRPLF/rippled/pull/4890) - -### Docs and Build System - -- Add unit test to raise the test coverage of the AMM. [#4971](https://github.com/XRPLF/rippled/pull/4971) - -- Improve test coverage reporting. [#4977](https://github.com/XRPLF/rippled/pull/4977) - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -Alex Kremer -Alloy Networks <45832257+alloynetworks@users.noreply.github.com> -Bronek Kozicki -Chenna Keshava -Denis Angell -Ed Hennis -Gregory Tsipenyuk -Howard Hinnant -John Freeman -Mark Travis -Mayukha Vadari -Michael Legleux -Nik Bougalis -Olek <115580134+oleks-rip@users.noreply.github.com> -Scott Determan -Snoppy - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - -## Version 2.1.1 - -The `rippled` 2.1.1 release fixes a critical bug in the integration of AMMs with the payment engine. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - - -## Action Required - -One new amendment is now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, upgrade to version 2.1.1 by April 8, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - -## Changelog - -### Amendments - -- **fixAMMOverflowOffer**: Fix improper handling of large synthetic AMM offers in the payment engine. Due to the importance of this fix, the default vote in the source code has been set to YES. For information on how to configure your validator's amendment voting, see [Configure Amendment Voting](https://xrpl.org/docs/infrastructure/configuration/configure-amendment-voting). - -# Introducing XRP Ledger version 2.1.0 - -Version 2.1.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds a bug fix, build improvements, and introduces the `fixNFTokenReserve` and `fixInnerObjTemplate` amendments. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - - -## Action Required - -Two new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, upgrade to version 2.1.0 by March 5, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - -## Changelog - -### Amendments -(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) - -- **fixNFTokenReserve**: Adds a check to the `NFTokenAcceptOffer` transactor to see if the `OwnerCount` changed. If it did, it checks that the reserve requirement is met. [#4767](https://github.com/XRPLF/rippled/pull/4767) - -- **fixInnerObjTemplate**: Adds an `STObject` constructor overload that includes an additional boolean argument to set the inner object template; currently, the inner object template isn't set upon object creation. In some circumstances, this causes a `tefEXCEPTION` error when trying to access the AMM `sfTradingFee` and `sfDiscountedFee` fields in the inner objects of `sfVoteEntry` and `sfAuctionSlot`. [#4906](https://github.com/XRPLF/rippled/pull/4906) - - -### Bug Fixes and Performance Improvements -(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) - -- Fixed a bug that prevented the gRPC port info from being specified in the `rippled` config file. [#4728](https://github.com/XRPLF/rippled/pull/4728) - - -### Docs and Build System - -- Added unit tests to check that payees and payers aren't the same account. [#4860](https://github.com/XRPLF/rippled/pull/4860) - -- Removed a workaround that bypassed Windows CI unit test failures. [#4871](https://github.com/XRPLF/rippled/pull/4871) - -- Updated library names to be platform-agnostic in Conan recipes. [#4831](https://github.com/XRPLF/rippled/pull/4831) - -- Added headers required in the Conan package to build xbridge witness servers. [#4885](https://github.com/XRPLF/rippled/pull/4885) - -- Improved object lifetime management when creating a temporary `Rules` object, fixing a crash in Windows unit tests. [#4917](https://github.com/XRPLF/rippled/pull/4917) - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -- Bronek Kozicki -- CJ Cobb -- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> -- Ed Hennis -- Elliot Lee -- Gregory Tsipenyuk -- John Freeman -- Michael Legleux -- Ryan Molley -- Shawn Xie <35279399+shawnxie999@users.noreply.github.com> - - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - -# Introducing XRP Ledger version 2.0.1 - -Version 2.0.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes minor fixes, unit test improvements, and doc updates. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - - -## Action Required - -If you operate an XRP Ledger server, upgrade to version 2.0.1 to take advantage of the changes included in this update. Nodes on version 1.12 should upgrade as soon as possible. - - -## Changelog - - -### Changes -(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) - -- Updated the `send_queue_limit` to 500 in the default `rippled` config to handle increased transaction loads. [#4867](https://github.com/XRPLF/rippled/pull/4867) - - -### Bug Fixes and Performance Improvements -(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) - -- Fixed an assertion that occurred when `rippled` was under heavy websocket client load. [#4848](https://github.com/XRPLF/rippled/pull/4848) - -- Improved lifetime management of serialized type ledger entries to improve memory usage. [#4822](https://github.com/XRPLF/rippled/pull/4822) - -- Fixed a clang warning about deprecated sprintf usage. [#4747](https://github.com/XRPLF/rippled/pull/4747) - - -### Docs and Build System - -- Added `DeliverMax` to more JSONRPC tests. [#4826](https://github.com/XRPLF/rippled/pull/4826) - -- Updated the pull request template to include a `Type of Change` checkbox and additional contextual questions. [#4875](https://github.com/XRPLF/rippled/pull/4875) - -- Updated help messages for unit tests pattern matching. [#4846](https://github.com/XRPLF/rippled/pull/4846) - -- Improved the time it take to generate coverage reports. [#4849](https://github.com/XRPLF/rippled/pull/4849) - -- Fixed broken links in the Conan build docs. [#4699](https://github.com/XRPLF/rippled/pull/4699) - -- Spurious codecov uploads are now retried if there's an error uploading them the first time. [#4896](https://github.com/XRPLF/rippled/pull/4896) - - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -- Bronek Kozicki -- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> -- Ed Hennis -- Elliot Lee -- Lathan Britz -- Mark Travis -- nixer89 - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - -# Introducing XRP Ledger version 2.0.0 - -Version 2.0.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds new features and bug fixes, and introduces these amendments: - -- `DID` -- `XChainBridge` -- `fixDisallowIncomingV1` -- `fixFillOrKill` - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - - -## Action Required - -Four new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, upgrade to version 2.0.0 by January 22, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - - -## Changelog - - -### Amendments, New Features, and Changes -(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) - -- **XChainBridge**: Introduces cross-chain bridges, enabling interoperability between the XRP Ledger and sidechains. [#4292](https://github.com/XRPLF/rippled/pull/4292) - -- **DID**: Introduces decentralized identifiers. [#4636](https://github.com/XRPLF/rippled/pull/4636) - -- **fixDisallowIncomingV1**: Fixes an issue that occurs when users try to authorize a trustline while the `lsfDisallowIncomingTrustline` flag is enabled on their account. [#4721](https://github.com/XRPLF/rippled/pull/4721) - -- **fixFillOrKill**: Fixes an issue introduced in the `flowCross` amendment. The `tfFillOrKill` and `tfSell` flags are now properly handled to allow offers to cross in certain scenarios. [#4694](https://github.com/XRPLF/rippled/pull/4694) - -- **API v2 released with these changes:** - - - Accepts currency codes in ASCII, using the full alphabet. [#4566](https://github.com/XRPLF/rippled/pull/4566) - - Added test to verify the `check` field is a string. [#4630](https://github.com/XRPLF/rippled/pull/4630) - - Added errors for malformed `account_tx` and `noripple_check` fields. [#4620](https://github.com/XRPLF/rippled/pull/4620) - - Added errors for malformed `gateway_balances` and `channel_authorize` requests. [#4618](https://github.com/XRPLF/rippled/pull/4618) - - Added a `DeliverMax` alias to `Amount` and removed `Amount`. [#4733](https://github.com/XRPLF/rippled/pull/4733) - - Removed `tx_history` and `ledger_header` methods. Also updated `RPC::Handler` to allow for version-specific methods. [#4759](https://github.com/XRPLF/rippled/pull/4759) - - Standardized the JSON serialization format of transactions. [#4727](https://github.com/XRPLF/rippled/issues/4727) - - Bumped API support to v2, but kept the command-line interface for `rippled` and unit tests at v1. [#4803](https://github.com/XRPLF/rippled/pull/4803) - - Standardized `ledger_index` to return as a number. [#4820](https://github.com/XRPLF/rippled/pull/4820) - -- Added a `server_definitions` command that returns an SDK-compatible `definitions.json` file, generated from the `rippled` instance currently running. [#4703](https://github.com/XRPLF/rippled/pull/4703) - -- Improved unit test command line input and run times. [#4634](https://github.com/XRPLF/rippled/pull/4634) - -- Added the link compression setting to the the `rippled-example.cfg` file. [#4753](https://github.com/XRPLF/rippled/pull/4753) - -- Changed the reserved hook error code name from `tecHOOK_ERROR` to `tecHOOK_REJECTED`. [#4559](https://github.com/XRPLF/rippled/pull/4559) - - -### Bug Fixes and Performance Improvements -(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) - -- Simplified `TxFormats` common fields logic. [#4637](https://github.com/XRPLF/rippled/pull/4637) - -- Improved transaction throughput by asynchronously writing batches to *NuDB*. [#4503](https://github.com/XRPLF/rippled/pull/4503) - -- Removed 2 unused functions. [#4708](https://github.com/XRPLF/rippled/pull/4708) - -- Removed an unused variable that caused clang 14 build errors. [#4672](https://github.com/XRPLF/rippled/pull/4672) - -- Fixed comment about return value of `LedgerHistory::fixIndex`. [#4574](https://github.com/XRPLF/rippled/pull/4574) - -- Updated `secp256k1` to 0.3.2. [#4653](https://github.com/XRPLF/rippled/pull/4653) - -- Removed built-in SNTP clock issues. [#4628](https://github.com/XRPLF/rippled/pull/4628) - -- Fixed amendment flapping. This issue usually occurred when an amendment was on the verge of gaining majority, but a validator not in favor of the amendment went offline. [#4410](https://github.com/XRPLF/rippled/pull/4410) - -- Fixed asan stack-use-after-scope issue. [#4676](https://github.com/XRPLF/rippled/pull/4676) - -- Transactions and pseudo-transactions share the same `commonFields` again. [#4715](https://github.com/XRPLF/rippled/pull/4715) - -- Reduced boilerplate in `applySteps.cpp`. When a new transactor is added, only one function needs to be modified now. [#4710](https://github.com/XRPLF/rippled/pull/4710) - -- Removed an incorrect assert. [#4743](https://github.com/XRPLF/rippled/pull/4743) - -- Replaced some asserts in `PeerFinder::Logic` with `LogicError` to better indicate the nature of server crashes. [#4562](https://github.com/XRPLF/rippled/pull/4562) - -- Fixed an issue with enabling new amendments on a network with an ID greater than 1024. [#4737](https://github.com/XRPLF/rippled/pull/4737) - - -### Docs and Build System - -- Updated `rippled-example.cfg` docs to clarify usage of *ssl_cert* vs *ssl_chain*. [#4667](https://github.com/XRPLF/rippled/pull/4667) - -- Updated `BUILD.md`: - - Made the `environment.md` link easier to find. Also made it easier to find platform-specific info. [#4507](https://github.com/XRPLF/rippled/pull/4507) - - Fixed typo. [#4718](https://github.com/XRPLF/rippled/pull/4718) - - Updated the minimum compiler requirements. [#4700](https://github.com/XRPLF/rippled/pull/4700) - - Added note about enabling `XRPFees`. [#4741](https://github.com/XRPLF/rippled/pull/4741) - -- Updated `API-CHANGELOG.md`: - - Explained API v2 is releasing with `rippled` 2.0.0. [#4633](https://github.com/XRPLF/rippled/pull/4633) - - Clarified the location of the `signer_lists` field in the `account_info` response for API v2. [#4724](https://github.com/XRPLF/rippled/pull/4724) - - Added documentation for the new `DeliverMax` field. [#4784](https://github.com/XRPLF/rippled/pull/4784) - - Removed references to API v2 being "in progress" and "in beta". [#4828](https://github.com/XRPLF/rippled/pull/4828) - - Clarified that all breaking API changes will now occur in API v3 or later. [#4773](https://github.com/XRPLF/rippled/pull/4773) - -- Fixed a mistake in the overlay README. [#4635](https://github.com/XRPLF/rippled/pull/4635) - -- Fixed an early return from `RippledRelease.cmake` that prevented targets from being created during packaging. [#4707](https://github.com/XRPLF/rippled/pull/4707) - -- Fixed a build error with Intel Macs. [#4632](https://github.com/XRPLF/rippled/pull/4632) - -- Added `.build` to `.gitignore`. [#4722](https://github.com/XRPLF/rippled/pull/4722) - -- Fixed a `uint is not universally defined` Windows build error. [#4731](https://github.com/XRPLF/rippled/pull/4731) - -- Reenabled Windows CI build with Artifactory support. [#4596](https://github.com/XRPLF/rippled/pull/4596) - -- Fixed output of remote step in Nix workflow. [#4746](https://github.com/XRPLF/rippled/pull/4746) - -- Fixed a broken link in `conan.md`. [#4740](https://github.com/XRPLF/rippled/pull/4740) - -- Added a `python` call to fix the `pip` upgrade command in Windows CI. [#4768](https://github.com/XRPLF/rippled/pull/4768) - -- Added an API Impact section to `pull_request_template.md`. [#4757](https://github.com/XRPLF/rippled/pull/4757) - -- Set permissions for the Doxygen workflow. [#4756](https://github.com/XRPLF/rippled/pull/4756) - -- Switched to Unity builds to speed up Windows CI. [#4780](https://github.com/XRPLF/rippled/pull/4780) - -- Clarified what makes consensus healthy in `FeeEscalation.md`. [#4729](https://github.com/XRPLF/rippled/pull/4729) - -- Removed a dependency on the header for unit tests. [#4788](https://github.com/XRPLF/rippled/pull/4788) - -- Fixed a clang `unused-but-set-variable` warning. [#4677](https://github.com/XRPLF/rippled/pull/4677) - -- Removed an unused Dockerfile. [#4791](https://github.com/XRPLF/rippled/pull/4791) - -- Fixed unit tests to work with API v2. [#4785](https://github.com/XRPLF/rippled/pull/4785) - -- Added support for the mold linker on Linux. [#4807](https://github.com/XRPLF/rippled/pull/4807) - -- Updated Linux distribtuions `rippled` smoke tests run on. [#4813](https://github.com/XRPLF/rippled/pull/4813) - -- Added codename `bookworm` to the distribution matrix during Artifactory uploads, enabling Debian 12 clients to install `rippled` packages. [#4836](https://github.com/XRPLF/rippled/pull/4836) - -- Added a workaround for compilation errors with GCC 13 and other compilers relying on libstdc++ version 13. [#4817](https://github.com/XRPLF/rippled/pull/4817) - -- Fixed a minor typo in the code comments of `AMMCreate.h`. [4821](https://github.com/XRPLF/rippled/pull/4821) - - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -- Bronek Kozicki -- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> -- Denis Angell -- Ed Hennis -- Elliot Lee -- Florent <36513774+florent-uzio@users.noreply.github.com> -- ForwardSlashBack <142098649+ForwardSlashBack@users.noreply.github.com> -- Gregory Tsipenyuk -- Howard Hinnant -- Hussein Badakhchani -- Jackson Mills -- John Freeman -- Manoj Doshi -- Mark Pevec -- Mark Travis -- Mayukha Vadari -- Michael Legleux -- Nik Bougalis -- Peter Chen <34582813+PeterChen13579@users.noreply.github.com> -- Rome Reginelli -- Scott Determan -- Scott Schurr -- Sophia Xie <106177003+sophiax851@users.noreply.github.com> -- Stefan van Kessel -- pwang200 <354723+pwang200@users.noreply.github.com> -- shichengsg002 <147461171+shichengsg002@users.noreply.github.com> -- sokkaofthewatertribe <140777955+sokkaofthewatertribe@users.noreply.github.com> - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the rippled code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - -# Introducing XRP Ledger version 1.12.0 - -Version 1.12.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds new features and bug fixes, and introduces these amendments: - -- `AMM` -- `Clawback` -- `fixReducedOffersV1` - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Action Required - -Three new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, upgrade to version 1.12.0 by September 20, 2023 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - - -## Install / Upgrade - -On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). - -The XRPL Foundation publishes portable binaries, which are drop-in replacements for the `rippled` daemon. [See information and downloads for the portable binaries](https://github.com/XRPLF/rippled-portable-builds#portable-builds-of-the-rippled-server). This will work on most distributions, including Ubuntu 16.04, 18.04, 20.04, and 22.04; CentOS; and others. Please test and open issues on GitHub if there are problems. - - -## Changelog - -### Amendments, New Features, and Changes -(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) - -- **`AMM`**: Introduces an automated market maker (AMM) protocol to the XRP Ledger's decentralized exchange, enabling you to trade assets without a counterparty. For more information about AMMs, see: [Automated Market Maker](https://opensource.ripple.com/docs/xls-30d-amm/amm-uc/). [#4294](https://github.com/XRPLF/rippled/pull/4294) - -- **`Clawback`**: Adds a setting, *Allow Clawback*, which lets an issuer recover, or _claw back_, tokens that they previously issued. Issuers cannot enable this setting if they have issued tokens already. For additional documentation on this feature, see: [#4553](https://github.com/XRPLF/rippled/pull/4553). - -- **`fixReducedOffersV1`**: Reduces the occurrence of order books that are blocked by reduced offers. [#4512](https://github.com/XRPLF/rippled/pull/4512) - -- Added WebSocket and RPC port info to `server_info` responses. [#4427](https://github.com/XRPLF/rippled/pull/4427) - -- Removed the deprecated `accepted`, `seqNum`, `hash`, and `totalCoins` fields from the `ledger` method. [#4244](https://github.com/XRPLF/rippled/pull/4244) - - -### Bug Fixes and Performance Improvements -(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) - -- Added a pre-commit hook that runs the clang-format linter locally before committing changes. To install this feature, see: [CONTRIBUTING](https://github.com/XRPLF/xrpl-dev-portal/blob/master/CONTRIBUTING.md). [#4599](https://github.com/XRPLF/rippled/pull/4599) - -- In order to make it more straightforward to catch and handle overflows: changed the output type of the `mulDiv()` function from `std::pair` to `std::optional`. [#4243](https://github.com/XRPLF/rippled/pull/4243) - -- Updated `Handler::Condition` enum values to make the code less brittle. [#4239](https://github.com/XRPLF/rippled/pull/4239) - -- Renamed `ServerHandlerImp` to `ServerHandler`. [#4516](https://github.com/XRPLF/rippled/pull/4516), [#4592](https://github.com/XRPLF/rippled/pull/4592) - -- Replaced hand-rolled code with `std::from_chars` for better maintainability. [#4473](https://github.com/XRPLF/rippled/pull/4473) - -- Removed an unused `TypedField` move constructor. [#4567](https://github.com/XRPLF/rippled/pull/4567) - - -### Docs and Build System - -- Updated checkout versions to resolve warnings during GitHub jobs. [#4598](https://github.com/XRPLF/rippled/pull/4598) - -- Fixed an issue with the Debian package build. [#4591](https://github.com/XRPLF/rippled/pull/4591) - -- Updated build instructions with additional steps to take after updating dependencies. [#4623](https://github.com/XRPLF/rippled/pull/4623) - -- Updated contributing doc to clarify that beta releases should also be pushed to the `release` branch. [#4589](https://github.com/XRPLF/rippled/pull/4589) - -- Enabled the `BETA_RPC_API` flag in the default unit tests config, making the API v2 (beta) available to unit tests. [#4573](https://github.com/XRPLF/rippled/pull/4573) - -- Conan dependency management. - - Fixed package definitions for Conan. [#4485](https://github.com/XRPLF/rippled/pull/4485) - - Updated build dependencies to the most recent versions in Conan Center. [#4595](https://github.com/XRPLF/rippled/pull/4595) - - Updated Conan recipe for NuDB. [#4615](https://github.com/XRPLF/rippled/pull/4615) - -- Added binary hardening and linker flags to enhance security during the build process. [#4603](https://github.com/XRPLF/rippled/pull/4603) - -- Added an Artifactory to the `nix` workflow to improve build times. [#4556](https://github.com/XRPLF/rippled/pull/4556) - -- Added quality-of-life improvements to workflows, using new [concurrency control](https://docs.github.com/en/actions/using-jobs/using-concurrency) features. [#4597](https://github.com/XRPLF/rippled/pull/4597) - - -[Full Commit Log](https://github.com/XRPLF/rippled/compare/1.11.0...1.12.0) - - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - - -## Credits - -The following people contributed directly to this release: - -- Alphonse N. Mousse <39067955+a-noni-mousse@users.noreply.github.com> -- Arihant Kothari -- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> -- Denis Angell -- Ed Hennis -- Elliot Lee -- Gregory Tsipenyuk -- Howard Hinnant -- Ikko Eltociear Ashimine -- John Freeman -- Manoj Doshi -- Mark Travis -- Mayukha Vadari -- Michael Legleux -- Peter Chen <34582813+PeterChen13579@users.noreply.github.com> -- RichardAH -- Rome Reginelli -- Scott Schurr -- Shawn Xie <35279399+shawnxie999@users.noreply.github.com> -- drlongle - -Bug Bounties and Responsible Disclosures: - -We welcome reviews of the rippled code and urge researchers to responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - -# Introducing XRP Ledger version 1.11.0 - -Version 1.11.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. - -This release reduces memory usage, introduces the `fixNFTokenRemint` amendment, and adds new features and bug fixes. For example, the new NetworkID field in transactions helps to prevent replay attacks with side-chains. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Action Required - -The `fixNFTokenRemint` amendment is now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, upgrade to version 1.11.0 by July 5 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - - -## Install / Upgrade - -On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). - - -## What's Changed - -### New Features and Improvements - -* Allow port numbers be be specified using a either a colon or a space by @RichardAH in https://github.com/XRPLF/rippled/pull/4328 -* Eliminate memory allocation from critical path: by @nbougalis in https://github.com/XRPLF/rippled/pull/4353 -* Make it easy for projects to depend on libxrpl by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4449 -* Add the ability to mark amendments as obsolete by @ximinez in https://github.com/XRPLF/rippled/pull/4291 -* Always create the FeeSettings object in genesis ledger by @ximinez in https://github.com/XRPLF/rippled/pull/4319 -* Log exception messages in several locations by @drlongle in https://github.com/XRPLF/rippled/pull/4400 -* Parse flags in account_info method by @drlongle in https://github.com/XRPLF/rippled/pull/4459 -* Add NFTokenPages to account_objects RPC by @RichardAH in https://github.com/XRPLF/rippled/pull/4352 -* add jss fields used by clio `nft_info` by @ledhed2222 in https://github.com/XRPLF/rippled/pull/4320 -* Introduce a slab-based memory allocator and optimize SHAMapItem by @nbougalis in https://github.com/XRPLF/rippled/pull/4218 -* Add NetworkID field to transactions to help prevent replay attacks on and from side-chains by @RichardAH in https://github.com/XRPLF/rippled/pull/4370 -* If present, set quorum based on command line. by @mtrippled in https://github.com/XRPLF/rippled/pull/4489 -* API does not accept seed or public key for account by @drlongle in https://github.com/XRPLF/rippled/pull/4404 -* Add `nftoken_id`, `nftoken_ids` and `offer_id` meta fields into NFT `Tx` responses by @shawnxie999 in https://github.com/XRPLF/rippled/pull/4447 - -### Bug Fixes - -* fix(gateway_balances): handle overflow exception by @RichardAH in https://github.com/XRPLF/rippled/pull/4355 -* fix(ValidatorSite): handle rare null pointer dereference in timeout by @ximinez in https://github.com/XRPLF/rippled/pull/4420 -* RPC commands understand markers derived from all ledger object types by @ximinez in https://github.com/XRPLF/rippled/pull/4361 -* `fixNFTokenRemint`: prevent NFT re-mint: by @shawnxie999 in https://github.com/XRPLF/rippled/pull/4406 -* Fix a case where ripple::Expected returned a json array, not a value by @scottschurr in https://github.com/XRPLF/rippled/pull/4401 -* fix: Ledger data returns an empty list (instead of null) when all entries are filtered out by @drlongle in https://github.com/XRPLF/rippled/pull/4398 -* Fix unit test ripple.app.LedgerData by @drlongle in https://github.com/XRPLF/rippled/pull/4484 -* Fix the fix for std::result_of by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4496 -* Fix errors for Clang 16 by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4501 -* Ensure that switchover vars are initialized before use: by @seelabs in https://github.com/XRPLF/rippled/pull/4527 -* Move faulty assert by @ximinez in https://github.com/XRPLF/rippled/pull/4533 -* Fix unaligned load and stores: (#4528) by @seelabs in https://github.com/XRPLF/rippled/pull/4531 -* fix node size estimation by @dangell7 in https://github.com/XRPLF/rippled/pull/4536 -* fix: remove redundant moves by @ckeshava in https://github.com/XRPLF/rippled/pull/4565 - -### Code Cleanup and Testing - -* Replace compare() with the three-way comparison operator in base_uint, Issue and Book by @drlongle in https://github.com/XRPLF/rippled/pull/4411 -* Rectify the import paths of boost::function_output_iterator by @ckeshava in https://github.com/XRPLF/rippled/pull/4293 -* Expand Linux test matrix by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4454 -* Add patched recipe for SOCI by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4510 -* Switch to self-hosted runners for macOS by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4511 -* [TRIVIAL] Add missing includes by @seelabs in https://github.com/XRPLF/rippled/pull/4555 - -### Docs - -* Refactor build instructions by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4381 -* Add install instructions for package managers by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4472 -* Fix typo by @solmsted in https://github.com/XRPLF/rippled/pull/4508 -* Update environment.md by @sappenin in https://github.com/XRPLF/rippled/pull/4498 -* Update BUILD.md by @oeggert in https://github.com/XRPLF/rippled/pull/4514 -* Trivial: add comments for NFToken-related invariants by @scottschurr in https://github.com/XRPLF/rippled/pull/4558 - -## New Contributors -* @drlongle made their first contribution in https://github.com/XRPLF/rippled/pull/4411 -* @ckeshava made their first contribution in https://github.com/XRPLF/rippled/pull/4293 -* @solmsted made their first contribution in https://github.com/XRPLF/rippled/pull/4508 -* @sappenin made their first contribution in https://github.com/XRPLF/rippled/pull/4498 -* @oeggert made their first contribution in https://github.com/XRPLF/rippled/pull/4514 - -**Full Changelog**: https://github.com/XRPLF/rippled/compare/1.10.1...1.11.0 - - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - -### Credits - -The following people contributed directly to this release: -- Alloy Networks <45832257+alloynetworks@users.noreply.github.com> -- Brandon Wilson -- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> -- David Fuelling -- Denis Angell -- Ed Hennis -- Elliot Lee -- John Freeman -- Mark Travis -- Nik Bougalis -- RichardAH -- Scott Determan -- Scott Schurr -- Shawn Xie <35279399+shawnxie999@users.noreply.github.com> -- drlongle -- ledhed2222 -- oeggert <117319296+oeggert@users.noreply.github.com> -- solmsted - - -Bug Bounties and Responsible Disclosures: -We welcome reviews of the rippled code and urge researchers to -responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - bugs@xrpl.org - - -# Introducing XRP Ledger version 1.10.1 - -Version 1.10.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release restores packages for Ubuntu 18.04. - -Compared to version 1.10.0, the only C++ code change fixes an edge case in Reporting Mode. - -If you are already running version 1.10.0, then upgrading to version 1.10.1 is generally not required. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Install / Upgrade - -On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). - -## Changelog - -- [`da18c86cbf`](https://github.com/ripple/rippled/commit/da18c86cbfea1d8fe6940035f9103e15890d47ce) Build packages with Ubuntu 18.04 -- [`f7b3ddd87b`](https://github.com/ripple/rippled/commit/f7b3ddd87b8ef093a06ab1420bea57ed1e77643a) Reporting Mode: Do not attempt to acquire missing data from peer network (#4458) - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - -### Credits - -The following people contributed directly to this release: - -- John Freeman -- Mark Travis -- Michael Legleux - -Bug Bounties and Responsible Disclosures: -We welcome reviews of the rippled code and urge researchers to -responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - bugs@xrpl.org - - -# Introducing XRP Ledger version 1.10.0 - -Version 1.10.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release introduces six new amendments, detailed below, and cleans up code to improve performance. - -[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) - - - -## Action Required - -Six new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, upgrade to version 1.10.0 by March 21 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - - -## Install / Upgrade - -On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). - - -## New Amendments - -- **`featureImmediateOfferKilled`**: Changes the response code of an `OfferCreate` transaction with the `tfImmediateOrCancel` flag to return `tecKILLED` when no funds are moved. The previous return code of `tecSUCCESS` was unintuitive. [#4157](https://github.com/XRPLF/rippled/pull/4157) - -- **`featureDisallowIncoming`**: Enables an account to block incoming checks, payment channels, NFToken offers, and trust lines. [#4336](https://github.com/XRPLF/rippled/pull/4336) - -- **`featureXRPFees`**: Simplifies transaction cost calculations to use XRP directly, rather than calculating indirectly in "fee units" and translating the results to XRP. Updates all instances of "fee units" in the protocol and ledger data to be drops of XRP instead. [#4247](https://github.com/XRPLF/rippled/pull/4247) - -- **`fixUniversalNumber`**: Simplifies and unifies the code for decimal floating point math. In some cases, this provides slightly better accuracy than the previous code, resulting in calculations whose least significant digits are different than when calculated with the previous code. The different results may cause other edge case differences where precise calculations are used, such as ranking of offers or processing of payments that use several different paths. [#4192](https://github.com/XRPLF/rippled/pull/4192) - -- **`fixNonFungibleTokensV1_2`**: This amendment is a combination of NFToken fixes. [#4417](https://github.com/XRPLF/rippled/pull/4417) - - Fixes unburnable NFTokens when it has over 500 offers. [#4346](https://github.com/XRPLF/rippled/pull/4346) - - Fixes 3 NFToken offer acceptance issues. [#4380](https://github.com/XRPLF/rippled/pull/4380) - - Prevents brokered sales of NFTokens to owners. [#4403](https://github.com/XRPLF/rippled/pull/4403) - - Only allows the destination to settle NFToken offers through brokerage. [#4399](https://github.com/XRPLF/rippled/pull/4399) - -- **`fixTrustLinesToSelf`**: Trust lines must be between two different accounts, but two exceptions exist because of a bug that briefly existed. This amendment removes those trust lines. [69bb2be](https://github.com/XRPLF/rippled/pull/4270/commits/69bb2be446e3cc24c694c0835b48bd2ecd3d119e) - - -## Changelog - - -### New Features and Improvements - -- **Improve Handshake in the peer protocol**: Switched to using a cryptographically secure PRNG for the Instance Cookie. `rippled` now uses hex encoding for the `Closed-Ledger` and `Previous-Ledger` fields in the Handshake. Also added `--newnodeid` and `--nodeid` command line options. [5a15229](https://github.com/XRPLF/rippled/pull/4270/commits/5a15229eeb13b69c8adf1f653b88a8f8b9480546) - -- **RPC tooBusy response now has 503 HTTP status code**: Added ripplerpc 3.0, enabling RPC tooBusy responses to return relevant HTTP status codes. This is a non-breaking change that only applies to JSON-RPC when you include `"ripplerpc": "3.0"` in the request. [#4143](https://github.com/XRPLF/rippled/pull/4143) - -- **Use the Conan package manager**: Added a `conanfile.py` and Conan recipe for Snappy. Removed the RocksDB recipe from the repo; you can now get it from Conan Center. [#4367](https://github.com/XRPLF/rippled/pull/4367), [c2b03fe](https://github.com/XRPLF/rippled/commit/c2b03fecca19a304b37467b01fa78593d3dce3fb) - -- **Update Build Instructions**: Updated the build instructions to build with the Conan package manager and restructured info for easier comprehension. [#4376](https://github.com/XRPLF/rippled/pull/4376), [#4383](https://github.com/XRPLF/rippled/pull/4383) - -- **Revise CONTRIBUTING**: Updated code contribution guidelines. `rippled` is an open source project and contributions are very welcome. [#4382](https://github.com/XRPLF/rippled/pull/4382) - -- **Update documented pathfinding configuration defaults**: `417cfc2` changed the default Path Finding configuration values, but missed updating the values documented in rippled-example.cfg. Updated those defaults and added recommended values for nodes that want to support advanced pathfinding. [#4409](https://github.com/XRPLF/rippled/pull/4409) - -- **Remove gRPC code previously used for the Xpring SDK**: Removed gRPC code used for the Xpring SDK. The gRPC API is also enabled locally by default in `rippled-example.cfg`. This API is used for [Reporting Mode](https://xrpl.org/build-run-rippled-in-reporting-mode.html) and [Clio](https://github.com/XRPLF/clio). [28f4cc7](https://github.com/XRPLF/rippled/pull/4321/commits/28f4cc7817c2e477f0d7e9ade8f07a45ff2b81f1) - -- **Switch from C++17 to C++20**: Updated `rippled` to use C++20. [92d35e5](https://github.com/XRPLF/rippled/pull/4270/commits/92d35e54c7de6bbe44ff6c7c52cc0765b3f78258) - -- **Support for Boost 1.80.0:**: [04ef885](https://github.com/XRPLF/rippled/pull/4321/commits/04ef8851081f6ee9176783ad3725960b8a931ebb) - -- **Reduce default reserves to 10/2**: Updated the hard-coded default reserves to match the current settings on Mainnet. [#4329](https://github.com/XRPLF/rippled/pull/4329) - -- **Improve self-signed certificate generation**: Improved speed and security of TLS certificate generation on fresh startup. [0ecfc7c](https://github.com/XRPLF/rippled/pull/4270/commits/0ecfc7cb1a958b731e5f184876ea89ae2d4214ee) - - -### Bug Fixes - -- **Update command-line usage help message**: Added `manifest` and `validator_info` to the `rippled` CLI usage statement. [b88ed5a](https://github.com/XRPLF/rippled/pull/4270/commits/b88ed5a8ec2a0735031ca23dc6569d54787dc2f2) - -- **Work around gdb bug by changing a template parameter**: Added a workaround for a bug in gdb, where unsigned template parameters caused issues with RTTI. [#4332](https://github.com/XRPLF/rippled/pull/4332) - -- **Fix clang 15 warnings**: [#4325](https://github.com/XRPLF/rippled/pull/4325) - -- **Catch transaction deserialization error in doLedgerGrpc**: Fixed an issue in the gRPC API, so `Clio` can extract ledger headers and state objects from specific transactions that can't be deserialized by `rippled` code. [#4323](https://github.com/XRPLF/rippled/pull/4323) - -- **Update dependency: gRPC**: New Conan recipes broke the old version of gRPC, so the dependency was updated. [#4407](https://github.com/XRPLF/rippled/pull/4407) - -- **Fix Doxygen workflow**: Added options to build documentation that don't depend on the library dependencies of `rippled`. [#4372](https://github.com/XRPLF/rippled/pull/4372) - -- **Don't try to read SLE with key 0 from the ledger**: Fixed the `preclaim` function to check for 0 in `NFTokenSellOffer` and `NFTokenBuyOffer` before calling `Ledger::read`. This issue only affected debug builds. [#4351](https://github.com/XRPLF/rippled/pull/4351) - -- **Update broken link to hosted Doxygen content**: [5e1cb09](https://github.com/XRPLF/rippled/pull/4270/commits/5e1cb09b8892e650f6c34a66521b6b1673bd6b65) - - -### Code Cleanup - -- **Prevent unnecessary `shared_ptr` copies by accepting a value in `SHAMapInnerNode::setChild`**: [#4266](https://github.com/XRPLF/rippled/pull/4266) - -- **Release TaggedCache object memory outside the lock**: [3726f8b](https://github.com/XRPLF/rippled/pull/4321/commits/3726f8bf31b3eab8bab39dce139656fd705ae9a0) - -- **Rename SHAMapStoreImp::stopping() to healthWait()**: [7e9e910](https://github.com/XRPLF/rippled/pull/4321/commits/7e9e9104eabbf0391a0837de5630af17a788e233) - -- **Improve wrapper around OpenSSL RAND**: [7b3507b](https://github.com/XRPLF/rippled/pull/4270/commits/7b3507bb873495a974db33c57a888221ddabcacc) - -- **Improve AccountID string conversion caching**: Improved memory cache usage. [e2eed96](https://github.com/XRPLF/rippled/pull/4270/commits/e2eed966b0ecb6445027e6a023b48d702c5f4832) - -- **Build the command map at compile time**: [9aaa0df](https://github.com/XRPLF/rippled/pull/4270/commits/9aaa0dff5fd422e5f6880df8e20a1fd5ad3b4424) - -- **Avoid unnecessary copying and dynamic memory allocations**: [d318ab6](https://github.com/XRPLF/rippled/pull/4270/commits/d318ab612adc86f1fd8527a50af232f377ca89ef) - -- **Use constexpr to check memo validity**: [e67f905](https://github.com/XRPLF/rippled/pull/4270/commits/e67f90588a9050162881389d7e7d1d0fb31066b0) - -- **Remove charUnHex**: [83ac141](https://github.com/XRPLF/rippled/pull/4270/commits/83ac141f656b1a95b5661853951ebd95b3ffba99) - -- **Remove deprecated AccountTxOld.cpp**: [ce64f7a](https://github.com/XRPLF/rippled/pull/4270/commits/ce64f7a90f99c6b5e68d3c3d913443023de061a6) - -- **Remove const_cast usage**: [23ce431](https://github.com/XRPLF/rippled/pull/4321/commits/23ce4318768b718c82e01004d23f1abc9a9549ff) - -- **Remove inaccessible code paths and outdated data format wchar_t**: [95fabd5](https://github.com/XRPLF/rippled/pull/4321/commits/95fabd5762a4917753c06268192e4d4e4baef8e4) - -- **Improve move semantics in Expected**: [#4326](https://github.com/XRPLF/rippled/pull/4326) - - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. - -### Credits - -The following people contributed directly to this release: - -- Alexander Kremer -- Alloy Networks <45832257+alloynetworks@users.noreply.github.com> -- CJ Cobb <46455409+cjcobb23@users.noreply.github.com> -- Chenna Keshava B S -- Crypto Brad Garlinghouse -- Denis Angell -- Ed Hennis -- Elliot Lee -- Gregory Popovitch -- Howard Hinnant -- J. Scott Branson <18340247+crypticrabbit@users.noreply.github.com> -- John Freeman -- ledhed2222 -- Levin Winter <33220502+levinwinter@users.noreply.github.com> -- manojsdoshi -- Nik Bougalis -- RichardAH -- Scott Determan -- Scott Schurr -- Shawn Xie <35279399+shawnxie999@users.noreply.github.com> - -Security Bug Bounty Acknowledgements: -- Aaron Hook -- Levin Winter - -Bug Bounties and Responsible Disclosures: -We welcome reviews of the rippled code and urge researchers to -responsibly disclose any issues they may find. - -To report a bug, please send a detailed report to: - - bugs@xrpl.org - - -# Introducing XRP Ledger version 1.9.4 - -Version 1.9.4 of `rippled`, the reference implementation of the XRP Ledger protocol is now available. This release introduces an amendment that removes the ability for an NFT issuer to indicate that trust lines should be automatically created for royalty payments from secondary sales of NFTs, in response to a bug report that indicated how this functionality could be abused to mount a denial of service attack against the issuer. - -## Action Required - -This release introduces a new amendment to the XRP Ledger protocol, **`fixRemoveNFTokenAutoTrustLine`** to mitigate a potential denial-of-service attack against NFT issuers that minted NFTs and allowed secondary trading of those NFTs to create trust lines for any asset. - -This amendment is open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, then you should upgrade to version 1.9.4 within two weeks, to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - -For more information about NFTs on the XRP Ledger, see [NFT Conceptual Overview](https://xrpl.org/nft-conceptual-overview.html). - - -## Install / Upgrade - -On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). - -## Changelog - -## Contributions - -The primary change in this release is the following bug fix: - -- **Introduce fixRemoveNFTokenAutoTrustLine amendment**: Introduces the `fixRemoveNFTokenAutoTrustLine` amendment, which disables the `tfTrustLine` flag, which a malicious attacker could exploit to mount denial-of-service attacks against NFT issuers that specified the flag on their NFTs. ([#4301](https://github.com/XRPLF/rippled/4301)) - - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome all contributions and invite everyone to join the community of XRP Ledger developers and help us build the Internet of Value. - -### Credits - -The following people contributed directly to this release: - -- Scott Schurr -- Howard Hinnant -- Scott Determan -- Ikko Ashimine - - -# Introducing XRP Ledger version 1.9.3 - -Version 1.9.3 of `rippled`, the reference server implementation of the XRP Ledger protocol is now available. This release corrects minor technical flaws with the code that loads configured amendment votes after a startup and the copy constructor of `PublicKey`. - -## Install / Upgrade - -On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). - -## Changelog - -## Contributions - -This release contains the following bug fixes: - -- **Change by-value to by-reference to persist vote**: A minor technical flaw, caused by use of a copy instead of a reference, resulted in operator-configured "yes" votes to not be properly loaded after a restart. ([#4256](https://github.com/XRPLF/rippled/pull/4256)) -- **Properly handle self-assignment of PublicKey**: The `PublicKey` copy assignment operator mishandled the case where a `PublicKey` would be assigned to itself, and could result in undefined behavior. - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome contributions, big and small, and invite everyone to join the community of XRP Ledger developers and help us build the Internet of Value. - -### Credits - -The following people contributed directly to this release: - -- Howard Hinnant -- Crypto Brad Garlinghouse -- Wo Jake <87929946+wojake@users.noreply.github.com> - - -# Introducing XRP Ledger version 1.9.2 - -Version 1.9.2 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes several fixes and improvements, including a second new fix amendment to correct a bug in Non-Fungible Tokens (NFTs) code, a new API method for order book changes, less noisy logging, and other small fixes. - - - - -## Action Required - -This release introduces a two new amendments to the XRP Ledger protocol. The first, **fixNFTokenNegOffer**, fixes a bug in code associated with the **NonFungibleTokensV1** amendment, originally introduced in [version 1.9.0](https://xrpl.org/blog/2022/rippled-1.9.0.html). The second, **NonFungibleTokensV1_1**, is a "roll-up" amendment that enables the **NonFungibleTokensV1** feature plus the two fix amendments associated with it, **fixNFTokenDirV1** and **fixNFTokenNegOffer**. - -If you want to enable NFT code on the XRP Ledger Mainnet, you can vote in favor of only the **NonFungibleTokensV1_1** amendment to support enabling the feature and fixes together, without risk that the unfixed NFT code may become enabled first. - -These amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, then you should upgrade to version 1.9.2 within two weeks, to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - -For more information about NFTs on the XRP Ledger, see [NFT Conceptual Overview](https://xrpl.org/nft-conceptual-overview.html). - -## Install / Upgrade - -On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). - -## Changelog - -This release contains the following features and improvements. - -- **Introduce fixNFTokenNegOffer amendment.** This amendment fixes a bug in the Non-Fungible Tokens (NFTs) functionality provided by the NonFungibleTokensV1 amendment (not currently enabled on Mainnet). The bug allowed users to place offers to buy tokens for negative amounts of money when using Brokered Mode. Anyone who accepted such an offer would transfer the token _and_ pay money. This amendment explicitly disallows offers to buy or sell NFTs for negative amounts of money, and returns an appropriate error code. This also corrects the error code returned when placing offers to buy or sell NFTs for negative amounts in Direct Mode. ([8266d9d](https://github.com/XRPLF/rippled/commit/8266d9d598d19f05e1155956b30ca443c27e119e)) -- **Introduce `NonFungibleTokensV1_1` amendment.** This amendment encompasses three NFT-related amendments: the original NonFungibleTokensV1 amendment (from version 1.9.0), the fixNFTokenDirV1 amendment (from version 1.9.1), and the new fixNFTokenNegOffer amendment from this release. This amendment contains no changes other than enabling those three amendments together; this allows validators to vote in favor of _only_ enabling the feature and fixes at the same time. ([59326bb](https://github.com/XRPLF/rippled/commit/59326bbbc552287e44b3a0d7b8afbb1ddddb3e3b)) -- **Handle invalid port numbers.** If the user specifies a URL with an invalid port number, the server would silently attempt to use port 0 instead. Now it raises an error instead. This affects admin API methods and config file parameters for downloading history shards and specifying validator list sites. ([#4213](https://github.com/XRPLF/rippled/pull/4213)) -- **Reduce log noisiness.** Decreased the severity of benign log messages in several places: "addPathsForType" messages during regular operation, expected errors during unit tests, and missing optional documentation components when compiling from source. ([#4178](https://github.com/XRPLF/rippled/pull/4178), [#4166](https://github.com/XRPLF/rippled/pull/4166), [#4180](https://github.com/XRPLF/rippled/pull/4180)) -- **Fix race condition in history shard implementation and support clang's ThreadSafetyAnalysis tool.** Added build settings so that developers can use this feature of the clang compiler to analyze the code for correctness, and fix an error found by this tool, which was the source of rare crashes in unit tests. ([#4188](https://github.com/XRPLF/rippled/pull/4188)) -- **Prevent crash when rotating a database with missing data.** When rotating databases, a missing entry could cause the server to crash. While there should never be a missing database entry, this change keeps the server running by aborting database rotation. ([#4182](https://github.com/XRPLF/rippled/pull/4182)) -- **Fix bitwise comparison in OfferCreate.** Fixed an expression that incorrectly used a bitwise comparison for two boolean values rather than a true boolean comparison. The outcome of the two comparisons is equivalent, so this is not a transaction processing change, but the bitwise comparison relied on compilers to implicitly fix the expression. ([#4183](https://github.com/XRPLF/rippled/pull/4183)) -- **Disable cluster timer when not in a cluster.** Disabled a timer that was unused on servers not running in clustered mode. The functionality of clustered servers is unchanged. ([#4173](https://github.com/XRPLF/rippled/pull/4173)) -- **Limit how often to process peer discovery messages.** In the peer-to-peer network, servers periodically share IP addresses of their peers with each other to facilitate peer discovery. It is not necessary to process these types of messages too often; previously, the code tracked whether it needed to process new messages of this type but always processed them anyway. With this change, the server no longer processes peer discovery messages if it has done so recently. ([#4202](https://github.com/XRPLF/rippled/pull/4202)) -- **Improve STVector256 deserialization.** Optimized the processing of this data type in protocol messages. This data type is used in several types of ledger entry that are important for bookkeeping, including directory pages that track other ledger types, amendments tracking, and the ledger hashes history. ([#4204](https://github.com/XRPLF/rippled/pull/4204)) -- **Fix and refactor spinlock code.** The spinlock code, which protects the `SHAMapInnerNode` child lists, had a mistake that allowed the same child to be repeatedly locked under some circumstances. Fixed this bug and improved the spinlock code to make it easier to use correctly and easier to verify that the code works correctly. ([#4201](https://github.com/XRPLF/rippled/pull/4201)) -- **Improve comments and contributor documentation.** Various minor documentation changes including some to reflect the fact that the source code repository is now owned by the XRP Ledger Foundation. ([#4214](https://github.com/XRPLF/rippled/pull/4214), [#4179](https://github.com/XRPLF/rippled/pull/4179), [#4222](https://github.com/XRPLF/rippled/pull/4222)) -- **Introduces a new API book_changes to provide information in a format that is useful for building charts that highlight DEX activity at a per-ledger level.** ([#4212](https://github.com/XRPLF/rippled/pull/4212)) - -## Contributions - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome contributions, big and small, and invite everyone to join the community of XRP Ledger developers and help us build the Internet of Value. - -### Credits - -The following people contributed directly to this release: - -- Chenna Keshava B S -- Ed Hennis -- Ikko Ashimine -- Nik Bougalis -- Richard Holland -- Scott Schurr -- Scott Determan - -For a real-time view of all lifetime contributors, including links to the commits made by each, please visit the "Contributors" section of the GitHub repository: . - -# Introducing XRP Ledger version 1.9.1 - -Version 1.9.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes several important fixes, including a fix for a syncing issue from 1.9.0, a new fix amendment to correct a bug in the new Non-Fungible Tokens (NFTs) code, and a new amendment to allow multi-signing by up to 32 signers. - - - - -## Action Required - -This release introduces two new amendments to the XRP Ledger protocol. These amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. - -If you operate an XRP Ledger server, then you should upgrade to version 1.9.1 within two weeks, to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. - -The **fixNFTokenDirV1** amendment fixes a bug in code associated with the **NonFungibleTokensV1** amendment, so the fixNFTokenDirV1 amendment should be enabled first. All validator operators are encouraged to [configure amendment voting](https://xrpl.org/configure-amendment-voting.html) to oppose the NonFungibleTokensV1 amendment until _after_ the fixNFTokenDirV1 amendment has become enabled. For more information about NFTs on the XRP Ledger, see [NFT Conceptual Overview](https://xrpl.org/nft-conceptual-overview.html). - -The **ExpandedSignerList** amendment extends the ledger's built-in multi-signing functionality so that each list can contain up to 32 entries instead of the current limit of 8. Additionally, this amendment allows each signer to have an arbitrary 256-bit data field associated with it. This data can be used to identify the signer or provide other metadata that is useful for organizations, smart contracts, or other purposes. - -## Install / Upgrade - -On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). - -## Changelog - -This release contains the following features and improvements. - -## New Features and Amendments - -- **Introduce fixNFTokenDirV1 Amendment** - This amendment fixes an off-by-one error that occurred in some corner cases when determining which `NFTokenPage` an `NFToken` object belongs on. It also adjusts the constraints of `NFTokenPage` invariant checks, so that certain error cases fail with a suitable error code such as `tecNO_SUITABLE_TOKEN_PAGE` instead of failing with a `tecINVARIANT_FAILED` error code. ([#4155](https://github.com/ripple/rippled/pull/4155)) - -- **Introduce ExpandedSignerList Amendment** - This amendment expands the maximum signer list size to 32 entries and allows each signer to have an optional 256-bit `WalletLocator` field containing arbitrary data. ([#4097](https://github.com/ripple/rippled/pull/4097)) - -- **Pause online deletion rather than canceling it if the server fails health check** - The server stops performing online deletion of old ledger history if the server fails its internal health check during this time. Online deletion can now resume after the server recovers, rather than having to start over. ([#4139](https://github.com/ripple/rippled/pull/4139)) - - -## Bug Fixes and Performance Improvements - -- **Fix performance issues introduced in 1.9.0** - Readjusts some parameters of the ledger acquisition engine to revert some changes introduced in 1.9.0 that had adverse effects on some systems, including causing some systems to fail to sync to the network. ([#4152](https://github.com/ripple/rippled/pull/4152)) - -- **Improve Memory Efficiency of Path Finding** - Finding paths for cross-currency payments is a resource-intensive operation. While that remains true, this fix improves memory usage of pathfinding by discarding trust line results that cannot be used before those results are fully loaded or cached. ([#4111](https://github.com/ripple/rippled/pull/4111)) - -- **Fix incorrect CMake behavior on Windows when platform is unspecified or x64** - Fixes handling of platform selection when using the cmake-gui tool to build on Windows. The generator expects `Win64` but the GUI only provides `x64` as an option, which raises an error. This fix only raises an error if the platform is `Win32` instead, allowing the generation of solution files to succeed. ([#4150](https://github.com/ripple/rippled/pull/4150)) - -- **Fix test failures with newer MSVC compilers on Windows** - Fixes some cases where the API handler code used string pointer comparisons, which may not work correctly with some versions of the MSVC compiler. ([#4149](https://github.com/ripple/rippled/pull/4149)) - -- **Update minimum Boost version to 1.71.0** - This release is compatible with Boost library versions 1.71.0 through 1.77.0. The build configuration and documentation have been updated to reflect this. ([#4134](https://github.com/ripple/rippled/pull/4134)) - -- **Fix unit test failures for DatabaseDownloader** - Increases a timeout in the `DatabaseDownloader` code and adjusts unit tests so that the code does not return spurious failures, and more data is logged if it does fail. ([#4021](https://github.com/ripple/rippled/pull/4021)) - -- **Refactor relational database interface** - Improves code comments, naming, and organization of the module that interfaces with relational databases (such as the SQLite database used for tracking transaction history). ([#3965](https://github.com/ripple/rippled/pull/3965)) - - -## Contributions - -### GitHub - -The public source code repository for `rippled` is hosted on GitHub at . - -We welcome contributions, big and small, and invite everyone to join the community of XRP Ledger developers and help us build the Internet of Value. - - -### Credits - -The following people contributed directly to this release: - -- Devon White -- Ed Hennis -- Gregory Popovitch -- Mark Travis -- Manoj Doshi -- Nik Bougalis -- Richard Holland -- Scott Schurr - -For a real-time view of all lifetime contributors, including links to the commits made by each, please visit the "Contributors" section of the GitHub repository: . - -We welcome external contributions and are excited to see the broader XRP Ledger community continue to grow and thrive. - - -# Change log - -- API version 2 will now return `signer_lists` in the root of the `account_info` response, no longer nested under `account_data`. - -# Releases - -## Version 1.9.0 -This is the 1.9.0 release of `rippled`, the reference implementation of the XRP Ledger protocol. This release brings several features and improvements. - -### New and Improved Features -- **Introduce NFT support (XLS020):** This release introduces support for non-fungible tokens, currently available to the developer community for broader review and testing. Developers can create applications that allow users to mint, transfer, and ultimately burn (if desired) NFTs on the XRP Ledger. You can try out the new NFT transactions using the [nft-devnet](https://xrpl.org/xrp-testnet-faucet.html). Note that some fields and error codes from earlier releases of the supporting code have been refactored for this release, shown in the Code Refactoring section, below. [70779f](https://github.com/ripple/rippled/commit/70779f6850b5f33cdbb9cf4129bc1c259af0013e) - -- **Simplify the Job Queue:** This is a refactor aimed at cleaning up and simplifying the existing job queue. Currently, all jobs are canceled at the same time and in the same way, so this commit removes the unnecessary per-job cancellation token. [#3656](https://github.com/ripple/rippled/pull/3656) - -- **Optimize trust line caching:** The existing trust line caching code was suboptimal in that it stored redundant information, pinned SLEs into memory, and required multiple memory allocations per cached object. This commit eliminates redundant data, reduces the size of cached objects and unpinning SLEs from memory, and uses value types to avoid the need for `std::shared_ptr`. As a result of these changes, the effective size of a cached object includes the overhead of the memory allocator, and the `std::shared_ptr` should be reduced by at least 64 bytes. This is significant, as there can easily be tens of millions of these objects. [4d5459](https://github.com/ripple/rippled/commit/4d5459d041da8f5a349c5f458d664e5865e1f1b5) - -- **Incremental improvements to pathfinding memory usage:** This commit aborts background pathfinding when closed or disconnected, exits the pathfinding job thread if there are no requests left, does not create the path find a job if there are no requests, and refactors to remove the circular dependency between InfoSub and PathRequest. [#4111](https://github.com/ripple/rippled/pull/4111) - -- **Improve deterministic transaction sorting in TxQ:** This commit ensures that transactions with the same fee level are sorted by TxID XORed with the parent ledger hash, the TxQ is re-sorted after every ledger, and attempts to future-proof the TxQ tie-breaking test. [#4077](https://github.com/ripple/rippled/pull/4077) - -- **Improve stop signaling for Application:** [34ca45](https://github.com/ripple/rippled/commit/34ca45713244d0defc39549dd43821784b2a5c1d) - -- **Eliminate SHAMapInnerNode lock contention:** The `SHAMapInnerNode` class had a global mutex to protect the array of node children. Profiling suggested that around 4% of all attempts to lock the global would block. This commit removes that global mutex, and replaces it with a new per-node 16-way spinlock (implemented so as not to affect the size of an inner node object), effectively eliminating the lock contention. [1b9387](https://github.com/ripple/rippled/commit/1b9387eddc1f52165d3243d2ace9be0c62495eea) - -- **Improve ledger-fetching logic:** When fetching ledgers, the existing code would isolate the peer that sent the most useful responses, and issue follow-up queries only to that peer. This commit increases the query aggressiveness, and changes the mechanism used to select which peers to issue follow-up queries to so as to more evenly spread the load among those peers that provided useful responses. [48803a](https://github.com/ripple/rippled/commit/48803a48afc3bede55d71618c2ee38fd9dbfd3b0) - -- **Simplify and improve order book tracking:** The order book tracking code would use `std::shared_ptr` to track the lifetime of objects. This commit changes the logic to eliminate the overhead of `std::shared_ptr` by using value types, resulting in significant memory savings. [b9903b](https://github.com/ripple/rippled/commit/b9903bbcc483a384decf8d2665f559d123baaba2) - -- **Negative cache support for node store:** This commit allows the cache to service requests for nodes that were previously looked up but not found, reducing the need to perform I/O in several common scenarios. [3eb8aa](https://github.com/ripple/rippled/commit/3eb8aa8b80bd818f04c99cee2cfc243192709667) - -- **Improve asynchronous database handlers:** This commit optimizes the way asynchronous node store operations are processed, both by reducing the number of times locks are held and by minimizing the number of memory allocations and data copying. [6faaa9](https://github.com/ripple/rippled/commit/6faaa91850d6b2eb9fbf16c1256bf7ef11ac4646) - -- **Cleanup AcceptedLedger and AcceptedLedgerTx:** This commit modernizes the `AcceptedLedger` and `AcceptedLedgerTx` classes, reduces their memory footprint, and reduces unnecessary dynamic memory allocations. [8f5868](https://github.com/ripple/rippled/commit/8f586870917818133924bf2e11acab5321c2b588) - -### Code Refactoring - -This release includes name changes in the NFToken API for SFields, RPC return labels, and error codes for clarity and consistency. To refactor your code, migrate the names of these items to the new names as listed below. - -#### `SField` name changes: -* `TokenTaxon -> NFTokenTaxon` -* `MintedTokens -> MintedNFTokens` -* `BurnedTokens -> BurnedNFTokens` -* `TokenID -> NFTokenID` -* `TokenOffers -> NFTokenOffers` -* `BrokerFee -> NFTokenBrokerFee` -* `Minter -> NFTokenMinter` -* `NonFungibleToken -> NFToken` -* `NonFungibleTokens -> NFTokens` -* `BuyOffer -> NFTokenBuyOffer` -* `SellOffer -> NFTokenSellOffer` -* `OfferNode -> NFTokenOfferNode` - -#### RPC return labels -* `tokenid -> nft_id` -* `index -> nft_offer_index` - -#### Error codes -* `temBAD_TRANSFER_FEE -> temBAD_NFTOKEN_TRANSFER_FEE` -* `tefTOKEN_IS_NOT_TRANSFERABLE -> tefNFTOKEN_IS_NOT_TRANSFERABLE` -* `tecNO_SUITABLE_PAGE -> tecNO_SUITABLE_NFTOKEN_PAGE` -* `tecBUY_SELL_MISMATCH -> tecNFTOKEN_BUY_SELL_MISMATCH` -* `tecOFFER_TYPE_MISMATCH -> tecNFTOKEN_OFFER_TYPE_MISMATCH` -* `tecCANT_ACCEPT_OWN_OFFER -> tecCANT_ACCEPT_OWN_NFTOKEN_OFFER` - - -### Bug Fixes -- **Fix deletion of orphan node store directories:** Orphaned node store directories should only be deleted if the proper node store directories are confirmed to exist. [06e87e](https://github.com/ripple/rippled/commit/06e87e0f6add5b880d647e14ab3d950decfcf416) - -## Version 1.8.5 -This is the 1.8.5 release of `rippled`, the reference implementation of the XRP Ledger protocol. This release includes fixes and updates for stability and security, and improvements to build scripts. There are no user-facing API or protocol changes in this release. - -### Bug Fixes - -This release contains the following bug fixes and under-the-hood improvements: - -- **Correct TaggedPointer move constructor:** Fixes a bug in unused code for the TaggedPointer class. The old code would fail if a caller explicitly tried to remove a child that is not actually part of the node. (227a12d) - -- **Ensure protocol buffer prerequisites are present:** The build scripts and packages now properly handle Protobuf packages and various packages. Prior to this change, building on Ubuntu 21.10 Impish Indri would fail unless the `libprotoc-dev` package was installed. (e06465f) - -- **Improve handling of endpoints during peer discovery.** This hardens and improves handling of incoming messages on the peer protocol. (289bc0a) - -- **Run tests on updated linux distros:** Test builds now run on Rocky Linux 8, Fedora 34 and 35, Ubuntu 18, 20, and 22, and Debian 9, 10, and 11. (a9ee802) - -- **Avoid dereferencing empty optional in ReportingETL:** Fixes a bug in Reporting Mode that could dereference an empty optional value when throwing an error. (cdc215d) - -- **Correctly add GIT_COMMIT_HASH into version string:** When building the server from a non-tagged release, the build files now add the commit ID in a way that follows the semantic-versioning standard, and correctly handle the case where the commit hash ID cannot be retrieved. (d23d37f) - -- **Update RocksDB to version 6.27.3:** Updates the version of RocksDB included in the server from 6.7.3 (which was released on 2020-03-18) to 6.27.3 (released 2021-12-10). - - - -## Version 1.8.4 -This is the 1.8.4 release of `rippled`, the reference implementation of the XRP Ledger protocol. - -This release corrects a technical flaw introduced with 1.8.3 that may result in failures if the newly-introduced 'fast loading' is enabled. The release also adjusts default parameters used to configure the pathfinding engine to reduce resource usage. - -### Bug Fixes -- **Adjust mutex scope in `walkMapParallel`**: This commit corrects a technical flaw introduced with commit [7c12f0135897361398917ad2c8cda888249d42ae] that would result in undefined behavior if the server operator configured their server to use the 'fast loading' mechanism introduced with 1.8.3. - -- **Adjust pathfinding configuration defaults**: This commit adjusts the default configuration of the pathfinding engine, to account for the size of the XRP Ledger mainnet. Unless explicitly overriden, the changes mean that pathfinding operations will return fewer, shallower paths than previous releases. - - -## Version 1.8.3 -This is the 1.8.3 release of `rippled`, the reference implementation of the XRP Ledger protocol. - -This release implements changes that improve the syncing performance of peers on the network, adds countermeasures to several routines involving LZ4 to defend against CVE-2021-3520, corrects a minor technical flaw that would result in the server not using a cache for nodestore operations, and adjusts tunable values to optimize disk I/O. - -### Summary of Issues -Recently, servers in the XRP Ledger network have been taking an increasingly long time to sync back to the network after restartiningg. This is one of several releases which will be made to improve on this issue. - - -### Bug Fixes - -- **Parallel ledger loader & I/O performance improvements**: This commit makes several changes that, together, should decrease the time needed for a server to sync to the network. To make full use of this change, `rippled` needs to be using storage with high IOPS and operators need to explicitly enable this behavior by adding the following to their config file, under the `[node_db]` stanza: - - [node_db] - ... - fast_load=1 - -Note that when 'fast loading' is enabled the server will not open RPC and WebSocket interfaces until after the initial load is completed. Because of this, it may appear unresponsive or down. - -- **Detect CVE-2021-3520 when decompressing using LZ4**: This commit adds code to detect LZ4 payloads that may result in out-of-bounds memory accesses. - -- **Provide sensible default values for nodestore cache:**: The nodestore includes a built-in cache to reduce the disk I/O load but, by default, this cache was not initialized unless it was explicitly configured by the server operator. This commit introduces sensible defaults based on the server's configured node size. - -- **Adjust the number of concurrent ledger data jobs**: Processing a large amount of data at once can effectively bottleneck a server's I/O subsystem. This commits helps optimize I/O performance by controlling how many jobs can concurrently process ledger data. - -- **Two small SHAMapSync improvements**: This commit makes minor changes to optimize the way memory is used and control the amount of background I/O performed when attempting to fetch missing `SHAMap` nodes. - -## Version 1.8.2 -Ripple has released version 1.8.2 of rippled, the reference server implementation of the XRP Ledger protocol. This release addresses the full transaction queues and elevated transaction fees issue observed on the XRP ledger, and also provides some optimizations and small fixes to improve the server's performance overall. - -### Summary of Issues -Recently, servers in the XRP Ledger network have had full transaction queues and transactions paying low fees have mostly not been able to be confirmed through the queue. After investigation, it was discovered that a large influx of transactions to the network caused it to raise the transaction costs to be proposed in the next ledger block, and defer transactions paying lower costs to later ledgers. The first part worked as designed, but deferred transactions were not being confirmed as the ledger had capacity to process them. - -The root cause was that there were very many low-cost transactions that different servers in the network received in a different order due to incidental differences in timing or network topology, which caused validators to propose different sets of low-cost transactions from the queue. Since none of these transactions had support from a majority of validators, they were removed from the proposed transaction set. Normally, any transactions removed from a proposed transaction set are supposed to be retried in the next ledger, but servers attempted to put these deferred transactions into their transaction queues first, which had filled up. As a result, the deferred transactions were discarded, and the network was only able to confirm transactions that paid high costs. - -### Bug Fixes - -- **Address elevated transaction fees**: This change addresses the full queue problems in two ways. First, it puts deferred transactions directly into the open ledger, rather than transaction queue. This reverts a subset of the changes from [ximinez@62127d7](https://github.com/ximinez/rippled/commit/62127d725d801641bfaa61dee7d88c95e48820c5). A transaction that is in the open ledger but doesn't get validated should stay in the open ledger so that it can be proposed again right away. Second, it changes the order in which transactions are pulled from the transaction queue to increase the overlap in servers' initial transaction consensus proposals. Like the old rules, transactions paying higher fee levels are selected first. Unlike the old rules, transactions paying the same fee level are ordered by transaction ID / hash ascending. (Previously, transactions paying the same fee level were unsorted, resulting in each server having a different order.) - -- **Add ignore_default option to account_lines API**: This flag, if present, suppresses the output of incoming trust lines in the default state. This is primarily motivated by observing that users often have many unwanted incoming trust lines in a default state, which are not useful in the vast majority of cases. Being able to suppress those when doing `account_lines` saves bandwidth and resources. ([#3980](https://github.com/ripple/rippled/pull/3980)) - -- **Make I/O and prefetch worker threads configurable**: This commit adds the ability to specify **io_workers** and **prefetch_workers** in the config file which can be used to specify the number of threads for processing raw inbound and outbound IO and configure the number of threads for performing node store prefetching. ([#3994](https://github.com/ripple/rippled/pull/3994)) - -- **Enforce account RPC limits by objects traversed**: This changes the way the account_objects API method counts and limits the number of objects it returns. Instead of limiting results by the number of objects found, it counts by the number of objects traversed. Additionally, the default and maximum limits for non-admin connections have been decreased. This reduces the amount of work that one API call can do so that public API servers can share load more effectively. ([#4032](https://github.com/ripple/rippled/pull/4032)) - -- **Fix a crash on shutdown**: The NuDB backend class could throw an error in its destructor, resulting in a crash while the server was shutting down gracefully. This crash was harmless but resulted in false alarms and noise when tracking down other possible crashes. ([#4017](https://github.com/ripple/rippled/pull/4017)) - -- **Improve reporting of job queue in admin server_info**: The server_info command, when run with admin permissions, provides information about jobs in the server's job queue. This commit provides more descriptive names and more granular categories for many jobs that were previously all identified as "clientCommand". ([#4031](https://github.com/ripple/rippled/pull/4031)) - -- **Improve full & compressed inner node deserialization**: Remove a redundant copy operation from low-level SHAMap deserialization. ([#4004](https://github.com/ripple/rippled/pull/4004)) - -- **Reporting mode: only forward to P2P nodes that are synced**: Previously, reporting mode servers forwarded to any of their configured P2P nodes at random. This commit improves the selection so that it only chooses from P2P nodes that are fully synced with the network. ([#4028](https://github.com/ripple/rippled/pull/4028)) - -- **Improve handling of HTTP X-Forwarded-For and Forwarded headers**: Fixes the way the server handles IPv6 addresses in these HTTP headers. ([#4009](https://github.com/ripple/rippled/pull/4009), [#4030](https://github.com/ripple/rippled/pull/4030)) - -- **Other minor improvements to logging and Reporting Mode.** - - -## Version 1.8.0 -Ripple has released version 1.8.0 of rippled, the reference server implementation of the XRP Ledger protocol. This release brings several features and improvements. - -### New and Improved Features - -- **Improve History Sharding**: Shards of ledger history are now assembled in a deterministic way so that any server can make a binary-identical shard for a given range of ledgers. This makes it possible to retrieve a shard from multiple sources in parallel, then verify its integrity by comparing checksums with peers' checksums for the same shard. Additionally, there's a new admin RPC command to import ledger history from the shard store, and the crawl_shards command has been expanded with more info. ([#2688](https://github.com/ripple/rippled/issues/2688), [#3726](https://github.com/ripple/rippled/pull/3726), [#3875](https://github.com/ripple/rippled/pull/3875)) -- **New CheckCashMakesTrustLine Amendment**: If enabled, this amendment will change the CheckCash transaction type so that cashing a check for an issued token automatically creates a trust line to hold the token, similar to how purchasing a token in the decentralized exchange creates a trust line to hold the token. This change provides a way for issuers to send tokens to a user before that user has set up a trust line, but without forcing anyone to hold tokens they don't want. ([#3823](https://github.com/ripple/rippled/pull/3823)) -- **Automatically determine the node size**: The server now selects an appropriate `[node_size]` configuration value by default if it is not explicitly specified. This parameter tunes various settings to the specs of the hardware that the server is running on, especially the amount of RAM and the number of CPU threads available in the system. Previously the server always chose the smallest value by default. -- **Improve transaction relaying logic**: Previously, the server relayed every transaction to all its peers (except the one that it received the transaction from). To reduce redundant messages, the server now relays transactions to a subset of peers using a randomized algorithm. Peers can determine whether there are transactions they have not seen and can request them from a peer that has them. It is expected that this feature will further reduce the bandwidth needed to operate a server. -- **Improve the Byzantine validator detector**: This expands the detection capabilities of the Byzantine validation detector. Previously, the server only monitored validators on its own UNL. Now, the server monitors for Byzantine behavior in all validations it sees. -- **Experimental tx stream with history for sidechains**: Adds an experimental subscription stream for sidechain federators to track messages on the main chain in canonical order. This stream is expected to change or be replaced in future versions as work on sidechains matures. -- **Support Debian 11 Bullseye**: This is the first release that is compatible with Debian Linux version 11.x, "Bullseye." The .deb packages now use absolute paths only, for compatibility with Bullseye's stricter package requirements. ([#3909](https://github.com/ripple/rippled/pull/3909)) -- **Improve Cache Performance**: The server uses a new storage structure for several in-memory caches for greatly improved overall performance. The process of purging old data from these caches, called "sweeping", was time-consuming and blocked other important activities necessary for maintaining ledger state and participating in consensus. The new structure divides the caches into smaller partitions that can be swept in parallel. -- **Amendment default votes:** Introduces variable default votes per amendment. Previously the server always voted "yes" on any new amendment unless an admin explicitly configured a voting preference for that amendment. Now the server's default vote can be "yes" or "no" in the source code. This should allow a safer, more gradual roll-out of new amendments, as new releases can be configured to understand a new amendment but not vote for it by default. ([#3877](https://github.com/ripple/rippled/pull/3877)) -- **More fields in the `validations` stream:** The `validations` subscription stream in the API now reports additional fields that were added to validation messages by the HardenedValidations amendment. These fields make it easier to detect misconfigurations such as multiple servers sharing a validation key pair. ([#3865](https://github.com/ripple/rippled/pull/3865)) -- **Reporting mode supports `validations` and `manifests` streams:** In the API it is now possible to connect to these streams when connected to a servers running in reporting. Previously, attempting to subscribe to these streams on a reporting server failed with the error `reportingUnsupported`. ([#3905](https://github.com/ripple/rippled/pull/3905)) - -### Bug Fixes - -- **Clarify the safety of NetClock::time_point arithmetic**: * NetClock::rep is uint32_t and can be error-prone when used with subtraction. * Fixes [#3656](https://github.com/ripple/rippled/pull/3656) -- **Fix out-of-bounds reserve, and some minor optimizations** -- **Fix nested locks in ValidatorSite** -- **Fix clang warnings about copies vs references** -- **Fix reporting mode build issue** -- **Fix potential deadlock in Validator sites** -- **Use libsecp256k1 instead of OpenSSL for key derivation**: The deterministic key derivation code was still using calls to OpenSSL. This replaces the OpenSSL-based routines with new libsecp256k1-based implementations -- **Improve NodeStore to ShardStore imports**: This runs the import process in a background thread while preventing online_delete from removing ledgers pending import -- **Simplify SHAMapItem construction**: The existing class offered several constructors which were mostly unnecessary. This eliminates all existing constructors and introduces a single new one, taking a `Slice`. The internal buffer is switched from `std::vector` to `Buffer` to save a minimum of 8 bytes (plus the buffer slack that is inherent in `std::vector`) per SHAMapItem instance. -- **Redesign stoppable objects**: Stoppable is no longer an abstract base class, but a pattern, modeled after the well-understood `std::thread`. The immediate benefits are less code, less synchronization, less runtime work, and (subjectively) more readable code. The end goal is to adhere to RAII in our object design, and this is one necessary step on that path. - -## Version 1.7.3 - -This is the 1.7.3 release of `rippled`, the reference implementation of the XRP Ledger protocol. This release addresses an OOB memory read identified by Guido Vranken, as well as an unrelated issue identified by the Ripple C++ team that could result in incorrect use of SLEs. Additionally, this version also introduces the `NegativeUNL` amendment, which corresponds to the feature which was introduced with the 1.6.0 release. - -## Action Required - -If you operate an XRP Ledger server, then you should upgrade to version 1.7.3 at your earliest convenience to mitigate the issues addressed in this hotfix. If a sufficient majority of servers on the network upgrade, the `NegativeUNL` amendment may gain a majority, at which point a two week activation countdown will begin. If the `NegativeUNL` amendment activates, servers running versions of `rippled` prior to 1.7.3 will become [amendment blocked](https://xrpl.org/amendments.html#amendment-blocked). - -### Bug Fixes - -- **Improve SLE usage in check cashing**: Fixes a situation which could result in the incorrect use of SLEs. -- **Address OOB in base58 decoder**: Corrects a technical flaw that could allow an out-of-bounds memory read in the Base58 decoder. -- **Add `NegativeUNL` as a supported amendment**: Introduces an amendment for the Negative UNL feature introduced in `rippled` 1.6.0. - -## Version 1.7.2 - -This the 1.7.2 release of rippled, the reference server implementation of the XRP Ledger protocol. This release protects against the security issue [CVE-2021-3499](https://www.openssl.org/news/secadv/20210325.txt) affecting OpenSSL, adds an amendment to fix an issue with small offers not being properly removed from order books in some cases, and includes various other minor fixes. -Version 1.7.2 supersedes version 1.7.1 and adds fixes for more issues that were discovered during the release cycle. - -## Action Required - -This release introduces a new amendment to the XRP Ledger protocol: `fixRmSmallIncreasedQOffers`. This amendments is now open for voting according to the XRP Ledger's amendment process, which enables protocol changes following two weeks of >80% support from trusted validators. -If you operate an XRP Ledger server, then you should upgrade to version 1.7.2 within two weeks, to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. -If you operate an XRP Ledger validator, please learn more about this amendment so you can make informed decisions about how your validator votes. If you take no action, your validator begins voting in favor of any new amendments as soon as it has been upgraded. - -### Bug Fixes - -- **fixRmSmallIncreasedQOffers Amendment:** This amendment fixes an issue where certain small offers can be left at the tip of an order book without being consumed or removed when appropriate and causes some payments and Offers to fail when they should have succeeded [(#3827)](https://github.com/ripple/rippled/pull/3827). -- **Adjust OpenSSL defaults and mitigate CVE-2021-3499:** Prior to this fix, servers compiled against a vulnerable version of OpenSSL could have a crash triggered by a malicious network connection. This fix disables renegotiation support in OpenSSL so that the rippled server is not vulnerable to this bug regardless of the OpenSSL version used to compile the server. This also removes support for deprecated TLS versions 1.0 and 1.1 and ciphers that are not part of TLS 1.2 [(#79e69da)](https://github.com/ripple/rippled/pull/3843/commits/79e69da3647019840dca49622621c3d88bc3883f). -- **Support HTTP health check in reporting mode:** Enables the Health Check special method when running the server in the new Reporting Mode introduced in 1.7.0 [(9c8cadd)](https://github.com/ripple/rippled/pull/3843/commits/9c8caddc5a197bdd642556f8beb14f06d53cdfd3). -- **Maintain compatibility for forwarded RPC responses:** Fixes a case in API responses from servers in Reporting Mode, where requests that were forwarded to a P2P-mode server would have the result field nested inside another result field [(8579eb0)](https://github.com/ripple/rippled/pull/3843/commits/8579eb0c191005022dcb20641444ab471e277f67). -- **Add load_factor in reporting mode:** Adds a load_factor value to the server info method response when running the server in Reporting Mode so that the response is compatible with the format returned by servers in P2P mode (the default) [(430802c)](https://github.com/ripple/rippled/pull/3843/commits/430802c1cf6d4179f2249a30bfab9eff8e1fa748). -- **Properly encode metadata from tx RPC command:** Fixes a problem where transaction metadata in the tx API method response would be in JSON format even when binary was requested [(7311629)](https://github.com/ripple/rippled/pull/3843/commits/73116297aa94c4acbfc74c2593d1aa2323b4cc52). -- **Updates to Windows builds:** When building on Windows, use vcpkg 2021 by default and add compatibility with MSVC 2019 [(36fe196)](https://github.com/ripple/rippled/pull/3843/commits/36fe1966c3cd37f668693b5d9910fab59c3f8b1f), [(30fd458)](https://github.com/ripple/rippled/pull/3843/commits/30fd45890b1d3d5f372a2091d1397b1e8e29d2ca). - -## Version 1.7.0 - -Ripple has released version 1.7.0 of `rippled`, the reference server implementation of the XRP Ledger protocol. -This release [significantly improves memory usage](https://blog.ripplex.io/how-ripples-c-team-cut-rippleds-memory-footprint-down-to-size/), introduces a protocol amendment to allow out-of-order transaction execution with Tickets, and brings several other features and improvements. - -## Upgrading (SPECIAL ACTION REQUIRED) -If you use the precompiled binaries of rippled that Ripple publishes for supported platforms, please note that Ripple has renewed the GPG key used to sign these packages. -If you are upgrading from a previous install, you must download and trust the renewed key. Automatic upgrades will not work until you have re-trusted the key. -### Red Hat Enterprise Linux / CentOS - -Perform a [manual upgrade](https://xrpl.org/update-rippled-manually-on-centos-rhel.html). When prompted, confirm that the key's fingerprint matches the following example, then press `y` to accept the updated key: - -``` -$ sudo yum install rippled -Loaded plugins: fastestmirror -Loading mirror speeds from cached hostfile -* base: mirror.web-ster.com -* epel: mirrors.syringanetworks.net -* extras: ftp.osuosl.org -* updates: mirrors.vcea.wsu.edu -ripple-nightly/signature | 650 B 00:00:00 -Retrieving key from https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key -Importing GPG key 0xCCAFD9A2: -Userid : "TechOps Team at Ripple " -Fingerprint: c001 0ec2 05b3 5a33 10dc 90de 395f 97ff ccaf d9a2 -From : https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key -Is this ok [y/N]: y -``` - -### Ubuntu / Debian - -Download and trust the updated public key, then perform a [manual upgrade](https://xrpl.org/update-rippled-manually-on-ubuntu.html) as follows: - -``` -wget -q -O - "https://repos.ripple.com/repos/api/gpg/key/public" | \ - sudo apt-key add - -sudo apt -y update -sudo apt -y install rippled -``` - -### New and Improved Features - -- **Rework deferred node logic and async fetch behavior:** This change significantly improves ledger sync and fetch times while reducing memory consumption. (https://blog.ripplex.io/how-ripples-c-team-cut-rippleds-memory-footprint-down-to-size/) -- **New Ticket feature:** Tickets are a mechanism to prepare and send certain transactions outside of the normal sequence order. This version reworks and completes the implementation for Tickets after more than 6 years of development. This feature is now open for voting as the newly-introduced `TicketBatch` amendment, which replaces the previously-proposed `Tickets` amendment. The specification for this change can be found at: [xrp-community/standards-drafts#16](https://github.com/xrp-community/standards-drafts/issues/16) -- **Add Reporting Mode:** The server can be compiled to operate in a new mode that serves API requests for validated ledger data without connecting directly to the peer-to-peer network. (The server needs a gRPC connection to another server that is on the peer-to-peer network.) Reporting Mode servers can share access to ledger data via Apache Cassandra and PostgreSQL to more efficiently serve API requests while peer-to-peer servers specialize in broadcasting and processing transactions. -- **Optimize relaying of validation and proposal messages:** Servers typically receive multiple copies of any given message from directly connected peers; in particular, consensus proposal and validation messages are often relayed with extremely high redundancy. For servers with several peers, this can cause redundant work. This commit introduces experimental code that attempts to optimize the relaying of proposals and validations by allowing servers to instruct their peers to "squelch" delivery of selected proposals and validations. This change is considered experimental at this time and is disabled by default because the functioning of the consensus network depends on messages propagating with high reliability through the constantly-changing peer-to-peer network. Server operators who wish to test the optimized code can enable it in their server config file. -- **Report server domain to other servers:** Server operators now have the option to configure a domain name to be associated with their servers. The value is communicated to other servers and is also reported via the `server_info` API. The value is meant for third-party applications and tools to group servers together. For example, a tool that visualizes the network's topology can show how many servers are operated by different stakeholders. An operator can claim any domain, so tools should use the [xrp-ledger.toml file](https://xrpl.org/xrp-ledger-toml.html) to confirm that the domain also claims ownership of the servers. -- **Improve handling of peers that aren't synced:** When evaluating the fitness and usefulness of an outbound peer, the code would incorrectly calculate the amount of time that the peer spent in a non-useful state. This release fixes the calculation and makes the timeout values configurable by server operators. Two new options are introduced in the 'overlay' stanza of the config file. -- **Persist API-configured voting settings:** Previously, the amendments that a server would vote in support of or against could be configured both via the configuration file and via the ["feature" API method](https://xrpl.org/feature.html). Changes made in the configuration file were only loaded at server startup; changes made via the command line take effect immediately but were not persisted across restarts. Starting with this release, changes made via the API are saved to the wallet.db database file so that they persist even if the server is restarted. -Amendment voting in the config file is deprecated. The first time the server starts with v1.7.0 or higher, it reads any amendment voting settings in the config file and saves the settings to the database; on later restarts the server prints a warning message and ignores the [amendments] and [veto_amendments] stanzas of the config file. -Going forward, use the [feature method](https://xrpl.org/feature.html) to view and configure amendment votes. If you want to use the config file to configure amendment votes, add a line to the [rpc_startup] stanza such as the following: -[rpc_startup] -{ "command": "feature", "feature": "FlowSortStrands", "vetoed": true } -- **Support UNLs with future effective dates:** Updates the format for the recommended validator list file format, allowing publishers to pre-publish the next recommended UNL while the current one is still valid. The server is still backwards compatible with the previous format, but the new format removes some uncertainty during the transition from one list to the next. Also, starting with this release, the server locks down and reports an error if it has no valid validator list. You can clear the error by loading a validator list from a file or by configuring a different UNL and restarting; the error also goes away on its own if the server is able to obtain a trusted validator list from the network (for example, after an network outage resolves itself). -- **Improve manifest relaying:** Servers now propagate change messages for validators' ephemeral public keys ("manifests") on a best-effort basis, to make manifests more available throughout the peer-to-peer network. Previously, the server would only relay manifests from validators it trusts locally, which made it difficult to detect and track validators that are not broadly trusted. -- **Implement ledger forward replay feature:** The server can now sync up to the network by "playing forward" transactions from a previously saved ledger until it catches up to the network. Compared with the default behavior of fetching the latest state and working backwards, forward replay can save time and bandwidth by reconstructing previous ledgers' state data rather than downloading the pre-calculated results from the network. As an added bonus, forward replay confirms that the rest of the network followed the same transaction processing rules as the local server when processing the intervening ledgers. This feature is considered experimental this time and can be enabled with an option in the config file. -- **Make the transaction job queue limit adjustable:** The server uses a job queue to manage tasks, with limits on how many jobs of a particular type can be queued. The previously hard-coded limit associated with transactions is now configurable. Server operators can increase the number of transactions their server is able to queue, which may be useful if your server has a large memory capacity or you expect an influx of transactions. (https://github.com/ripple/rippled/issues/3556) -- **Add public_key to the Validator List method response:** The [Validator List method](https://xrpl.org/validator-list.html) can be used to request a recommended validator list from a rippled instance. The response now includes the public key of the requested list. (https://github.com/ripple/rippled/issues/3392) -- **Server operators can now configure maximum inbound and outbound peers separately:** The new `peers_in_max` and `peers_out_max` config options allow server operators to independently control the maximum number of inbound and outbound peers the server allows. [70c4ecc] -- **Improvements to shard downloading:** Previously the download_shard command could only load shards over HTTPS. Compressed shards can now also be downloaded over plain HTTP. The server fully checks the data for integrity and consistency, so the encryption is not strictly necessary. When initiating multiple shard downloads, the server now returns an error if there is not enough space to store all the shards currently being downloaded. -- **The manifest command is now public:** The manifest API method returns public information about a given validator. The required permissions have been changed so it is now part of the public API. - -### Bug Fixes - -- **Implement sticky DNS resolution for validator list retrieval:** When attempting to load a validator list from a configured site, attempt to reuse the last IP that was successfully used if that IP is still present in the DNS response. (https://github.com/ripple/rippled/issues/3494). -- **Improve handling of RPC ledger_index argument:** You can now provide the `ledger_index` as a numeric string. This allows you to copy and use the numeric string `ledger_index` value returned by certain RPC commands. Previously you could only send native JSON numbers or shortcut strings such as "validated" in the `ledger_index` field. (https://github.com/ripple/rippled/issues/3533) -- **Fix improper promotion of bool on return** [6968da1] -- **Fix ledger sequence on copynode** [ef53197] -- **Fix parsing of node public keys in `manifest` CLI:** The previous code attempts to validate the provided node public key using a function that assumes that the encoded public key is for an account. This causes the parsing to fail. This commit fixes #3317 (https://github.com/ripple/rippled/issues/3317) by letting the caller specify the type of the public key being checked. -- **Fix idle peer timer:** Fixes a bug where a function to remove idle peers was called every second instead of every 4 seconds. #3754 (https://github.com/ripple/rippled/issues/3754) -- **Add database counters:** Fix bug where DatabaseRotateImp::getBackend and ::sync utilized the writable backend without a lock. ::getBackend was replaced with ::getCounters. -- **Improve online_delete configuration and DB tuning** [6e9051e] -- **Improve handling of burst writes in NuDB database** ( https://github.com/ripple/rippled/pull/3662 ) -- **Fix excessive logging after disabling history shards.** Previously if you configured the server with a shard store, then disabled it, the server output excessive warning messages about the shard limit being exceeded. -- **Fixed some issues with negotiating link compression.** ( https://github.com/ripple/rippled/pull/3705 ) -- **Fixed a potential thread deadlock with history sharding.** ( https://github.com/ripple/rippled/pull/3683 ) -- **Various fixes to typos and comments, refactoring, and build system improvements** - -## Version 1.6.0 - -This release introduces several new features including changes to the XRP Ledger's consensus mechanism to make it even more robust in -adverse conditions, as well as numerous bug fixes and optimizations. - -### New and Improved Features - -- Initial implementation of Negative UNL functionality: This change can improve the liveness of the network during periods of network instability, by allowing servers to track which validators are temporarily offline and to adjust quorum calculations to match. This change requires an amendment, but the amendment is not in the **1.6.0** release. Ripple expects to run extensive public testing for Negative UNL functionality on the Devnet in the coming weeks. If public testing satisfies all requirements across security, reliability, stability, and performance, then the amendment could be included in a version 2.0 release. [[#3380](https://github.com/ripple/rippled/pull/3380)] -- Validation Hardening: This change allows servers to detect accidental misconfiguration of validators, as well as potentially Byzantine behavior by malicious validators. Servers can now log a message to notify operators if they detect a single validator issuing validations for multiple, incompatible ledger versions, or validations from multiple servers sharing a key. As part of this update, validators report the version of `rippled` they are using, as well as the hash of the last ledger they consider to be fully validated, in validation messages. [[#3291](https://github.com/ripple/rippled/pull/3291)] ![Amendment: Required](https://img.shields.io/badge/Amendment-Required-red) -- Software Upgrade Monitoring & Notification: After the `HardenedValidations` amendment is enabled and the validators begin reporting the versions of `rippled` they are running, a server can check how many of the validators on its UNL run a newer version of the software than itself. If more than 60% of a server's validators are running a newer version, the server writes a message to notify the operator to consider upgrading their software. [[#3447](https://github.com/ripple/rippled/pull/3447)] -- Link Compression: Beginning with **1.6.0**, server operators can enable support for compressing peer-to-peer messages. This can save bandwidth at a cost of higher CPU usage. This support is disabled by default and should prove useful for servers with a large number of peers. [[#3287](https://github.com/ripple/rippled/pull/3287)] -- Unconditionalize Amendments that were enabled in 2017: This change removes legacy code which the network has not used since 2017. This change limits the ability to [replay](https://github.com/xrp-community/standards-drafts/issues/14) ledgers that rely on the pre-2017 behavior. [[#3292](https://github.com/ripple/rippled/pull/3292)] -- New Health Check Method: Perform a simple HTTP request to get a summary of the health of the server: Healthy, Warning, or Critical. [[#3365](https://github.com/ripple/rippled/pull/3365)] -- Start work on API version 2. Version 2 of the API will be part of a future release. The first breaking change will be to consolidate several closely related error messages that can occur when the server is not synced into a single "notSynced" error message. [[#3269](https://github.com/ripple/rippled/pull/3269)] -- Improved shard concurrency: Improvements to the shard engine have helped reduce the lock scope on all public functions, increasing the concurrency of the code. [[#3251](https://github.com/ripple/rippled/pull/3251)] -- Default Port: In the config file, the `[ips_fixed]` and `[ips]` stanzas now use the [IANA-assigned port](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=2459) for the XRP Ledger protocol (2459) when no port is specified. The `connect` API method also uses the same port by default. [[#2861](https://github.com/ripple/rippled/pull/2861)]. -- Improve proposal and validation relaying. The peer-to-peer protocol always relays trusted proposals and validations (as part of the [consensus process](https://xrpl.org/consensus.html)), but only relays _untrusted_ proposals and validations in certain circumstances. This update adds configuration options so server operators can fine-tune how their server handles untrusted proposals and validations, and changes the default behavior to prioritize untrusted validations higher than untrusted proposals. [[#3391](https://github.com/ripple/rippled/pull/3391)] -- Various Build and CI Improvements including updates to RocksDB 6.7.3 [[#3356](https://github.com/ripple/rippled/pull/3356)], NuDB 2.0.3 [[#3437](https://github.com/ripple/rippled/pull/3437)], adjusting CMake settings so that rippled can be built as a submodule [[#3449](https://github.com/ripple/rippled/pull/3449)], and adding Travis CI settings for Ubuntu Bionic Beaver [[#3319](https://github.com/ripple/rippled/pull/3319)]. -- Better documentation in the config file for online deletion and database tuning. [[#3429](https://github.com/ripple/rippled/pull/3429)] - - -### Bug Fixes - -- Fix the 14 day timer to enable amendment to start at the correct quorum size [[#3396](https://github.com/ripple/rippled/pull/3396)] -- Improve online delete backend lock which addresses a possibility in the online delete process where one or more backend shared pointer references may become invalid during rotation. [[#3342](https://github.com/ripple/rippled/pull/3342)] -- Address an issue that can occur during the loading of validator tokens, where a deliberately malformed token could cause the server to crash during startup. [[#3326](https://github.com/ripple/rippled/pull/3326)] -- Add delivered amount to GetAccountTransactionHistory. The delivered_amount field was not being populated when calling GetAccountTransactionHistory. In contrast, the delivered_amount field was being populated when calling GetTransaction. This change populates delivered_amount in the response to GetAccountTransactionHistory, and adds a unit test to make sure the results delivered by GetTransaction and GetAccountTransactionHistory match each other. [[#3370](https://github.com/ripple/rippled/pull/3370)] -- Fix build issues for GCC 10 [[#3393](https://github.com/ripple/rippled/pull/3393)] -- Fix historical ledger acquisition - this fixes an issue where historical ledgers were acquired only since the last online deletion interval instead of the configured value to allow deletion.[[#3369](https://github.com/ripple/rippled/pull/3369)] -- Fix build issue with Docker [#3416](https://github.com/ripple/rippled/pull/3416)] -- Add Shard family. The App Family utilizes a single shared Tree Node and Full Below cache for all history shards. This can create a problem when acquiring a shard that shares an account state node that was recently cached from another shard operation. The new Shard Family class solves this issue by managing separate Tree Node and Full Below caches for each shard. [#3448](https://github.com/ripple/rippled/pull/3448)] -- Amendment table clean up which fixes a calculation issue with majority. [#3428](https://github.com/ripple/rippled/pull/3428)] -- Add the `ledger_cleaner` command to rippled command line help [[#3305](https://github.com/ripple/rippled/pull/3305)] -- Various typo and comments fixes. - - -## Version 1.5.0 - -The `rippled` 1.5.0 release introduces several improvements and new features, including support for gRPC API, API versioning, UNL propagation via the peer network, new RPC methods `validator_info` and `manifest`, augmented `submit` method, improved `tx` method response, improved command line parsing, improved handshake protocol, improved package building and various other minor bug fixes and improvements. - -This release also introduces two new amendments: `fixQualityUpperBound` and `RequireFullyCanonicalSig`. - -Several improvements to the sharding system are currently being evaluated for inclusion into the upcoming 1.6 release of `rippled`. These changes are incompatible with shards generated by previous versions of the code. -Additionally, an issue with the existing sharding engine can result in a server running versions 1.4 or 1.5 of the software to experience a deadlock and automatically restart when running with the sharding feature enabled. -At this time, the developers recommend running with sharding disabled, pending the improvements scheduled to be introduced with 1.6. For more information on how to disable sharding, please visit https://xrpl.org/configure-history-sharding.html - - -**New and Updated Features** -- The `RequireFullyCanonicalSig` amendment which changes the signature requirements for the XRP Ledger protocol so that non-fully-canonical signatures are no longer valid. This protects against transaction malleability on all transactions, instead of just transactions with the tfFullyCanonicalSig flag enabled. Without this amendment, a transaction is malleable if it uses a secp256k1 signature and does not have tfFullyCanonicalSig enabled. Most signing utilities enable tfFullyCanonicalSig by default, but there are exceptions. With this amendment, no single-signed transactions are malleable. (Multi-signed transactions may still be malleable if signers provide more signatures than are necessary.) All transactions must use the fully canonical form of the signature, regardless of the tfFullyCanonicalSig flag. Signing utilities that do not create fully canonical signatures are not supported. All of Ripple's signing utilities have been providing fully-canonical signatures exclusively since at least 2014. For more information. [`ec137044a`](https://github.com/ripple/rippled/commit/ec137044a014530263cd3309d81643a5a3c1fdab) -- Native [gRPC API](https://grpc.io/) support. Currently, this API provides a subset of the full `rippled` [API](https://xrpl.org/rippled-api.html). You can enable the gRPC API on your server with a new configuration stanza. [`7d867b806`](https://github.com/ripple/rippled/commit/7d867b806d70fc41fb45e3e61b719397033b272c) -- API Versioning which allows for future breaking change of RPC methods to co-exist with existing versions. [`2aa11fa41`](https://github.com/ripple/rippled/commit/2aa11fa41d4a7849ae6a5d7a11df6f367191e3ef) -- Nodes now receive and broadcast UNLs over the peer network under various conditions. [`2c71802e3`](https://github.com/ripple/rippled/commit/2c71802e389a59118024ea0152123144c084b31c) -- Augmented `submit` method to include additional details on the status of the command. [`79e9085dd`](https://github.com/ripple/rippled/commit/79e9085dd1eb72864afe841225b78ec96e72b5ca) -- Improved `tx` method response with additional details on ledgers searched. [`47501b7f9`](https://github.com/ripple/rippled/commit/47501b7f99d4103d9ad405e399169fc251161548) -- New `validator_info` method which returns information pertaining to the current validator's keys, manifest sequence, and domain. [`3578acaf0`](https://github.com/ripple/rippled/commit/3578acaf0b5f2d27ddc33f5b4cc81d21be1903ae) -- New `manifest` method which looks up manifest information for the specified key (either master or ephemeral). [`3578acaf0`](https://github.com/ripple/rippled/commit/3578acaf0b5f2d27ddc33f5b4cc81d21be1903ae) -- Introduce handshake protocol for compression negotiation (compression is not implemented at this point) and other minor improvements. [`f6916bfd4`](https://github.com/ripple/rippled/commit/f6916bfd429ce654e017ae9686cb023d9e05408b) -- Remove various old conditionals introduced by amendments. [`(51ed7db00`](https://github.com/ripple/rippled/commit/51ed7db0027ba822739bd9de6f2613f97c1b227b), [`6e4945c56)`](https://github.com/ripple/rippled/commit/6e4945c56b1a1c063b32921d7750607587ec3063) -- Add `getRippledInfo` info gathering script to `rippled` Linux packages. [`acf4b7889`](https://github.com/ripple/rippled/commit/acf4b78892074303cb1fa22b778da5e7e7eddeda) - -**Bug Fixes and Improvements** -- The `fixQualityUpperBound` amendment which fixes a bug in unused code for estimating the ratio of input to output of individual steps in cross-currency payments. [`9d3626fec`](https://github.com/ripple/rippled/commit/9d3626fec5b610100f401dc0d25b9ec8e4a9a362) -- `tx` method now properly fetches all historical tx if they are incorporated into a validated ledger under rules that applied at the time. [`11cf27e00`](https://github.com/ripple/rippled/commit/11cf27e00698dbfc099b23463927d1dac829ed19) -- Fix to how `fail_hard` flag is handled with the `submit` method - transactions that are submitted with the `fail_hard` flag that result in any TER code besides tesSUCCESS is neither queued nor held. [`cd9732b47`](https://github.com/ripple/rippled/commit/cd9732b47a9d4e95bcb74e048d2c76fa118b80fb) -- Remove unused `Beast` code. [`172ead822`](https://github.com/ripple/rippled/commit/172ead822159a3c1f9b73217da4316df48851ab6) -- Lag ratchet code fix to use proper ephemeral public keys instead of the long-term master public keys.[`6529d3e6f`](https://github.com/ripple/rippled/commit/6529d3e6f7333fc5226e5aa9ae65f834cb93dfe5) - - -## Version 1.4.0 - -The `rippled` 1.4.0 release introduces several improvements and new features, including support for deleting accounts, improved peer slot management, improved CI integration and package building and support for [C++17](https://en.wikipedia.org/wiki/C%2B%2B17) and [Boost 1.71](https://www.boost.org/users/history/version_1_71_0.html). Finally, this release removes the code for the `SHAMapV2` amendment which failed to gain majority support and has been obsoleted by other improvements. - -**New and Updated Features** -- The `DeletableAccounts` amendment which, if enabled, will make it possible for users to delete unused or unneeded accounts, recovering the account's reserve. -- Support for improved management of peer slots and the ability to add and removed reserved connections without requiring a restart of the server. -- Tracking and reporting of cumulative and instantaneous peer bandwidth usage. -- Preliminary support for post-processing historical shards after downloading to index their contents. -- Reporting the master public key alongside the ephemeral public key in the `validation` stream [subscriptions](https://xrpl.org/subscribe.html). -- Reporting consensus phase changes in the `server` stream [subscription](https://xrpl.org/subscribe.html). - -**Bug Fixes** -- The `fixPayChanRecipientOwnerDir` amendment which corrects a minor technical flaw that would cause a payment channel to not appear in the recipient's owner directory, which made it unnecessarily difficult for users to enumerate all their payment channels. -- The `fixCheckThreading` amendment which corrects a minor technical flaw that caused checks to not be properly threaded against the account of the check's recipient. -- Respect the `ssl_verify` configuration option in the `SSLHTTPDownloader` and `HTTPClient` classes. -- Properly update the `server_state` when a server detects a disagreement between itself and the network. -- Allow Ed25519 keys to be used with the `channel_authorize` command. - -## Version 1.3.1 - -The `rippled` 1.3.1 release improves the built-in deadlock detection code, improves logging during process startup, changes the package build pipeline and improves the build documentation. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** -- Add a LogicError when a deadlock is detected (355a7b04) -- Improve logging during process startup (7c24f7b1) - -## Version 1.3.0 -The `rippled` 1.3.0 release introduces several new features and overall improvements to the codebase, including the `fixMasterKeyAsRegularKey` amendment, code to adjust the timing of the consensus process and support for decentralized validator domain verification. The release also includes miscellaneous improvements including in the transaction censorship detection code, transaction validation code, manifest parsing code, configuration file parsing code, log file rotation code, and in the build, continuous integration, testing and package building pipelines. - -**New and Updated Features** -- The `fixMasterKeyAsRegularKey` amendment which, if enabled, will correct a technical flaw that allowed setting an account's regular key to the account's master key. -- Code that allows validators to adjust the timing of the consensus process in near-real-time to account for connection delays. -- Support for decentralized validator domain verification by adding support for a "domain" field in manifests. - -**Bug Fixes** -- Improve ledger trie ancestry tracking to reduce unnecessary error messages. -- More efficient detection of dry paths in the payment engine. Although not a transaction-breaking change, this should reduce spurious error messages in the log files. - -## Version 1.2.4 - -The `rippled` 1.2.4 release improves the way that shard crawl requests are routed and the robustness of configured validator list retrieval by imposing a 20 second timeout. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Use public keys when routing shard crawl requests -- Enforce a 20s timeout when making validator list requests (RIPD-1737) - -## Version 1.2.3 - -The `rippled` 1.2.3 release corrects a technical flaw which in some circumstances can cause a null pointer dereference that can crash the server. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Fix a technical flaw which in some circumstances can cause a null pointer dereference that can crash the server. - -## Version 1.2.2 - -The `rippled` 1.2.2 release corrects a technical flaw in the fee escalation -engine which could cause some fee metrics to be calculated incorrectly. In some -circumstances this can potentially cause the server to crash. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Fix a technical flaw in the fee escalation engine which could cause some fee metrics to be calculated incorrectly (4c06b3f86) - -## Version 1.2.1 - -The `rippled` 1.2.1 release introduces several fixes including a change in the -information reported via the enhanced crawl functionality introduced in the -1.2.0 release, a fix for a potential race condition when processing a status -change message for a peer, and for a technical flaw that could cause a server -to not properly detect that it had lost all its peers. - -The release also adds the `delivered_amount` field to more responses to simplify -the handling of payment or check cashing transactions. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Fix a race condition during `TMStatusChange` handling (c8249981) -- Properly transition state to disconnected (9d027394) -- Display validator status only in response to admin requests (2d6a518a) -- Add the `delivered_amount` to more RPC commands (f2756914) - - -## Version 1.2.0 - -The `rippled` 1.2.0 release introduces the MultisignReserve Amendment, which -reduces the reserve requirement associated with signer lists. This release also -includes incremental improvements to the code that handles offers. Furthermore, -`rippled` now also has the ability to automatically detect transaction -censorship attempts and issue warnings of increasing severity for transactions -that should have been included in a closed ledger after several rounds of -consensus. - -**New and Updated Features** - -- Reduce the account reserve for a Multisign SignerList (6572fc8) -- Improve transaction error condition handling (4104778) -- Allow servers to automatically detect transaction censorship attempts (945493d) -- Load validator list from file (c1a0244) -- Add RPC command shard crawl (17e0d09) -- Add RPC Call unit tests (eeb9d92) -- Grow the open ledger expected transactions quickly (7295cf9) -- Avoid dispatching multiple fetch pack threads (4dcb3c9) -- Remove unused function in AutoSocket.h (8dd8433) -- Update TxQ developer docs (e14f913) -- Add user defined literals for megabytes and kilobytes (cd1c5a3) -- Make the FeeEscalation Amendment permanent (58f786c) -- Remove undocumented experimental options from RPC sign (a96cb8f) -- Improve RPC error message for fee command (af1697c) -- Improve ledger_entry command’s inconsistent behavior (63e167b) - -**Bug Fixes** - -- Accept redirects from validator list sites (7fe1d4b) -- Implement missing string conversions for JSON (c0e9418) -- Eliminate potential undefined behavior (c71eb45) -- Add safe_cast to sure no overflow in casts between enums and integral types (a7e4541) - -## Version 1.1.2 - -The `rippled` 1.1.2 release introduces a fix for an issue that could have -prevented cluster peers from successfully bypassing connection limits when -connecting to other servers on the same cluster. Additionally, it improves -logic used to determine what the preferred ledger is during suboptimal -network conditions. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Properly bypass connection limits for cluster peers (#2795, #2796) -- Improve preferred ledger calculation (#2784) - -## Version 1.1.1 - -The `rippled` 1.1.1 release adds support for redirections when retrieving -validator lists and changes the way that validators with an expired list -behave. Additionally, informational commands return more useful information -to allow server operators to determine the state of their server - -**New and Updated Features** - -- Enhance status reporting when using the `server_info` and `validators` commands (#2734) -- Accept redirects from validator list sites: (#2715) - -**Bug Fixes** - -- Properly handle expired validator lists when validating (#2734) - - - -## Version 1.1.0 - -The `rippled` 1.1.0 release release includes the `DepositPreAuth` amendment, which combined with the previously released `DepositAuth` amendment, allows users to pre-authorize incoming transactions to accounts, by whitelisting sender addresses. The 1.1.0 release also includes incremental improvements to several previously released features (`fix1515` amendment), deprecates support for the `sign` and `sign_for` commands from the rippled API and improves invariant checking for enhanced security. - -Ripple recommends that all server operators upgrade to XRP Ledger version 1.1.0 by Thursday, 2018-09-27, to ensure service continuity. - -**New and Updated Features** - -- Add `DepositPreAuth` ledger type and transaction (#2513) -- Increase fault tolerance and raise validation quorum to 80%, which fixes issue 2604 (#2613) -- Support ipv6 for peer and RPC comms (#2321) -- Refactor ledger replay logic (#2477) -- Improve Invariant Checking (#2532) -- Expand SQLite potential storage capacity (#2650) -- Replace UptimeTimer with UptimeClock (#2532) -- Don’t read Amount field if it is not present (#2566) -- Remove Transactor:: mFeeDue member variable (#2586) -- Remove conditional check for using Boost.Process (#2586) -- Improve charge handling in NoRippleCheckLimits test (#2629) -- Migrate more code into the chrono type system (#2629) -- Supply ConsensusTimer with milliseconds for finer precision (#2629) -- Refactor / modernize Cmake (#2629) -- Add delimiter when appending to cmake_cxx_flags (#2650) -- Remove using namespace declarations at namespace scope in headers (#2650) - -**Bug Fixes** - -- Deprecate the ‘sign’ and ‘sign_for’ APIs (#2657) -- Use liquidity from strands that consume too many offers, which will be enabled on fix1515 Amendment (#2546) -- Fix a corner case when decoding base64 (#2605) -- Trim space in Endpoint::from_string (#2593) -- Correctly suppress sent messages (#2564) -- Detect when a unit test child process crashes (#2415) -- Handle WebSocket construction exceptions (#2629) -- Improve JSON exception handling (#2605) -- Add missing virtual destructors (#2532) - - -## Version 1.0.0. - -The `rippled` 1.0.0 release includes incremental improvements to several previously released features. - -**New and Updated Features** - -- The **history sharding** functionality has been improved. Instances can now use the shard store to satisfy ledger requests. -- Change permessage-deflate and compress defaults (RIPD-506) -- Update validations on UNL change (RIPD-1566) - -**Bug Fixes** - -- Add `check`, `escrow`, and `pay_chan` to `ledger_entry` (RIPD-1600) -- Clarify Escrow semantics (RIPD-1571) - - -## Version 0.90.1 - -The `rippled` 0.90.1 release includes fixes for issues reported by external security researchers. These issues, when exploited, could cause a rippled instance to restart or, in some circumstances, stop executing. While these issues can result in a denial of service attack, none affect the integrity of the XRP Ledger and no user funds, including XRP, are at risk. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Address issues identified by external review: - - Verify serialized public keys more strictly before using them - (RIPD-1617, RIPD-1619, RIPD-1621) - - Eliminate a potential out-of-bounds memory access in the base58 - encoding/decoding logic (RIPD-1618) - - Avoid invoking undefined behavior in memcpy (RIPD-1616) - - Limit STVar recursion during deserialization (RIPD-1603) -- Use lock when creating a peer shard rangeset - - -## Version 0.90.0 - -The `rippled` 0.90.0 release introduces several features and enhancements that improve the reliability, scalability and security of the XRP Ledger. - -Highlights of this release include: - -- The `DepositAuth` amendment, which lets an account strictly reject any incoming money from transactions sent by other accounts. -- The `Checks` amendment, which allows users to create deferred payments that can be cancelled or cashed by their intended recipients. -- **History Sharding**, which allows `rippled` servers to distribute historical ledger data if they agree to dedicate storage for segments of ledger history. -- New **Preferred Ledger by Branch** semantics which improve the logic that allow a server to decide which ledger it should base future ledgers on when there are multiple candidates. - -**New and Updated Features** - -- Add support for Deposit Authorization account root flag ([#2239](https://github.com/ripple/rippled/issues/2239)) -- Implement history shards ([#2258](https://github.com/ripple/rippled/issues/2258)) -- Preferred ledger by branch ([#2300](https://github.com/ripple/rippled/issues/2300)) -- Redesign Consensus Simulation Framework ([#2209](https://github.com/ripple/rippled/issues/2209)) -- Tune for higher transaction processing ([#2294](https://github.com/ripple/rippled/issues/2294)) -- Optimize queries for `account_tx` to work around SQLite query planner ([#2312](https://github.com/ripple/rippled/issues/2312)) -- Allow `Journal` to be copied/moved ([#2292](https://github.com/ripple/rippled/issues/2292)) -- Cleanly report invalid `[server]` settings ([#2305](https://github.com/ripple/rippled/issues/2305)) -- Improve log scrubbing ([#2358](https://github.com/ripple/rippled/issues/2358)) -- Update `rippled-example.cfg` ([#2307](https://github.com/ripple/rippled/issues/2307)) -- Force json commands to be objects ([#2319](https://github.com/ripple/rippled/issues/2319)) -- Fix cmake clang build for sanitizers ([#2325](https://github.com/ripple/rippled/issues/2325)) -- Allow `account_objects` RPC to filter by “check” ([#2356](https://github.com/ripple/rippled/issues/2356)) -- Limit nesting of json commands ([#2326](https://github.com/ripple/rippled/issues/2326)) -- Unit test that `sign_for` returns a correct hash ([#2333](https://github.com/ripple/rippled/issues/2333)) -- Update Visual Studio build instructions ([#2355](https://github.com/ripple/rippled/issues/2355)) -- Force boost static linking for MacOS builds ([#2334](https://github.com/ripple/rippled/issues/2334)) -- Update MacOS build instructions ([#2342](https://github.com/ripple/rippled/issues/2342)) -- Add dev docs generation to Jenkins ([#2343](https://github.com/ripple/rippled/issues/2343)) -- Poll if process is still alive in Test.py ([#2290](https://github.com/ripple/rippled/issues/2290)) -- Remove unused `beast::currentTimeMillis()` ([#2345](https://github.com/ripple/rippled/issues/2345)) - - -**Bug Fixes** -- Improve error message on mistyped command ([#2283](https://github.com/ripple/rippled/issues/2283)) -- Add missing includes ([#2368](https://github.com/ripple/rippled/issues/2368)) -- Link boost statically only when requested ([#2291](https://github.com/ripple/rippled/issues/2291)) -- Unit test logging fixes ([#2293](https://github.com/ripple/rippled/issues/2293)) -- Fix Jenkins pipeline for branches ([#2289](https://github.com/ripple/rippled/issues/2289)) -- Avoid AppVeyor stack overflow ([#2344](https://github.com/ripple/rippled/issues/2344)) -- Reduce noise in log ([#2352](https://github.com/ripple/rippled/issues/2352)) - - -## Version 0.81.0 - -The `rippled` 0.81.0 release introduces changes that improve the scalability of the XRP Ledger and transitions the recommended validator configuration to a new hosted site, as described in Ripple's [Decentralization Strategy Update](https://ripple.com/dev-blog/decentralization-strategy-update/) post. - -**New and Updated Features** - -- New hosted validator configuration. - - -**Bug Fixes** - -- Optimize queries for account_tx to work around SQLite query planner ([#2312](https://github.com/ripple/rippled/issues/2312)) - - -## Version 0.80.2 - -The `rippled` 0.80.2 release introduces changes that improve the scalability of the XRP Ledger. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Do not dispatch a transaction received from a peer for processing if it has already been dispatched within the past ten seconds. -- Increase the number of transaction handlers that can be in flight in the job queue and decrease the relative cost for peers to share transaction and ledger data. -- Make better use of resources by adjusting the number of threads we initialize, by reverting commit [#68b8ffd](https://github.com/ripple/rippled/commit/68b8ffdb638d07937f841f7217edeb25efdb3b5d). - -## Version 0.80.1 - -The `rippled` 0.80.1 release provides several enhancements in support of published validator lists and corrects several bugs. - -**New and Updated Features** - -- Allow including validator manifests in published list ([#2278](https://github.com/ripple/rippled/issues/2278)) -- Add validator list RPC commands ([#2242](https://github.com/ripple/rippled/issues/2242)) -- Support [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) when querying published list sites and use Windows system root certificates ([#2275](https://github.com/ripple/rippled/issues/2275)) -- Grow TxQ expected size quickly, shrink slowly ([#2235](https://github.com/ripple/rippled/issues/2235)) - -**Bug Fixes** - -- Make consensus quorum unreachable if validator list expires ([#2240](https://github.com/ripple/rippled/issues/2240)) -- Properly use ledger hash to break ties when determing working ledger for consensus ([#2257](https://github.com/ripple/rippled/issues/2257)) -- Explictly use std::deque for missing node handler in SHAMap code ([#2252](https://github.com/ripple/rippled/issues/2252)) -- Verify validator token manifest matches private key ([#2268](https://github.com/ripple/rippled/issues/2268)) - - -## Version 0.80.0 - -The `rippled` 0.80.0 release introduces several enhancements that improve the reliability, scalability and security of the XRP Ledger. - -Highlights of this release include: - -- The `SortedDirectories` amendment, which allows the entries stored within a page to be sorted, and corrects a technical flaw that could, in some edge cases, prevent an empty intermediate page from being deleted. -- Changes to the UNL and quorum rules - + Use a fixed size UNL if the total listed validators are below threshold - + Ensure a quorum of 0 cannot be configured - + Set a quorum to provide Byzantine fault tolerance until a threshold of total validators is exceeded, at which time the quorum is 80% - -**New and Updated Features** - -- Improve directory insertion and deletion ([#2165](https://github.com/ripple/rippled/issues/2165)) -- Move consensus thread safety logic from the generic implementation in Consensus into the RCL adapted version RCLConsensus ([#2106](https://github.com/ripple/rippled/issues/2106)) -- Refactor Validations class into a generic version that can be adapted ([#2084](https://github.com/ripple/rippled/issues/2084)) -- Make minimum quorum Byzantine fault tolerant ([#2093](https://github.com/ripple/rippled/issues/2093)) -- Make amendment blocked state thread-safe and simplify a constructor ([#2207](https://github.com/ripple/rippled/issues/2207)) -- Use ledger hash to break ties ([#2169](https://github.com/ripple/rippled/issues/2169)) -- Refactor RangeSet ([#2113](https://github.com/ripple/rippled/issues/2113)) - -**Bug Fixes** - -- Fix an issue where `setAmendmentBlocked` is only called when processing the `EnableAmendment` transaction for the amendment ([#2137](https://github.com/ripple/rippled/issues/2137)) -- Track escrow in recipient's owner directory ([#2212](https://github.com/ripple/rippled/issues/2212)) - -## Version 0.70.2 - -The `rippled` 0.70.2 release corrects an emergent behavior which causes large numbers of transactions to get -stuck in different nodes' open ledgers without being passed on to validators, resulting in a spike in the open -ledger fee on those nodes. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Recent fee rises and TxQ issues ([#2215](https://github.com/ripple/rippled/issues/2215)) - - -## Version 0.70.1 - -The `rippled` 0.70.1 release corrects a technical flaw in the newly refactored consensus code that could cause a node to get stuck in consensus due to stale votes from a -peer, and allows compiling `rippled` under the 1.1.x releases of OpenSSL. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- Allow compiling against OpenSSL 1.1.0 ([#2151](https://github.com/ripple/rippled/pull/2151)) -- Log invariant check messages at "fatal" level ([2154](https://github.com/ripple/rippled/pull/2154)) -- Fix the consensus code to update all disputed transactions after a node changes a position ([2156](https://github.com/ripple/rippled/pull/2156)) - - -## Version 0.70.0 - -The `rippled` 0.70.0 release introduces several enhancements that improve the reliability, scalability and security of the network. - -Highlights of this release include: - -- The `FlowCross` amendment, which streamlines offer crossing and autobrigding logic by leveraging the new “Flow” payment engine. -- The `EnforceInvariants` amendment, which can safeguard the integrity of the XRP Ledger by introducing code that executes after every transaction and ensures that the execution did not violate key protocol rules. -- `fix1373`, which addresses an issue that would cause payments with certain path specifications to not be properly parsed. - -**New and Updated Features** - -- Implement and test invariant checks for transactions (#2054) -- TxQ: Functionality to dump all queued transactions (#2020) -- Consensus refactor for simulation/cleanup (#2040) -- Payment flow code should support offer crossing (#1884) -- make `Config` init extensible via lambda (#1993) -- Improve Consensus Documentation (#2064) -- Refactor Dependencies & Unit Test Consensus (#1941) -- `feature` RPC test (#1988) -- Add unit Tests for handlers/TxHistory.cpp (#2062) -- Add unit tests for handlers/AccountCurrenciesHandler.cpp (#2085) -- Add unit test for handlers/Peers.cpp (#2060) -- Improve logging for Transaction affects no accounts warning (#2043) -- Increase logging in PeerImpl fail (#2043) -- Allow filtering of ledger objects by type in RPC (#2066) - -**Bug Fixes** - -- Fix displayed warning when generating brain wallets (#2121) -- Cmake build does not append '+DEBUG' to the version info for non-unity builds -- Crossing tiny offers can misbehave on RCL -- `asfRequireAuth` flag not always obeyed (#2092) -- Strand creating is incorrectly accepting invalid paths -- JobQueue occasionally crashes on shutdown (#2025) -- Improve pseudo-transaction handling (#2104) - -## Version 0.60.3 - -The `rippled` 0.60.3 release helps to increase the stability of the network under heavy load. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -Server overlay improvements ([#2110](https://github.com/ripple/rippled/pull/2011)) - -## Version 0.60.2 - -The `rippled` 0.60.2 release further strengthens handling of cases associated with a previously patched exploit, in which NoRipple flags were being bypassed by using offers. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -Prevent the ability to bypass the `NoRipple` flag using offers ([#7cd4d78](https://github.com/ripple/rippled/commit/4ff40d4954dfaa237c8b708c2126cb39566776da)) - -## Version 0.60.1 - -The `rippled` 0.60.1 release corrects a technical flaw that resulted from using 32-bit space identifiers instead of the protocol-defined 16-bit values for Escrow and Payment Channel ledger entries. rippled version 0.60.1 also fixes a problem where the WebSocket timeout timer would not be cancelled when certain errors occurred during subscription streams. Ripple requires upgrading to rippled version 0.60.1 immediately. - -**New and Updated Feature** - -This release has no new features. - -**Bug Fixes** - -Correct calculation of Escrow and Payment Channel indices. -Fix WebSocket timeout timer issues. - -## Version 0.60.0 - -The `rippled` 0.60.0 release introduces several enhancements that improve the reliability and scalability of the Ripple Consensus Ledger (RCL), including features that add ledger interoperability by improving Interledger Protocol compatibility. Ripple recommends that all server operators upgrade to version 0.60.0 by Thursday, 2017-03-30, for service continuity. - -Highlights of this release include: - -- `Escrow` (previously called `SusPay`) which permits users to cryptographically escrow XRP on RCL with an expiration date, and optionally a hashlock crypto-condition. Ripple expects Escrow to be enabled via an Amendment named [`Escrow`](https://ripple.com/build/amendments/#escrow) on Thursday, 2017-03-30. See below for details. -- Dynamic UNL Lite, which allows `rippled` to automatically adjust which validators it trusts based on recommended lists from trusted publishers. - -**New and Updated Features** - -- Add `Escrow` support (#2039) -- Dynamize trusted validator list and quorum (#1842) -- Simplify fee handling during transaction submission (#1992) -- Publish server stream when fee changes (#2016) -- Replace manifest with validator token (#1975) -- Add validator key revocations (#2019) -- Add `SecretKey` comparison operator (#2004) -- Reduce `LEDGER_MIN_CONSENSUS` (#2013) -- Update libsecp256k1 and Beast B30 (#1983) -- Make `Config` extensible via lambda (#1993) -- WebSocket permessage-deflate integration (#1995) -- Do not close socket on a foreign thread (#2014) -- Update build scripts to support latest boost and ubuntu distros (#1997) -- Handle protoc targets in scons ninja build (#2022) -- Specify syntax version for ripple.proto file (#2007) -- Eliminate protocol header dependency (#1962) -- Use gnu gold or clang lld linkers if available (#2031) -- Add tests for `lookupLedger` (#1989) -- Add unit test for `get_counts` RPC method (#2011) -- Add test for `transaction_entry` request (#2017) -- Unit tests of RPC "sign" (#2010) -- Add failure only unit test reporter (#2018) - -**Bug Fixes** - -- Enforce rippling constraints during payments (#2049) -- Fix limiting step re-execute bug (#1936) -- Make "wss" work the same as "wss2" (#2033) -- Config test uses unique directories for each test (#1984) -- Check for malformed public key on payment channel (#2027) -- Send a websocket ping before timing out in server (#2035) - - -## Version 0.50.3 - -The `rippled` 0.50.3 release corrects a reported exploit that would allow a combination of trust lines and order books in a payment path to bypass the blocking effect of the [`NoRipple`](https://ripple.com/build/understanding-the-noripple-flag/) flag. Ripple recommends that all server operators immediately upgrade to version 0.50.3. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -Correct a reported exploit that would allow a combination of trust lines and order books in a payment path to bypass the blocking effect of the “NoRipple” flag. - - -## Version 0.50.2 - -The `rippled` 0.50.2 release adjusts the default TLS cipher list and corrects a flaw that would not allow an SSL handshake to properly complete if the port was configured using the `wss` keyword. Ripple recommends upgrading to 0.50.2 only if server operators are running rippled servers that accept client connections over TLS. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -Adjust the default cipher list and correct a flaw that would not allow an SSL handshake to properly complete if the port was configured using the `wss` keyword (#1985) - - -## Version 0.50.0 - -The `rippled` 0.50.0 release includes TickSize, which allows gateways to set a "tick size" for assets they issue to help promote faster price discovery and deeper liquidity, as well as reduce transaction spam and ledger churn on RCL. Ripple expects TickSize to be enabled via an Amendment called TickSize on Tuesday, 2017-02-21. - -You can [update to the new version](https://ripple.com/build/rippled-setup/#updating-rippled) on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please [compile the new version from source](https://wiki.ripple.com/Rippled_build_instructions). - -**New and Updated Features** - -**Tick Size** - -Currently, offers on RCL can differ by as little as one part in a quadrillion. This means that there is essentially no value to placing an offer early, as an offer placed later at a microscopically better price gets priority over it. The [TickSize](https://ripple.com/build/amendments/#ticksize) Amendment solves this problem by introducing a minimum tick size that a price must move for an offer to be considered to be at a better price. The tick size is controlled by the issuers of the assets involved. - -This change lets issuers quantize the exchange rates of offers to use a specified number of significant digits. Gateways must enable a TickSize on their account for this feature to benefit them. A single AccountSet transaction may set a `TickSize` parameter. Legal values are 0 and 3-15 inclusive. Zero removes the setting. 3-15 allow that many decimal digits of precision in the pricing of offers for assets issued by this account. It will still be possible to place an offer to buy or sell any amount of an asset and the offer will still keep that amount as exactly as it does now. If an offer involves two assets that each have a tick size, the smaller number of significant figures (larger ticks) controls. - -For asset pairs with XRP, the tick size imposed, if any, is the tick size of the issuer of the non-XRP asset. For asset pairs without XRP, the tick size imposed, if any, is the smaller of the two issuer's configured tick sizes. - -The tick size is imposed by rounding the offer quality down to the nearest tick and recomputing the non-critical side of the offer. For a buy, the amount offered is rounded down. For a sell, the amount charged is rounded up. - -The primary expected benefit of the TickSize amendment is the reduction of bots fighting over the tip of the order book, which means: -- Quicker price discovery as outpricing someone by a microscopic amount is made impossible (currently bots can spend hours outbidding each other with no significant price movement) -- A reduction in offer creation and cancellation spam -- Traders can't outbid by a microscopic amount -- More offers left on the books as priority - -We also expect larger tick sizes to benefit market makers in the following ways: -- They increase the delta between the fair market value and the trade price, ultimately reducing spreads -- They prevent market makers from consuming each other's offers due to slight changes in perceived fair market value, which promotes liquidity -- They promote faster price discovery by reducing the back and forths required to move the price by traders who don't want to move the price more than they need to -- They reduce transaction spam by reducing fighting over the tip of the order book and reducing the need to change offers due to slight price changes -- They reduce ledger churn and metadata sizes by reducing the number of indexes each order book must have -- They allow the order book as presented to traders to better reflect the actual book since these presentations are inevitably aggregated into ticks - -**Hardened TLS configuration** - -This release updates the default TLS configuration for rippled. The new release supports only 2048-bit DH parameters and defines a new default set of modern ciphers to use, removing support for ciphers and hash functions that are no longer considered secure. - -Server administrators who wish to have different settings can configure custom global and per-port cipher suites in the configuration file using the `ssl_ciphers` directive. - -**0.50.0 Change Log** - -Remove websocketpp support (#1910) - -Increase OpenSSL requirements & harden default TLS cipher suites (#1913) - -Move test support sources out of ripple directory (#1916) - -Enhance ledger header RPC commands (#1918) - -Add support for tick sizes (#1922) - -Port discrepancy-test.coffee to c++ (#1930) - -Remove redundant call to `clearNeedNetworkLedger` (#1931) - -Port freeze-test.coffee to C++ unit test. (#1934) - -Fix CMake docs target to work if `BOOST_ROOT` is not set (#1937) - -Improve setup for account_tx paging test (#1942) - -Eliminate npm tests (#1943) - -Port uniport js test to cpp (#1944) - -Enable amendments in genesis ledger (#1944) - -Trim ledger data in Discrepancy_test (#1948) - -Add `current_ledger` field to `fee` result (#1949) - -Cleanup unit test support code (#1953) - -Add ledger save / load tests (#1955) - -Remove unused websocket files (#1957) - -Update RPC handler role/usage (#1966) - -**Bug Fixes** - -Validator's manifest not forwarded beyond directly connected peers (#1919) - -**Upcoming Features** - -We expect the previously announced Suspended Payments feature, which introduces new transaction types to the Ripple protocol that will permit users to cryptographically escrow XRP on RCL, to be enabled via the [SusPay](https://ripple.com/build/amendments/#suspay) Amendment on Tuesday, 2017-02-21. - -Also, we expect support for crypto-conditions, which are signature-like structures that can be used with suspended payments to support ILP integration, to be included in the next rippled release scheduled for March. - -Lastly, we do not have an update on the previously announced changes to the hash tree structure that rippled uses to represent a ledger, called [SHAMapV2](https://ripple.com/build/amendments/#shamapv2). At the time of activation, this amendment will require brief scheduled allowable unavailability while the changes to the hash tree structure are computed by the network. We will keep the community updated as we progress towards this date (TBA). - - -## Version 0.40.1 - -The `rippled` 0.40.1 release increases SQLite database limits in all rippled servers. Ripple recommends upgrading to 0.40.1 only if server operators are running rippled servers with full-history of the ledger. There are no new or updated features in the 0.40.1 release. - -You can update to the new version on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please compile the new version from source. - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -Increase SQLite database limits to prevent full-history servers from crashing when restarting. (#1961) - -## Version 0.40.0 - -The `rippled` 0.40.0 release includes Suspended Payments, a new transaction type on the Ripple network that functions similar to an escrow service, which permits users cryptographically escrow XRP on RCL with an expiration date. Ripple expects Suspended Payments to be enabled via an Amendment named [SusPay](https://ripple.com/build/amendments/#suspay) on Tuesday, 2017-01-17. - -You can update to the new version on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please compile the new version from source. - -**New and Updated Features** - -Previously, Ripple announced the introduction of Payment Channels during the release of rippled version 0.33.0, which permit scalable, off-ledger checkpoints of high volume, low value payments flowing in a single direction. This was the first step in a multi-phase effort to make RCL more scalable and to support Interledger Protocol (ILP). Ripple expects Payment Channels to be enabled via an Amendment called [PayChan](https://ripple.com/build/amendments/#paychan) on a future date to be determined. - -In the second phase towards making RCL more scalable and compatible with ILP, Ripple is introducing Suspended Payments, a new transaction type on the Ripple network that functions similar to an escrow service, which permits users to cryptographically escrow XRP on RCL with an expiration date. Ripple expects Suspended Payments to be enabled via an Amendment named [SusPay](https://ripple.com/build/amendments/#suspay) on Tuesday, 2017-01-17. - -A Suspended Payment can be created, which deducts the funds from the sending account. It can then be either fulfilled or canceled. It can only be fulfilled if the fulfillment transaction makes it into a ledger with a CloseTime lower than the expiry date of the transaction. It can be canceled with a transaction that makes it into a ledger with a CloseTime greater than the expiry date of the transaction. - -In the third phase towards making RCL more scalable and compatible with ILP, Ripple plans to introduce additional library support for crypto-conditions, which are distributable event descriptions written in a standard format that describe how to recognize a fulfillment message without saying exactly what the fulfillment is. Fulfillments are cryptographically verifiable messages that prove an event occurred. If you transmit a fulfillment, then everyone who has the condition can agree that the condition has been met. Fulfillment requires the submission of a signature that matches the condition (message hash and public key). This format supports multiple algorithms, including different hash functions and cryptographic signing schemes. Crypto-conditions can be nested in multiple levels, with each level possibly having multiple signatures. - -Lastly, we do not have an update on the previously announced changes to the hash tree structure that rippled uses to represent a ledger, called [SHAMapV2](https://ripple.com/build/amendments/#shamapv2). This will require brief scheduled allowable downtime while the changes to the hash tree structure are propagated by the network. We will keep the community updated as we progress towards this date (TBA). - -Consensus refactor (#1874) - -Bug Fixes - -Correct an issue in payment flow code that did not remove an unfunded offer (#1860) - -Sign validator manifests with both ephemeral and master keys (#1865) - -Correctly parse multi-buffer JSON messages (#1862) - - -## Version 0.33.0 - -The `rippled` 0.33.0 release includes an improved version of the payment code, which we expect to be activated via Amendment on Wednesday, 2016-10-20 with the name [Flow](https://ripple.com/build/amendments/#flow). We are also introducing XRP Payment Channels, a new structure in the ledger designed to support [Interledger Protocol](https://interledger.org/) trust lines as balances get substantial, which we expect to be activated via Amendment on a future date (TBA) with the name [PayChan](https://ripple.com/build/amendments/#paychan). Lastly, we will be introducing changes to the hash tree structure that rippled uses to represent a ledger, which we expect to be available via Amendment on a future date (TBA) with the name [SHAMapV2](https://ripple.com/build/amendments/#shamapv2). - -You can [update to the new version](https://ripple.com/build/rippled-setup/#updating-rippled) on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please [compile the new version from source](https://wiki.ripple.com/Rippled_build_instructions). - -** New and Updated Features ** - -A fixed version of the new payment processing engine, which we initially announced on Friday, 2016-07-29, is expected to be available via Amendment on Wednesday, 2016-10-20 with the name [Flow](https://ripple.com/build/amendments/#flow). The new payments code adds no new features, but improves efficiency and robustness in payment handling. - -The Flow code may occasionally produce slightly different results than the old payment processing engine due to the effects of floating point rounding. - -We will be introducing changes to the hash tree structure that rippled uses to represent a ledger, which we expect to be activated via Amendment on a future date (TBA) with the name [SHAMapV2](https://ripple.com/build/amendments/#shamapv2). The new structure is more compact and efficient than the previous version. This affects how ledger hashes are calculated, but has no other user-facing consequences. The activation of the SHAMapV2 amendment will require brief scheduled allowable downtime, while the changes to the hash tree structure are propagated by the network. We will keep the community updated as we progress towards this date (TBA). - -In an effort to make RCL more scalable and to support Interledger Protocol (ILP) trust lines as balances get more substantial, we’re introducing XRP Payment Channels, a new structure in the ledger, which we expect to be available via Amendment on a future date (TBA) with the name [PayChan](https://ripple.com/build/amendments/#paychan). - -XRP Payment Channels permit scalable, intermittent, off-ledger settlement of ILP trust lines for high volume payments flowing in a single direction. For bidirectional channels, an XRP Payment Channel can be used in each direction. The recipient can claim any unpaid balance at any time. The owner can top off the channel as needed. The owner must wait out a delay to close the channel to give the recipient a chance to supply any claims. The total amount paid increases monotonically as newer claims are issued. - -The initial concept behind payment channels was discussed as early as 2011 and the first implementation was done by Mike Hearn in bitcoinj. Recent work being done by Lightning Network has showcased examples of the many use cases for payment channels. The introduction of XRP Payment Channels allows for a more efficient integration between RCL and ILP to further support enterprise use cases for high volume payments. - -Added `getInfoRippled.sh` support script to gather health check for rippled servers [RIPD-1284] - -The `account_info` command can now return information about queued transactions - [RIPD-1205] - -Automatically-provided sequence numbers now consider the transaction queue - [RIPD-1206] - -The `server_info` and `server_state` commands now include the queue-related escalated fee factor in the load_factor field of the response - [RIPD-1207] - -A transaction with a high transaction cost can now cause transactions from the same sender queued in front of it to get into the open ledger if the transaction costs are high enough on average across all such transactions. - [RIPD-1246] - -Reorganization: Move `LoadFeeTrack` to app/tx and clean up functions - [RIPD-956] - -Reorganization: unit test source files - [RIPD-1132] - -Reorganization: NuDB stand-alone repository - [RIPD-1163] - -Reorganization: Add `BEAST_EXPECT` to Beast - [RIPD-1243] - -Reorganization: Beast 64-bit CMake/Bjam target on Windows - [RIPD-1262] - -** Bug Fixes ** - -`PaymentSandbox::balanceHook` can return the wrong issuer, which could cause the transfer fee to be incorrectly by-passed in rare circumstances. [RIPD-1274, #1827] - -Prevent concurrent write operations in websockets [#1806] - -Add HTTP status page for new websocket implementation [#1855] - - -## Version 0.32.1 - -The `rippled` 0.32.1 release includes an improved version of the payment code, which we expect to be available via Amendment on Wednesday, 2016-08-24 with the name FlowV2, and a completely new implementation of the WebSocket protocol for serving clients. - -You can [update to the new version](https://ripple.com/build/rippled-setup/#updating-rippled) on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please [compile the new version from source](https://wiki.ripple.com/Rippled_build_instructions). - -**New and Updated Features** - -An improved version of the payment processing engine, which we expect to be available via Amendment on Wednesday, 2016-08-24 with the name “FlowV2”. The new payments code adds no new features, but improves efficiency and robustness in payment handling. - -The FlowV2 code may occasionally produce slightly different results than the old payment processing engine due to the effects of floating point rounding. Once FlowV2 is enabled on the network then old servers without the FlowV2 amendment will lose sync more frequently because of these differences. - -**Beast WebSocket** - -A completely new implementation of the WebSocket protocol for serving clients is available as a configurable option for `rippled` administrators. To enable this new implementation, change the “protocol” field in `rippled.cfg` from “ws” to “ws2” (or from “wss” to “wss2” for Secure WebSockets), as illustrated in this example: - - [port_ws_public] - port = 5006 - ip = 0.0.0.0 - protocol = wss2 - -The new implementation paves the way for increased reliability and future performance when submitting commands over WebSocket. The behavior and syntax of commands should be identical to the previous implementation. Please report any issues to support@ripple.com. A future version of rippled will remove the old WebSocket implementation, and use only the new one. - -**Bug fixes** - -Fix a non-exploitable, intermittent crash in some client pathfinding requests (RIPD-1219) - -Fix a non-exploitable crash caused by a race condition in the HTTP server. (RIPD-1251) - -Fix bug that could cause a previously fee queued transaction to not be relayed after being in the open ledger for an extended time without being included in a validated ledger. Fix bug that would allow an account to have more than the allowed limit of transactions in the fee queue. Fix bug that could crash debug builds in rare cases when replacing a dropped transaction. (RIPD-1200) - -Remove incompatible OS X switches in Test.py (RIPD-1250) - -Autofilling a transaction fee (sign / submit) with the experimental `x-queue-okay` parameter will use the user’s maximum fee if the open ledger fee is higher, improving queue position, and giving the tx more chance to succeed. (RIPD-1194) - - - -## Version 0.32.0 - -The `rippled` 0.32.0 release improves transaction queue which now supports batching and can hold up to 10 transactions per account, allowing users to queue multiple transactions for processing when the network load is high. Additionally, the `server_info` and `server_state` commands now include information on transaction cost multipliers and the fee command is available to unprivileged users. We advise rippled operators to upgrade immediately. - -You can update to the new version on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please compile the new version from source. - -**New and Updated Features** - -- Allow multiple transactions per account in transaction queue (RIPD-1048). This also introduces a new transaction engine code, `telCAN_NOT_QUEUE`. -- Charge pathfinding consumers per source currency (RIPD-1019): The IP address used to perform pathfinding operations is now charged an additional resource increment for each source currency in the path set. -- New implementation of payment processing engine. This implementation is not yet enabled by default. -- Include amendments in validations subscription -- Add C++17 compatibility -- New WebSocket server implementation with Beast.WebSocket library. The new library offers a stable, high-performance websocket server implementation. To take advantage of this implementation, change websocket protocol under rippled.cfg from wss and ws to wss2 and ws2 under `[port_wss_admin]` and `[port_ws_public]` stanzas: -``` - [port_wss_admin] - port = 51237 - ip = 127.0.0.1 - admin = 127.0.0.1 - protocol = wss2 - - [port_ws_public] - port = 51233 - ip = 0.0.0.0 - protocol = wss2, ws2 -``` -- The fee command is now public (RIPD-1113) -- The fee command checks open ledger rules (RIPD-1183) -- Log when number of available file descriptors is insufficient (RIPD-1125) -- Publish all validation fields for signature verification -- Get quorum and trusted master validator keys from validators.txt -- Standalone mode uses temp DB files by default (RIPD-1129): If a [database_path] is configured, it will always be used, and tables will be upgraded on startup. -- Include config manifest in server_info admin response (RIPD-1172) - -**Bug fixes** - -- Fix history acquire check (RIPD-1112) -- Correctly handle connections that fail security checks (RIPD-1114) -- Fix secured Websocket closing -- Reject invalid MessageKey in SetAccount handler (RIPD-308, RIPD-990) -- Fix advisory delete effect on history acquisition (RIPD-1112) -- Improve websocket send performance (RIPD-1158) -- Fix XRP bridge payment bug (RIPD-1141) -- Improve error reporting for wallet_propose command. Also include a warning if the key used may be an insecure, low-entropy key. (RIPD-1110) - -**Deprecated features** - -- Remove obsolete sendGetPeers support (RIPD-164) -- Remove obsolete internal command (RIPD-888) - - - - -## Version 0.31.2 - -The `rippled` 0.31.2 release corrects issues with the fee escalation algorithm. We advise `rippled` operators to upgrade immediately. - -You can [update to the new version](https://ripple.com/build/rippled-setup/#updating-rippled) on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please [compile the new version from source](https://wiki.ripple.com/Rippled_build_instructions). - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -- A defect in the fee escalation algorithm that caused network fees to escalate more rapidly than intended has been corrected. (RIPD-1177) -- The minimum local fee advertised by validators will no longer be adjusted upwards. - - - -## Version 0.31.1 - -The `rippled` 0.31.1 release contains one important bug fix. We advise `rippled` operators to upgrade immediately. - -You can [update to the new version](https://ripple.com/build/rippled-setup/#updating-rippled) on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please [compile the new version from source](https://wiki.ripple.com/Rippled_build_instructions). - -**New and Updated Features** - -This release has no new features. - -**Bug Fixes** - -`rippled` 0.31.1 contains the following fix: - -- Correctly handle ledger validations with no `LedgerSequence` field. Previous versions of `rippled` incorrectly assumed that the optional validation field would always be included. Current versions of the software always include the field, and gracefully handle its absence. - - - -## Version 0.31.0 - -`rippled` 0.31.0 has been released. - -You can [update to the new version](https://ripple.com/build/rippled-setup/#updating-rippled) on Red Hat Enterprise Linux 7 or CentOS 7 using yum. - -For other platforms, please [compile the new version from source](https://wiki.ripple.com/Rippled_build_instructions). Use the `git log` command to confirm you have the correct source tree. The first log entry should be the change setting the version: - - - commit a5d58566386fd86ae4c816c82085fe242b255d2c - Author: Nik Bougalis - Date: Sun Apr 17 18:02:02 2016 -0700 - - Set version to 0.31.0 - - -**Warnings** - -Please expect a one-time delay when starting 0.31.0 while certain database indices are being built or rebuilt. The delay can be up to five minutes, during which CPU will spike and the server will appear unresponsive (no response to RPC, etc.). - -Additionally, `rippled` 0.31.0 now checks at start-up time that it has sufficient open file descriptors available, and shuts down with an error message if it does not. Previous versions of `rippled` could run out of file descriptors unexpectedly during operation. If you get a file-descriptor error message, increase the number of file descriptors available to `rippled` (for example, editing `/etc/security/limits.conf`) and restart. - -**New and Updated Features** - -`rippled` 0.31.0 has the following new or updated features: - -- (New) [**Amendments**](https://ripple.com/build/amendments/) - A consensus-based system for introducing changes to transaction processing. -- (New) [**Multi-Signing**](https://ripple.com/build/transactions/#multi-signing) - (To be enabled as an amendment) Allow transactions to be authorized by a list of signatures. (RIPD-182) -- (New) **Transaction queue and FeeEscalation** - (To be enabled as an amendment) Include or defer transactions based on the [transaction cost](https://ripple.com/build/transaction-cost/) offered, for better behavior in DDoS conditions. (RIPD-598) -- (Updated) Validations subscription stream now includes `ledger_index` field. (DEC-564) -- (Updated) You can request SignerList information in the `account_info` command (RIPD-1061) - -**Closed Issues** - -`rippled` 0.31.0 has the following fixes and improvements: - -- Improve held transaction submission -- Update SQLite from 3.8.11.1 to 3.11.0 -- Allow random seed with specified wallet_propose key_type (RIPD-1030) -- Limit pathfinding source currency limits (RIPD-1062) -- Speed up out of order transaction processing (RIPD-239) -- Pathfinding optimizations -- Streamlined UNL/validator list: The new code removes the ability to specify domain names in the [validators] configuration block, and no longer supports the [validators_site] option. -- Add websocket client -- Add description of rpcSENDMAX_MALFORMED error -- Convert PathRequest to use std::chrono (RIPD-1069) -- Improve compile-time OpenSSL version check -- Clear old Validations during online delete (RIPD-870) -- Return correct error code during unfunded offer cross (RIPD-1082) -- Report delivered_amount for legacy account_tx queries. -- Improve error message when signing fails (RIPD-1066) -- Fix websocket deadlock - - - - -## Version 0.30.1 - -rippled 0.30.1 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit c717006c44126aa0edb3a36ca29ee30e7a72c1d3 - Author: Nik Bougalis - Date: Wed Feb 3 14:49:07 2016 -0800 - - Set version to 0.30.1 - -This release incorporates a number of important features, bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.30.1) for more detailed information. - -**Release Overview** - -The rippled team is proud to release rippled version 0.30.1. This version contains a several minor new features as well as significant improvements to the consensus algorithm that make it work faster and with more consistency. In the time we have been testing the new release on our validators, these changes have led to increased agreement and shorter close times between ledger versions, for approximately 40% more ledgers validated per day. - -**New Features** - -- Secure gateway: configured IPs can forward identifying user data in HTTP headers, including user name and origin IP. If the user name exists, then resource limits are lifted for that session. See rippled-example.cfg for more information. -- Allow fractional fee multipliers (RIPD-626) -- Add “expiration” to account\_offers (RIPD-1049) -- Add “owner\_funds” to “transactions” array in RPC ledger (RIPD-1050) -- Add "tx" option to "ledger" command line -- Add server uptime in server\_info -- Allow multiple incoming connections from the same IP -- Report connection uptime in peer command (RIPD-927) -- Permit pathfinding to be disabled by setting \[path\_search\_max\] to 0 in rippled.cfg file (RIPD-271) -- Add subscription to peer status changes (RIPD-579) - -**Improvements** - -- Improvements to ledger\_request response -- Improvements to validations proposal relaying (RIPD-1057) -- Improvements to consensus algorithm -- Ledger close time optimizations (RIPD-998, RIPD-791) -- Delete unfunded offers in predictable order - -**Development-Related Updates** - -- Require boost 1.57 -- Implement new coroutines (RIPD-1043) -- Force STAccount interface to 160-bit size (RIPD-994) -- Improve compile-time OpenSSL version check - -**Bug Fixes** - -- Fix handling of secp256r1 signatures (RIPD-1040) -- Fix websocket messages dispatching -- Fix pathfinding early response (RIPD-1064) -- Handle account\_objects empty response (RIPD-958) -- Fix delivered\_amount reporting for minor ledgers (RIPD-1051) -- Fix setting admin privileges on websocket -- Fix race conditions in account\_tx command (RIPD-1035) -- Fix to enforce no-ripple constraints - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - - - ------------------------------------------------------------ - -## Version 0.30.0 - -rippled 0.30.0 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit a8859b495b552fe1eb140771f0f2cb32d11d2ac2 - Author: Vinnie Falco - Date: Wed Oct 21 18:26:02 2015 -0700 - - Set version to 0.30.0 - -This release incorporates a number of important features, bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.30.0) for more detailed information. - -**Release Overview** - -As part of Ripple Labs’ ongoing commitment toward protocol security, the rippled team would like to release rippled 0.30.0. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**`grep '^processor' /proc/cpuinfo | wc -l`**), you can use them to assist in the build process by compiling with the command **`scons -j[number of CPUs - 1]`**. - -**New Features** - -- Honor markers in ledger\_data requests ([RIPD-1010](https://ripplelabs.atlassian.net/browse/RIPD-1010)). -- New Amendment - **TrustSetAuth** (Not currently enabled) Create zero balance trust lines with auth flag ([RIPD-1003](https://ripplelabs.atlassian.net/browse/RIPD-1003)): this allows a TrustSet transaction to create a trust line if the only thing being changed is setting the tfSetfAuth flag. -- Randomize the initial transaction execution order for closed ledgers based on the hash of the consensus set ([RIPD-961](https://ripplelabs.atlassian.net/browse/RIPD-961)). **Activates on October 27, 2015 at 11:00 AM PCT**. -- Differentiate path\_find response ([RIPD-1013](https://ripplelabs.atlassian.net/browse/RIPD-1013)). -- Convert all of an asset ([RIPD-655](https://ripplelabs.atlassian.net/browse/RIPD-655)). - -**Improvements** - -- SHAMap improvements. -- Upgrade SQLite from 3.8.8.2 to 3.8.11.1. -- Limit the number of offers that can be consumed during crossing ([RIPD-1026](https://ripplelabs.atlassian.net/browse/RIPD-1026)). -- Remove unfunded offers on tecOVERSIZE ([RIPD-1026](https://ripplelabs.atlassian.net/browse/RIPD-1026)). -- Improve transport security ([RIPD-1029](https://ripplelabs.atlassian.net/browse/RIPD-1029)): to take full advantage of the improved transport security, servers with a single, static public IP address should add it to their configuration file, as follows: - - [overlay] - public_ip= - -**Development-Related Updates** - -- Transitional support for gcc 5.2: to enable support define the environmental variable `RIPPLED_OLD_GCC_ABI`=1 -- Transitional support for C++ 14: to enable support define the environment variable `RIPPLED_USE_CPP_14`=1 -- Visual Studio 2015 support -- Updates to integration tests -- Add uptime to crawl data ([RIPD-997](https://ripplelabs.atlassian.net/browse/RIPD-997)) - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - - - ------------------------------------------------------------ - -## Version 0.29.0 - -rippled 0.29.0 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 5964710f736e258c7892e8b848c48952a4c7856c - Author: Nik Bougalis - Date: Tue Aug 4 13:22:45 2015 -0700 - - Set version to 0.29.0 - -This release incorporates a number of important features, bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.29.0) for more detailed information. - -**Release Overview** - -As part of Ripple Labs’ ongoing commitment toward protocol security, the rippled team would like to announce rippled release 0.29.0. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -**New Features** - -- Subscription stream for validations ([RIPD-504](https://ripplelabs.atlassian.net/browse/RIPD-504)) - -**Deprecated features** - -- Disable Websocket ping timer - -**Bug Fixes** - -- Fix off-by one bug that overstates the account reserve during OfferCreate transaction. **Activates August 17, 2015**. -- Fix funded offer removal during Payment transaction ([RIPD-113](https://ripplelabs.atlassian.net/browse/RIPD-113)). **Activates August 17, 2015**. -- Fix display discrepancy in fee. - -**Improvements** - -- Add “quality” field to account\_offers API response: quality is defined as the exchange rate, the ratio taker\_pays divided by taker\_gets. -- Add [full\_reply](https://ripple.com/build/rippled-apis/#path-find-create) field to path\_find API response: full\_reply is defined as true/false value depending on the completed depth of pathfinding search ([RIPD-894](https://ripplelabs.atlassian.net/browse/RIPD-894)). -- Add [DeliverMin](https://ripple.com/build/transactions/#payment) transaction field ([RIPD-930](https://ripplelabs.atlassian.net/browse/RIPD-930)). **Activates August 17, 2015**. - -**Development-Related Updates** - -- Add uptime to crawl data ([RIPD-997](https://ripplelabs.atlassian.net/browse/RIPD-997)). -- Add IOUAmount and XRPAmount: these numeric types replace the monolithic functionality found in STAmount ([RIPD-976](https://ripplelabs.atlassian.net/browse/RIPD-976)). -- Log metadata differences on built ledger mismatch. -- Add enableTesting flag to applyTransactions. - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - - - ------------------------------------------------------------ - -## Version 0.28.2 - -rippled 0.28.2 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 6374aad9bc94595e051a04e23580617bc1aaf300 - Author: Vinnie Falco - Date: Tue Jul 7 09:21:44 2015 -0700 - - Set version to 0.28.2 - -This release incorporates a number of important features, bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/release) for more detailed information. - -**Release Overview** - -As part of Ripple Labs’ ongoing commitment toward protocol security, the rippled team would like to announce rippled release 0.28.2. **This release is necessary for compatibility with OpenSSL v.1.0.1n and later.** - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**rippled.cfg Updates** - -For \[ips\] stanza, a port must be specified for each listed IP address with the space between IP address and port, ex.: `r.ripple.com` `51235` ([RIPD-893](https://ripplelabs.atlassian.net/browse/RIPD-893)) - -**New Features** - -- New API: [gateway\_balances](https://ripple.com/build/rippled-apis/#gateway-balances) to get a gateway's hot wallet balances and total obligations. - -**Deprecated features** - -- Removed temp\_db ([RIPD-887](https://ripplelabs.atlassian.net/browse/RIPD-887)) - -**Improvements** - -- Improve peer send queue management -- Support larger EDH keys -- More robust call to get the valid ledger index -- Performance improvements to transactions application to open ledger - -**Development-Related Updates** - -- New Env transaction testing framework for unit testing -- Fix MSVC link -- C++ 14 readiness - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - - - ------------------------------------------------------------ - -## Version 0.28.1 - -rippled 0.28.1 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 399c43cae6e90a428e9ce6a988123972b0f03c99 - Author: Miguel Portilla - Date: Wed May 20 13:30:54 2015 -0400 - - Set version to 0.28.1 - -This release incorporates a number of important features, bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.28.1) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**New Features** - -- Filtering for Account Objects ([RIPD-868](https://ripplelabs.atlassian.net/browse/RIPD-868)). -- Track rippled server peers latency ([RIPD-879](https://ripplelabs.atlassian.net/browse/RIPD-879)). - -**Bug fixes** - -- Expedite zero flow handling for offers -- Fix offer crossing when funds are the limiting factor - -**Deprecated features** - -- Wallet\_accounts and generator maps ([RIPD-804](https://ripplelabs.atlassian.net/browse/RIPD-804)) - -**Improvements** - -- Control ledger query depth based on peers latency -- Improvements to ledger history fetches -- Improve RPC ledger synchronization requirements ([RIPD-27](https://ripplelabs.atlassian.net/browse/RIPD-27), [RIPD-840](https://ripplelabs.atlassian.net/browse/RIPD-840)) -- Eliminate need for ledger in delivered\_amount calculation ([RIPD-860](https://ripplelabs.atlassian.net/browse/RIPD-860)) -- Improvements to JSON parsing - -**Development-Related Updates** - -- Add historical ledger fetches per minute to get\_counts -- Compute validated ledger age from signing time -- Remove unused database table ([RIPD-755](https://ripplelabs.atlassian.net/browse/RIPD-755)) - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - - - ------------------------------------------------------------ - -## Version 0.28.0 - -rippled 0.28.0 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 7efd0ab0d6ef017331a0e214a3053893c88f38a9 - Author: Vinnie Falco - Date: Fri Apr 24 18:57:36 2015 -0700 - - Set version to 0.28.0 - -This release incorporates a number of important features, bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.28.0) for more detailed information. - -**Release Overview** - -As part of Ripple Labs’ ongoing commitment toward improving the protocol, the rippled team is excited to announce **autobridging** — a feature that allows XRP to serve as a bridge currency. Autobridging enhances utility and has the potential to expose more of the network to liquidity and improve prices. For more information please refer to the [autobridging blog post](https://ripple.com/uncategorized/introducing-offer-autobridging/). - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Important rippled.cfg update** - -With rippled version 0.28, the rippled.cfg file must be changed according to these instructions: - -- Change any entries that say - -`admin` `=` `allow` to `admin` `=` - -- For most installations, 127.0.0.1 will preserve current behavior. 0.0.0.0 may be specified to indicate "any IP" but cannot be combined with other IP addresses. Use of 0.0.0.0 may introduce severe security risks and is not recommended. See docs/rippled-example.cfg for more information. - -**More Strict Requirements on MemoType** - -The requirements on the contents of the MemoType field, if present, are more strict than the previous version. Transactions that can successfully be submitted to 0.27.4 and earlier may fail in 0.28.0. For details, please refer to [updated memo documentation](https://ripple.com/build/transactions/#memos) for details. Partners should check their implementation to make sure that their MemoType follows the new rules. - -**New Features** - -- Autobridging implementation ([RIPD-423](https://ripplelabs.atlassian.net/browse/RIPD-423)). **This feature will be turned on May 12, 2015**. -- Combine history\_ledger\_index and online\_delete settings in rippled.cfg ([RIPD-774](https://ripplelabs.atlassian.net/browse/RIPD-774)). -- Claim a fee when a required destination tag is not specified ([RIPD-574](https://ripplelabs.atlassian.net/browse/RIPD-574)). -- Require the master key when disabling the use of the master key or when enabling 'no freeze' ([RIPD-666](https://ripplelabs.atlassian.net/browse/RIPD-666)). -- Change the port setting admin to accept allowable admin IP addresses ([RIPD-820](https://ripplelabs.atlassian.net/browse/RIPD-820)): - - rpc\_admin\_allow has been removed. - - Comma-separated list of IP addresses that are allowed administrative privileges (subject to username & password authentication if configured). - - 127.0.0.1 is no longer a default admin IP. - - 0.0.0.0 may be specified to indicate "any IP" but cannot be combined with other MIP addresses. Use of 0.0.0.0 may introduce severe security risks and is not recommended. -- Enable Amendments from config file or static data ([RIPD-746](https://ripplelabs.atlassian.net/browse/RIPD-746)). - -**Bug fixes** - -- Fix payment engine handling of offer ⇔ account ⇔ offer cases ([RIPD-639](https://ripplelabs.atlassian.net/browse/RIPD-639)). **This fix will take effect on May 12, 2015**. -- Fix specified destination issuer in pathfinding ([RIPD-812](https://ripplelabs.atlassian.net/browse/RIPD-812)). -- Only report delivered\_amount for executed payments ([RIPD-827](https://ripplelabs.atlassian.net/browse/RIPD-827)). -- Return a validated ledger if there is one ([RIPD-814](https://ripplelabs.atlassian.net/browse/RIPD-814)). -- Refund owner's ticket reserve when a ticket is canceled ([RIPD-855](https://ripplelabs.atlassian.net/browse/RIPD-855)). -- Return descriptive error from account\_currencies RPC ([RIPD-806](https://ripplelabs.atlassian.net/browse/RIPD-806)). -- Fix transaction enumeration in account\_tx API ([RIPD-734](https://ripplelabs.atlassian.net/browse/RIPD-734)). -- Fix inconsistent ledger\_current return ([RIPD-669](https://ripplelabs.atlassian.net/browse/RIPD-669)). -- Fix flags --rpc\_ip and --rpc\_port ([RIPD-679](https://ripplelabs.atlassian.net/browse/RIPD-679)). -- Skip inefficient SQL query ([RIPD-870](https://ripplelabs.atlassian.net/browse/RIPD-870)) - -**Deprecated features** - -- Remove support for deprecated PreviousTxnID field ([RIPD-710](https://ripplelabs.atlassian.net/browse/RIPD-710)). **This will take effect on May 12, 2015**. -- Eliminate temREDUNDANT\_SEND\_MAX ([RIPD-690](https://ripplelabs.atlassian.net/browse/RIPD-690)). -- Remove WalletAdd ([RIPD-725](https://ripplelabs.atlassian.net/browse/RIPD-725)). -- Remove SMS support. - -**Improvements** - -- Improvements to peer communications. -- Reduce master lock for client requests. -- Update SQLite to 3.8.8.2. -- Require Boost 1.57. -- Improvements to Universal Port ([RIPD-687](https://ripplelabs.atlassian.net/browse/RIPD-687)). -- Constrain valid inputs for memo fields ([RIPD-712](https://ripplelabs.atlassian.net/browse/RIPD-712)). -- Binary option for ledger command ([RIPD-692](https://ripplelabs.atlassian.net/browse/RIPD-692)). -- Optimize transaction checks ([RIPD-751](https://ripplelabs.atlassian.net/browse/RIPD-751)). - -**Development-Related Updates** - -- Add RPC metrics ([RIPD-705](https://ripplelabs.atlassian.net/browse/RIPD-705)). -- Track and report peer load. -- Builds/Test.py will build and test by one or more scons targets. -- Support a --noserver command line option in tests: -- Run npm/integration tests without launching rippled, using a running instance of rippled (possibly in a debugger) instead. -- Works for npm test and mocha. -- Display human readable SSL error codes. -- Better transaction analysis ([RIPD-755](https://ripplelabs.atlassian.net/browse/RIPD-755)). - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - - - ------------------------------------------------------------ - -## Version 0.27.4 - -rippled 0.27.4 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 92812fe7239ffa3ba91649b2ece1e892b866ec2a - Author: Nik Bougalis - Date: Wed Mar 11 11:26:44 2015 -0700 - - Set version to 0.27.4 - -This release includes one new feature. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.27.4) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Bug Fixes** - -- Limit passes in the payment engine - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - - - ------------------------------------------------------------ - -## Version 0.27.3-sp2 - -rippled 0.27.3-sp2 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit f999839e599e131ed624330ad0ce85bb995f02d3 - Author: Nik Bougalis - Date: Thu Mar 12 13:37:47 2015 -0700 - - Set version to 0.27.3-sp2 - -This release includes one new feature. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.27.3-sp2) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**New Features** - -- Add noripple\_check RPC command: this command tells gateways what they need to do to set "Default Ripple" account flag and fix any trust lines created before the flag was set. - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - - - ------------------------------------------------------------ - -## Version 0.27.3-sp1 - -rippled 0.27.3-sp1 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 232693419a2c9a8276a0fae991f688f6f01a3add - Author: Nik Bougalis - Date: Wed Mar 11 10:26:39 2015 -0700 - - Set version to 0.27.3-sp1 - -This release includes one new feature. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.27.3-sp1) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**New Features** - -- Add "Default Ripple" account flag - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.27.3 - -rippled 0.27.3 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 70c2854f7c8a28801a7ebc81dd62bf0d068188f0 - Author: Nik Bougalis - Date: Tue Mar 10 14:06:33 2015 -0700 - - Set version to 0.27.3 - -This release includes one new feature. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.27.3) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**New Features** - -- Add "Default Ripple" account flag - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.27.2 - -rippled 0.27.2 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 9cc8eec773e8afc9c12a6aab4982deda80495cf1 - Author: Nik Bougalis - Date: Sun Mar 1 14:56:44 2015 -0800 - - Set version to 0.27.2 - -This release incorporates a number of important bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.27.2) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**New Features** - -- NuDB backend option: high performance key/value database optimized for rippled (set “type=nudb” in .cfg). - - Either import RockdDB to NuDB using import tool, or - - Start fresh with NuDB but delete SQLite databases if rippled ran previously with RocksDB: - - rm [database_path]/transaction.* [database_path]/ledger.* - -**Bug Fixes** - -- Fix offer quality bug - -**Deprecated** - -- HyperLevelDB, LevelDB, and SQLlite backend options. Use RocksDB for spinning drives and NuDB for SSDs backend options. - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.27.1 - -rippled 0.27.1 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 95973ba3e8b0bd28eeaa034da8b806faaf498d8a - Author: Vinnie Falco - Date: Tue Feb 24 13:31:13 2015 -0800 - - Set version to 0.27.1 - -This release incorporates a number of important bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.27.1) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**New Features** - -- RocksDB to NuDB import tool ([RIPD-781](https://ripplelabs.atlassian.net/browse/RIPD-781), [RIPD-785](https://ripplelabs.atlassian.net/browse/RIPD-785)): custom tool specifically designed for very fast import of RocksDB nodestore databases into NuDB - -**Bug Fixes** - -- Fix streambuf bug - -**Improvements** - -- Update RocksDB backend settings -- NuDB improvements: - - Limit size of mempool ([RIPD-787](https://ripplelabs.atlassian.net/browse/RIPD-787)) - - Performance improvements ([RIPD-793](https://ripplelabs.atlassian.net/browse/RIPD-793), [RIPD-796](https://ripplelabs.atlassian.net/browse/RIPD-796)): changes in Nudb to improve speed, reduce database size, and enhance correctness. The most significant change is to store hashes rather than entire keys in the key file. The output of the hash function is reduced to 48 bits, and stored directly in buckets. - -**Experimental** - -- Add /crawl cgi request feature to peer protocol ([RIPD-729](https://ripplelabs.atlassian.net/browse/RIPD-729)): adds support for a cgi /crawl request, issued over HTTPS to the configured peer protocol port. The response to the request is a JSON object containing the node public key, type, and IP address of each directly connected neighbor. The IP address is suppressed unless the neighbor has requested its address to be revealed by adding "Crawl: public" to its HTTP headers. This field is currently set by the peer\_private option in the rippled.cfg file. - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.27.0 - -rippled 0.27.0 has been released. The commit can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit c6c8e5d70c6fbde02cd946135a061aa77744396f - Author: Vinnie Falco - Date: Mon Jan 26 10:56:11 2015 -0800 - - Set version to 0.27.0 - -This release incorporates a number of important bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.27.0) for more detailed information. - -**Release Overview** - -The rippled team is proud to release rippled 0.27.0. This new version includes many exciting features that will appeal to our users. The team continues to work on stability, scalability, and performance. - -The first feature is Online Delete. This feature allows rippled to maintain it’s database of previous ledgers within a fixed amount of disk space. It does this while allowing rippled to stay online and maintain an administrator specify minimum number of ledgers. This means administrators with limited disk space will no longer need to manage disk space by periodically manually removing the database. Also, with the previously existing backend databases performance would gradually degrade as the database grew in size. In particular, rippled would perform poorly whenever the backend database performed ever growing compaction operations. By limiting rippled to less history, compaction is less resource intensive and systems with less disk performance can now run rippled. - -Additionally, we are very excited to include Universal Port. This feature allows rippled's listening port to handshake in multiple protocols. For example, a single listening port can be configured to receive incoming peer connections, incoming RPC commands over HTTP, and incoming RPC commands over HTTPS at the same time. Or, a single port can receive both Websockets and Secure Websockets clients at the same. - -Finally, a new, experimental backend database, NuDB, has been added. This database was developed by Ripple Labs to take advantage of rippled’s specific data usage profile and performs much better than previous databases. Significantly, this database does not degrade in performance as the database grows. Very excitingly, this database works on OS X and Windows. This allows rippled to use these platforms for the first time. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.57.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Important rippled.cfg Update** - -**The format of the configuration file has changed. If upgrading from a previous version of rippled, please see the migration instructions below.** - -**New Features** - -- SHAMapStore Online Delete ([RIPD-415](https://ripplelabs.atlassian.net/browse/RIPD-415)): Makes rippled configurable to support deletion of all data in its key-value store (nodestore) and ledger and transaction SQLite databases based on validated ledger sequence numbers. See doc/rippled-example.cfg for configuration setup. -- [Universal Port](https://forum.ripple.com/viewtopic.php?f=2&t=8313&p=57969). See necessary config changes below. -- Config "ledger\_history\_index" option ([RIPD-559](https://ripplelabs.atlassian.net/browse/RIPD-559)) - -**Bug Fixes** - -- Fix pathfinding with multiple issuers for one currency ([RIPD-618](https://ripplelabs.atlassian.net/browse/RIPD-618)) -- Fix account\_lines, account\_offers and book\_offers result ([RIPD-682](https://ripplelabs.atlassian.net/browse/RIPD-682)) -- Fix pathfinding bugs ([RIPD-735](https://ripplelabs.atlassian.net/browse/RIPD-735)) -- Fix RPC subscribe with multiple books ([RIPD-77](https://ripplelabs.atlassian.net/browse/RIPD-77)) -- Fix account\_tx API - -**Improvements** - -- Improve the human-readable description of the tesSUCCESS code -- Add 'delivered\_amount' to Transaction JSON ([RIPD-643](https://ripplelabs.atlassian.net/browse/RIPD-643)): The synthetic field 'delivered\_amount' can be used to determine the exact amount delivered by a Payment without having to check the DeliveredAmount field, if present, or the Amount field otherwise. - -**Development-Related Updates** - -- HTTP Handshaking for Peers on Universal Port ([RIPD-446](https://ripplelabs.atlassian.net/browse/RIPD-446)) -- Use asio signal handling in Application ([RIPD-140](https://ripplelabs.atlassian.net/browse/RIPD-140)) -- Build dependency on Boost 1.57.0 -- Support a "no\_server" flag in test config -- API for improved Unit Testing ([RIPD-432](https://ripplelabs.atlassian.net/browse/RIPD-432)) -- Option to specify rippled path on command line (--rippled=\) - -**Experimental** - -- NuDB backend option: high performance key/value database optimized for rippled (set “type=nudb” in .cfg) - -**Migration Instructions** - -With rippled version 0.27.0, the rippled.cfg file must be changed according to these instructions: - -- Add new stanza - `[server]`. This section will contain a list of port names and key/value pairs. A port name must start with a letter and contain only letters and numbers. The name is not case-sensitive. For each name in this list, rippled will look for a configuration file section with the same name and use it to create a listening port. To simplify migration, you can use port names from your previous version of rippled.cfg (see Section 1. Server for detailed explanation in doc/rippled-example.cfg). For example: - - [server] - rpc_port - peer_port - websocket_port - ssl_key = - ssl_cert = - ssl_chain = - -- For each port name in `[server]` stanza, add separate stanzas. For example: - - [rpc_port] - port = - ip = - admin = allow - protocol = https - - [peer_port] - port = - ip = - protocol = peer - - [websocket_port] - port = - ip = - admin = allow - protocol = wss - -- Remove current `[rpc_port],` `[rpc_ip],` `[rpc_allow_remote],` `[rpc_ssl_key],` `[rpc_ssl_cert],` `and` `[rpc_ssl_chain],` `[peer_port],` `[peer_ip],` `[websocket_port],` `[websocket_ip]` settings from rippled.cfg - -- If you allow untrusted websocket connections to your rippled, add `[websocket_public_port]` stanza under `[server]` section and replace websocket public settings with `[websocket_public_port]` section: - - [websocket_public_port] - port = - ip = - protocol = ws ← make sure this is ws, not wss` - -- Remove `[websocket_public_port],` `[websocket_public_ip],` `[websocket_ssl_key],` `[websocket_ssl_cert],` `[websocket_ssl_chain]` settings from rippled.cfg -- Disable `[ssl_verify]` section by setting it to 0 -- Migrate the remaining configurations without changes. To enable online delete feature, check Section 6. Database in doc/rippled-example.cfg - -**Integration Notes** - -With this release, integrators should deprecate the "DeliveredAmount" field in favor of "delivered\_amount." - -**For Transactions That Occurred Before January 20, 2014:** - -- If amount actually delivered is different than the transactions “Amount” field - - "delivered\_amount" will show as unavailable indicating a developer should use caution when processing this payment. - - Example: A partial payment transaction (tfPartialPayment). -- Otherwise - - "delivered\_amount" will show the correct destination balance change. - -**For Transactions That Occur After January 20, 2014:** - -- If amount actually delivered is different than the transactions “Amount” field - - A "delivered\_amount" field will determine the destination amount change - - Example: A partial payment transaction (tfPartialPayment). -- Otherwise - - "delivered\_amount" will show the correct destination balance change. - -**Assistance** - -For assistance, please contact **integration@ripple.com** - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.26.4 - -rippled 0.26.4 has been released. The repository tag is *0.26.4* and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 05a04aa80192452475888479c84ff4b9b54e6ae7 - Author: Vinnie Falco - Date: Mon Nov 3 16:53:37 2014 -0800 - - Set version to 0.26.4 - -This release incorporates a number of important bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.26.4) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.55.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Important JSON-RPC Update** - -With rippled version 0.26.4, the [rippled.cfg](https://github.com/ripple/rippled/blob/0.26.4/doc/rippled-example.cfg) file must set the ssl\_verify property to 0. Without this update, JSON-RPC API calls may not work. - -**New Features** - -- Rocksdb v. 3.5.1 -- SQLite v. 3.8.7 -- Disable SSLv3 -- Add counters to track ledger read and write activities -- Use trusted validators median fee when determining transaction fee -- Add --quorum argument for server start ([RIPD-563](https://ripplelabs.atlassian.net/browse/RIPD-563)) -- Add account\_offers paging ([RIPD-344](https://ripplelabs.atlassian.net/browse/RIPD-344)) -- Add account\_lines paging ([RIPD-343](https://ripplelabs.atlassian.net/browse/RIPD-343)) -- Ability to configure network fee in rippled.cfg file ([RIPD-564](https://ripplelabs.atlassian.net/browse/RIPD-564)) - -**Bug Fixes** - -- Fix OS X version parsing/error related to OS X 10.10 update -- Fix incorrect address in connectivity check report -- Fix page sizes for ledger\_data ([RIPD-249](https://ripplelabs.atlassian.net/browse/RIPD-249)) -- Make log partitions case-insensitive in rippled.cfg - -**Improvements** - -- Performance - - Ledger performance improvements for storage and traversal ([RIPD-434](https://ripplelabs.atlassian.net/browse/RIPD-434)) - - Improve client performance for JSON responses ([RIPD-439](https://ripplelabs.atlassian.net/browse/RIPD-439)) -- Other - - Remove PROXY handshake feature - - Change to rippled.cfg to support sections containing both key/value pairs and a list of values - - Return descriptive error message for memo validation ([RIPD-591](https://ripplelabs.atlassian.net/browse/RIPD-591)) - - Changes to enforce JSON-RPC 2.0 error format - - Optimize account\_lines and account\_offers ([RIPD-587](https://ripplelabs.atlassian.net/browse/RIPD-587)) - - Improve fee setting logic ([RIPD-614](https://ripplelabs.atlassian.net/browse/RIPD-614)) - - Improve transaction security - - Config improvements - - Improve path filtering ([RIPD-561](https://ripplelabs.atlassian.net/browse/RIPD-561)) - - Logging to distinguish Byzantine failure from tx bug ([RIPD-523](https://ripplelabs.atlassian.net/browse/RIPD-523)) - -**Experimental** - -- Add "deferred" flag to transaction relay message (required for future code that will relay deferred transactions) -- Refactor STParsedJSON to parse an object or array (required for multisign implementation) ([RIPD-480](https://ripplelabs.atlassian.net/browse/RIPD-480)) - -**Development-Related Updates** - -- Changes to DatabaseReader to read ledger numbers from database -- Improvements to SConstruct - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.26.3-sp1 - -rippled 0.26.3-sp1 has been released. The repository tag is *0.26.3-sp1* and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 2ad6f0a65e248b4f614d38d199a9d5d02f5aaed8 - Author: Vinnie Falco - Date: Fri Sep 12 15:22:54 2014 -0700 - - Set version to 0.26.3-sp1 - -This release incorporates a number of important bugfixes and functional improvements. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.26.3-sp1) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.55.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**New Features** - -- New command to display HTTP/S-RPC sessions metrics ([RIPD-533](https://ripplelabs.atlassian.net/browse/RIPD-533)) - -**Bug Fixes** - -- Improved handling of HTTP/S-RPC sessions ([RIPD-489](https://ripplelabs.atlassian.net/browse/RIPD-489)) -- Fix unit tests for Windows. -- Fix integer overflows in JSON parser. - -**Improvements** - -- Improve processing of trust lines during pathfinding. - -**Experimental Features** - -- Added a command line utility called LedgerTool for retrieving and processing ledger blocks from the Ripple network. - -**Development-Related Updates** - -- HTTP message and parser improvements. - - Streambuf wrapper supports rvalue move. - - Message class holds a complete HTTP message. - - Body class holds the HTTP content body. - - Headers class holds RFC-compliant HTTP headers. - - Basic\_parser provides class interface to joyent's http-parser. - - Parser class parses into a message object. - - Remove unused http get client free function. - - Unit test for parsing malformed messages. -- Add enable\_if\_lvalue. -- Updates to includes and scons. -- Additional ledger.history.mismatch insight statistic. -- Convert rvalue to an lvalue. ([RIPD-494](https://ripplelabs.atlassian.net/browse/RIPD-494)) -- Enable heap profiling with jemalloc. -- Add aged containers to Validators module. ([RIPD-349](https://ripplelabs.atlassian.net/browse/RIPD-349)) -- Account for high-ASCII characters. ([RIPD-464](https://ripplelabs.atlassian.net/browse/RIPD-464)) - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.26.2 - -rippled 0.26.2 has been released. The repository tag is *0.26.2* and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit b9454e0f0ca8dbc23844a0520d49394e10d445b1 - Author: Vinnie Falco - Date: Mon Aug 11 15:25:44 2014 -0400 - - Set version to 0.26.2 - -This release incorporates a small number of important bugfixes. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.26.2) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.55.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**New Features** - -- Freeze enforcement: activates on September 15, 2014 ([RIPD-399](https://ripplelabs.atlassian.net/browse/RIPD-399)) -- Add pubkey\_node and hostid to server stream messages ([RIPD-407](https://ripplelabs.atlassian.net/browse/RIPD-407)) - -**Bug Fixes** - -- Fix intermittent exception when closing HTTPS connections ([RIPD-475](https://ripplelabs.atlassian.net/browse/RIPD-475)) -- Correct Pathfinder::getPaths out to handle order books ([RIPD-427](https://ripplelabs.atlassian.net/browse/RIPD-427)) -- Detect inconsistency in PeerFinder self-connects ([RIPD-411](https://ripplelabs.atlassian.net/browse/RIPD-411)) - -**Experimental Features** - -- Add owner\_funds to client subscription data ([RIPD-377](https://ripplelabs.atlassian.net/browse/RIPD-377)) - -The offer funding status feature is “experimental” in this version. Developers are able to see the field, but it is subject to change in future releases. - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.26.1 - -rippled v0.26.1 has been released. The repository tag is **0.26.1** and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 9a0e806f78300374e20070e2573755fbafdbfd03 - Author: Vinnie Falco - Date: Mon Jul 28 11:27:31 2014 -0700 - - Set version to 0.26.1 - -This release incorporates a small number of important bugfixes. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/0.26.1) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.55.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Bug Fixes** - -- Enabled asynchronous handling of HTTP-RPC interactions. This fixes client handlers using RPC that periodically return blank responses to requests. ([RIPD-390](https://ripplelabs.atlassian.net/browse/RIPD-390)) -- Fixed auth handling during OfferCreate. This fixes a regression of [RIPD-256](https://ripplelabs.atlassian.net/browse/RIPD-256). ([RIPD-414](https://ripplelabs.atlassian.net/browse/RIPD-414)) - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.26.0 - -rippled v0.26.0 has been released. The repository tag is **0.26.0** and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 9fa5e3987260e39dba322f218d39ac228a5b361b - Author: Vinnie Falco - Date: Tue Jul 22 09:59:45 2014 -0700 - - Set version to 0.26.0 - -This release incorporates a significant number of improvements and important bugfixes. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/develop) for more detailed information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend compiling on (virtual) machines with 8GB of RAM or more. If your build machine has more than one CPU (**\`grep '^processor' /proc/cpuinfo | wc -l\`**), you can use them to assist in the build process by compiling with the command **scons -j\[number of CPUs - 1\]**. - -The minimum supported version of Boost is v1.55.0. You **must** upgrade to this release or later to successfully compile this release of rippled. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Improvements** - -- Updated integration tests. -- Updated tests for account freeze functionality. -- Implement setting the no-freeze flag on Ripple accounts ([RIPD-394](https://ripplelabs.atlassian.net/browse/RIPD-394)). -- Improve transaction fee and execution logic ([RIPD-323](https://ripplelabs.atlassian.net/browse/RIPD-323)). -- Implemented finding of 'sabfd' paths ([RIPD-335](https://ripplelabs.atlassian.net/browse/RIPD-335)). -- Imposed a local limit on paths lengths ([RIPD-350](https://ripplelabs.atlassian.net/browse/RIPD-350)). -- Documented [ledger entries](https://github.com/ripple/rippled/blob/develop/src/ripple/module/app/ledger/README.md) ([RIPD-361](https://ripplelabs.atlassian.net/browse/RIPD-361)). -- Documented [SHAMap](https://github.com/ripple/rippled/blob/develop/src/ripple/module/app/shamap/README.md). - -**Bug Fixes** - -- Fixed the limit parameter on book\_offers ([RIPD-295](https://ripplelabs.atlassian.net/browse/RIPD-295)). -- Removed SHAMapNodeID from SHAMapTreeNode to fix "right data, wrong ID" bug in the tree node cache ([RIPD-347](https://ripplelabs.atlassian.net/browse/RIPD-347)). -- Eliminated spurious SHAMap::getFetchPack failure ([RIPD-379](https://ripplelabs.atlassian.net/browse/RIPD-379)). -- Disabled SSLv2. -- Implemented rate-limiting of SSL client renegotiation to mitigate [SCIR DoS vulnerability](https://www.thc.org/thc-ssl-dos/) ([RIPD-360](https://ripplelabs.atlassian.net/browse/RIPD-360)). -- Display unprintable or malformatted currency codes as hex digits. -- Fix static initializers in RippleSSLContext ([RIPD-375](https://ripplelabs.atlassian.net/browse/RIPD-375)). - -**More information** - -For more information or assistance, the following resources will be of use: - -- [Ripple Developer Forums](https://ripple.com/forum/viewforum.php?f=2) -- [IRC](https://webchat.freenode.net/?channels=#ripple) - - ------------------------------------------------------------ - -## Version 0.25.2 - -rippled v0.25.2 has been released. The repository tag is **0.25.2** and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit ddf68d464d74e1c76a0cfd100a08bc8e65b91fec - Author: Mark Travis - Date: Mon Jul 7 11:46:15 2014 -0700 - - Set version to 0.25.2 - -This release incorporates significant improvements which may not warrant separate entries but are incorporated into the feature changes as summary lines. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/develop) for more information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -While it may be possible to compile rippled on (virtual) machines with 4GB of RAM, we recommend build machines with 8GB of RAM. - -The minimum supported version of Boost is v1.55. You **must** upgrade to this release or later to successfully compile this release. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Improvements** - -- CPU utilization for certain operations has been optimized. -- Improve serialization of public ledger blocks. -- rippled now takes much less time to compile. -- Additional pathfinding heuristic: increases liquidity in some cases. - -**Bug Fixes** - -- Unprintable currency codes will be printed as hex digits. -- Transactions with unreasonably long path lengths are rejected. The maximum is now eight (8) hops. - - ------------------------------------------------------------ - -## Version 0.25.1 - -`rippled` v0.25.1 has been released. The repository tag is `0.25.1` and can be found on GitHub at: https://github.com/ripple/rippled/tree/0.25.1 - -Prior to building, please confirm you have the correct source tree with the `git log` command. The first log entry should be the change setting the version: - - commit b677cacb8ce0d4ef21f8c60112af1db51dce5bb4 - Author: Vinnie Falco - Date: Thu May 15 08:27:20 2014 -0700 - - Set version to 0.25.1 - -This release incorporates significant improvements which may not warrant separate entries but are incorporated into the feature changes as summary lines. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/develop) for more information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -A minimum of 4GB of RAM are required to successfully compile this release. - -The minimum supported version of Boost is v1.55. You **must** upgrade to this release or later to successfully compile this release. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Major Features** - -* Option to compress the NodeStore db. More speed, less space. See [`rippled-example.cfg`](https://github.com/ripple/rippled/blob/0.25.1/doc/rippled-example.cfg#L691) - -**Improvements** - -* Remove redundant checkAccept call -* Added I/O latency to output of ''server_info''. -* Better performance handling of Fetch Packs. -* Improved handling of modified ledger nodes. -* Improved performance of JSON document generator. -* Made strConcat operate in O(n) time for greater efficiency. -* Added some new configuration options to doc/rippled-example.cfg - -**Bug Fixes** - -* Fixed a bug in Unicode parsing of transactions. -* Fix a blocker with tfRequireAuth -* Merkle tree nodes that are retrieved as a result of client requests are cached locally. -* Use the last ledger node closed for finding old paths through the network. -* Reduced number of asynchronous fetches. - - ------------------------------------------------------------ - -## Version 0.25.0 - -rippled version 0.25.0 has been released. The repository tag is **0.25.0** and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 29d1d5f06261a93c5e94b4011c7675ff42443b7f - Author: Vinnie Falco - Date: Wed May 14 09:01:44 2014 -0700 - - Set version to 0.25.0 - -This release incorporates significant improvements which may not warrant separate entries but are incorporated into the feature changes as summary lines. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/develop) for more information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -A minimum of 4GB of RAM are required to successfully compile this release. - -The minimum supported version of Boost is v1.55. You **must** upgrade to this release or later to successfully compile this release. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Major Features** - -- Option to compress the NodeStore db. More speed, less space. See [`rippled-example.cfg`](https://github.com/ripple/rippled/blob/0.25.0/doc/rippled-example.cfg#L691) - -**Improvements** - -- Remove redundant checkAccept call -- Added I/O latency to output of *server\_info*. -- Better performance handling of Fetch Packs. -- Improved handling of modified ledger nodes. -- Improved performance of JSON document generator. -- Made strConcat operate in O(n) time for greater efficiency. - -**Bug Fixes** - -- Fix a blocker with tfRequireAuth -- Merkle tree nodes that are retrieved as a result of client requests are cached locally. -- Use the last ledger node closed for finding old paths through the network. -- Reduced number of asynchronous fetches. - - ------------------------------------------------------------ - -## Version 0.24.0 - -rippled version 0.24.0 has been released. The repository tag is **0.24.0** and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 3eb1c7bd6f93e5d874192197f76571184338f702 - Author: Vinnie Falco - Date: Mon May 5 10:20:46 2014 -0700 - - Set version to 0.24.0 - -This release incorporates significant improvements which may not warrant separate entries but are incorporated into the feature changes as summary lines. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/develop) for more information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -A minimum of 4GB of RAM are required to successfully compile this release. - -The minimum supported version of Boost is v1.55. You **must** upgrade to this release or later to successfully compile this release. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Improvements** - -- Implemented logic for ledger processes and features. -- Use "high threads" for background RocksDB database writes. -- Separately track locally-issued transactions to ensure they always appear in the open ledger. - -**Bug Fixes** - -- Fix AccountSet for canonical transactions. -- The RPC [sign](https://ripple.com/build/rippled-apis/#sign) command will now sign with either an account's master or regular secret key. -- Fixed out-of-order network initialization. -- Improved efficiency of pathfinding for transactions. -- Reworked timing of ledger validation and related operations to fix race condition against the network. -- Build process enforces minimum versions of OpenSSL and BOOST for operation. - - ------------------------------------------------------------ - -## Version 0.23.0 - -rippled version 0.23.0 has been released. The repository tag is **0.23.0** and can be found on GitHub at: - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 29a4f61551236f70865d46d6653da2e62de1c701 - Author: Vinnie Falco - Date: Fri Mar 14 13:01:23 2014 -0700 - - Set version to 0.23.0 - -This release incorporates significant improvements which may not warrant separate entries but are incorporated into the feature changes as summary lines. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/develop) for more information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -A minimum of 4GB of RAM are required to successfully compile this release. - -The minimum supported version of Boost is v1.55. You **must** upgrade to this release or later to successfully compile this release. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Improvements** - -- Allow the word 'none' in the *.cfg* file to disable storing historical ledgers. -- Clarify the initialization of hash prefixes used in the *RadMap*. -- Better validation of RPC-JSON from all sources -- Reduce spurious log output from Peers -- Eliminated some I/O for certain operations in the *RadMap*. -- Client requests for full state trees now require administrative privileges. -- Added "MemoData" field for transaction memos. -- Prevent the node cache from overflowing needlessly in certain cases -- Add "ledger\_data" command for retrieving entire ledgers in chunks. -- Reduce the quantity of forwarded transactions and proposals in some cases -- Improved diagnostics when errors occur loading SSL certificates - -**Bug Fixes** - -- Fix rare crash when a race condition involving disconnecting sockets occurs -- Fix a corner case with hex conversion of strings with odd character lengths -- Fix an exception in a corner case when erroneous transactions were being logged -- Fix the treatment of expired offers when cleaning up offers -- Prevent a needless transactor from being created if the tx ID is not valid -- Fix the peer action transition from "syncing" to "full" -- Fix error reporting for unknown inner JSON fields -- Fix source file path displayed when an assertion failure is reported -- Fix typos in transaction engine error code identifiers - - ------------------------------------------------------------ - -## Version 0.22.0 - -rippled version 0.22.0 has been released. This release is currently the tip of the **develop/** branch and can be found on GitHub at: The tag is **0.22.0** and can be found on GitHub at: - -**This is a critical release affecting transaction processing. All partners should update immediately.** - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - -This release incorporates significant improvements which may not warrant separate entries but are incorporated into the feature changes as summary lines. Please refer to the [Git commit history](https://github.com/ripple/rippled/commits/develop) for more information. - -**Toolchain support** - -The minimum supported version of GCC used to compile rippled is v4.8. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8) if you have not upgraded already. - -A minimum of 4GB of RAM are required to successfully compile this release. - -The minimum supported version of libBOOST is v1.55. You **must** upgrade to this release or later to successfully compile this release. Please follow [these instructions](https://wiki.ripple.com/Ubuntu_build_instructions#Install_Boost) if you have not upgraded already. - -**Key release features** - -- **PeerFinder** - - - Actively guides network topology. - - Scrubs listening advertisements based on connectivity checks. - - Redirection for new nodes when existing nodes are full. - -- **Memos** - - - Transactions can optionally include a short text message, which optionally can be encrypted. - -- **Database** - - - Improved management of I/O resources. - - Better performance accessing historical data. - -- **PathFinding** - - - More efficient search algorithm when computing paths - -**Major Partner Issues Fixed** - -- **Transactions** - - - Malleability: Ability to ensure that signatures are fully canonical. - -- **PathFinding** - - - Less time needed to get the first path result! - -- **Database** - - - Eliminated "meltdowns" caused when fetching historical ledger data. - -**Significant Changes** - -- Cleaned up logic which controls when ledgers are fetched and under what conditions. -- Cleaned up file path calculation for database files. -- Changed dispatcher for WebSocket requests. -- Cleaned up multithreading mechanisms. -- Fixed custom currency code parsing. -- Optimized transaction node lookup circumstances in the node store. - - ------------------------------------------------------------ - -## Version 0.21.0 - -rippled version 0.21.0 has been released. This release is currently the tip of the **develop/** branch and can be found on GitHub at [1](https://github.com/ripple/rippled/tree/develop). The tag is **0.21.0-rc2** and can be found on GitHub at [2](https://github.com/ripple/rippled/tree/0.21.0-rc2). - -**This is a critical release. All partners should update immediately.** - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit f295bb20a16d1d2999f606c1297c8930d8e33c40 - Author: JoelKatz - Date: Fri Jan 24 11:17:16 2014 -0800 - - Set version to 0.21.0.rc2 - -**Major Partner Issues Fixed** - -- Order book issues - - Ensure all crossing offers are taken - - Ensure order book is not left crossed -- Added **DeliveredAmount** field to transaction metadata - - Reports amount delivered in partial payments - -**Toolchain support** - -As with the previous release, the minimum supported version of GCC used to compile rippled is v4.8. - -**Significant Changes** - -- Pairwise no-ripple - - Permits trust lines to be protected from rippling - - Operates on protected pairs -- Performance improvements - - Improve I/O latency - - Improve fetching ledgers - - Improve pathfinding -- Features for robust transaction submission - - LastLedgerSeq for transaction expiration - - AccountTxnID for transaction chaining -- Fix some cases where an invalid transaction would stay in limbo -- Code cleanups -- Better reporting of invalid parameters - -**Release Candidates** - -RC1 fixed performance problems with order book retrieval. - -RC2 fixed a bug that caused crashes in order processing and a bug in parsing order book requests. - -**Notice** - -If you are upgrading from version 0.12 or earlier of rippled, these next sections apply to you because the format of the *rippled.cfg* file changed around that time. If you have upgraded since that time and you have applied the configuration file fixes, you can safely ignore them. - -**Validators** - -Ripple Labs is now running five validators. You can use this template for your *validators.txt* file (or place this in your config file): - - [validators] - n9KPnVLn7ewVzHvn218DcEYsnWLzKerTDwhpofhk4Ym1RUq4TeGw RIP1 - n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V RIP2 - n94rSdgTyBNGvYg8pZXGuNt59Y5bGAZGxbxyvjDaqD9ceRAgD85P RIP3 - n9LeQeDcLDMZKjx1TZtrXoLBLo5q1bR1sUQrWG7tEADFU6R27UBp RIP4 - n9KF6RpvktjNs2MDBkmxpJbup4BKrKeMKDXPhaXkq7cKTwLmWkFr RIP5 - -You should also raise your quorum to at least three by putting the following in your *rippled.cfg* file: - - [validation_quorum] - 3 - -If you are a validator, you should set your quorum to at least four. - -**IPs** - -A list of Ripple Labs server IP addresses can be found by resolving **r.ripple.com**. You can also add this to your *rippled.cfg* file to ensure you always have several peer connections to Ripple Labs servers: - - [ips] - 184.73.226.101 51235 - 23.23.201.55 51235 - 54.200.43.173 51235 - 184.73.57.84 51235 - 54.234.249.55 51235 - 54.200.86.110 51235 - -**RocksDB back end** - -RocksDB is based on LevelDB with improvements from Facebook and the community. Preliminary tests show that it stalls less often than HyperLevelDB for our use cases. - -If you are switching over from an existing back end, you have two options. You can remove your old database and let rippled recreate it as it re-syncs, or you can import your old database into the new one. - -To remove your old database, make sure the server is shut down (\`rippled stop\`). Remove the *db/ledger.db* and *db/transaction.db* files. Remove all the files in your back end store directory (*db/hashnode* by default). Then change your configuration file to use the RocksDB back end and restart. - -To import your old database, start by shutting the server down. Then modify the configuration file by renaming your *\[node\_db\]* stanza to *\[import\_db\]*. Create a new *\[node\_db\]* stanza and specify a RocksDB back end with a different directory. Start the server with the command **rippled --import**. When the import finishes gracefully stop the server (\`rippled stop\`). Please wait for rippled to stop on its own because it can take several minutes for it to shut down after an import. Remove the old database, put the new database into place, remove the *\[import\_db\]* section, change the *\[node\_db\]* section to refer to the final location, and restart the server. - -The recommended RocksDB configuration is: - - [node_db] - type=RocksDB - path=db/hashnode - open_files=1200 - filter_bits=12 - cache_mb=128 - file_size_mb=8 - file_size_mult=2 - -**Configuring your Node DB** - -You need to configure the [NodeBackEnd](https://wiki.ripple.com/NodeBackEnd) that you want the server to use. See above for an example RocksDB configuration. - -- **Note**: HyperLevelDB and RocksDB are not available on Windows platform. - - ------------------------------------------------------------ - -## Version 0.20.1 - -rippled version 0.20.1 has been released. This release is currently the tip of the [develop](https://github.com/ripple/rippled/tree/develop) branch and the tag is [0.20.1](https://github.com/ripple/rippled/tree/0.20.1). - -**This is a critical release. All partners should update immediately.** - -Prior to building, please confirm you have the correct source tree with the **git log** command. The first log entry should be the change setting the version: - - commit 95a573b755219d7e1e078d53b8e11a8f0d7cade1 - Author: Vinnie Falco - Date: Wed Jan 8 17:08:27 2014 -0800 - - Set version to 0.20.1 - -**Major Partner Issues Fixed** - -- rippled will crash randomly. - - Entries in the three parts of the order book are missing or do not match. In such a case, rippled will crash. -- Server loses sync randomly. - - This is due to rippled restarting after it crashes. That the server restarted is not obvious and appears to be something else. -- Server goes 'offline' randomly. - - This is due to rippled restarting after it crashes. That the server restarted is not obvious and appears to be something else. -- **complete\_ledgers** part of **server\_info** output says "None". - - This is due to rippled restarting and reconstructing the ledger after it crashes. - - If the node back end is corrupted or has been moved without being renamed in rippled.cfg, this can cause rippled to crash and restart. - -**Toolchain support** - -Starting with this release, the minimum supported version of GCC used to compile rippled is v4.8. - -**Significant Changes** - -- Don't log StatsD messages to the console by default. -- Fixed missing jtACCEPT job limit. -- Removed dead code to clean up the codebase. -- Reset liquidity before retrying rippleCalc. -- Made improvements becuase items in SHAMaps are immutable. -- Multiple pathfinding bugfixes: - - Make each path request track whether it needs updating. - - Improve new request handling, reverse order for processing requests. - - Break to handle new requests immediately. - - Make mPathFindThread an integer rather than a bool. Allow two threads. - - Suspend processing requests if server is backed up. - - Multiple performance improvements and enhancements. - - Fixed locking. -- Refactored codebase to make it C++11 compliant. -- Multiple fixes to ledger acquisition, cleanup, and logging. -- Made multiple improvements to WebSockets server. -- Added Debian-style initscript (doc/rippled.init). -- Updated default config file (doc/rippled-example.cfg) to reflect best practices. -- Made changes to SHAMapTreeNode and visitLeavesInternal to conserve memory. -- Implemented new fee schedule: - - Transaction fee: 10 drops - - Base reserve: 20 XRP - - Incremental reserve: 5 XRP -- Fixed bug \#211 (getTxsAccountB in NetworkOPs). -- Fixed a store/fetch race condition in ther node back end. -- Fixed multiple comparison operations. -- Removed Sophia and Lightning databases. - -**Notice** - -If you are upgrading from version 0.12 or earlier of rippled, these next sections apply to you because the format of the *rippled.cfg* file changed around that time. If you have upgraded since that time and you have applied the configuration file fixes, you can safely ignore them. - -**Validators** - -Ripple Labs is now running five validators. You can use this template for your *validators.txt* file (or place this in your config file): - - [validators] - n9KPnVLn7ewVzHvn218DcEYsnWLzKerTDwhpofhk4Ym1RUq4TeGw RIP1 - n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V RIP2 - n94rSdgTyBNGvYg8pZXGuNt59Y5bGAZGxbxyvjDaqD9ceRAgD85P RIP3 - n9LeQeDcLDMZKjx1TZtrXoLBLo5q1bR1sUQrWG7tEADFU6R27UBp RIP4 - n9KF6RpvktjNs2MDBkmxpJbup4BKrKeMKDXPhaXkq7cKTwLmWkFr RIP5 - -You should also raise your quorum to at least three by putting the following in your *rippled.cfg* file: - - [validation_quorum] - 3 - -If you are a validator, you should set your quorum to at least four. - -**IPs** - -A list of Ripple Labs server IP addresses can be found by resolving **r.ripple.com**. You can also add this to your *rippled.cfg* file to ensure you always have several peer connections to Ripple Labs servers: - - [ips] - 54.225.112.220 51235 - 54.225.123.13 51235 - 54.227.239.106 51235 - 107.21.251.218 51235 - 184.73.226.101 51235 - 23.23.201.55 51235 - -**New RocksDB back end** - -RocksDB is based on LevelDB with improvements from Facebook and the community. Preliminary tests show that it stalls less often than HyperLevelDB for our use cases. - -If you are switching over from an existing back end, you have two options. You can remove your old database and let rippled recreate it as it re-syncs, or you can import your old database into the new one. - -To remove your old database, make sure the server is shut down (`rippled stop`). Remove the *db/ledger.db* and *db/transaction.db* files. Remove all the files in your back end store directory (*db/hashnode* by default). Then change your configuration file to use the RocksDB back end and restart. - -To import your old database, start by shutting the server down. Then modify the configuration file by renaming your *\[node\_db\]* stanza to *\[import\_db\]*. Create a new *\[node\_db\]* stanza and specify a RocksDB back end with a different directory. Start the server with the command **rippled --import**. When the import finishes gracefully stop the server (`rippled stop`). Please wait for rippled to stop on its own because it can take several minutes for it to shut down after an import. Remove the old database, put the new database into place, remove the *\[import\_db\]* section, change the *\[node\_db\]* section to refer to the final location, and restart the server. - -The recommended RocksDB configuration is: - - [node_db] - type=RocksDB - path=db/hashnode - open_files=1200 - filter_bits=12 - cache_mb=256 - file_size_mb=8 - file_size_mult=2 - -**Configuring your Node DB** - -You need to configure the [NodeBackEnd](https://wiki.ripple.com/NodeBackEnd) that you want the server to use. See above for an example RocksDB configuration. - -- **Note**: HyperLevelDB and RocksDB are not available on Windows platform. - - ------------------------------------------------------------ - -## Version 0.19 - -rippled version 0.19 has now been released. This release is currently the tip of the [release](https://github.com/ripple/rippled/tree/release) branch and the tag is [0.19.0](https://github.com/ripple/rippled/tree/0.19.0). - -Prior to building, please confirm you have the correct source tree with the `git log` command. The first log entry should be the change setting the version: - - commit 26783607157a8b96e6e754f71565f4eb0134efc1 - Author: Vinnie Falco - Date: Fri Nov 22 23:36:50 2013 -0800 - - Set version to 0.19.0 - -**Significant Changes** - -- Bugfixes and improvements in path finding, path filtering, and payment execution. -- Updates to HyperLevelDB and LevelDB node storage back ends. -- Addition of RocksDB node storage back end. -- New resource manager for tracking server load. -- Fixes for a few bugs that can crashes or inability to serve client requests. - -**Validators** - -Ripple Labs is now running five validators. You can use this template for your `validators.txt` file (or place this in your config file): - - [validators] - n9KPnVLn7ewVzHvn218DcEYsnWLzKerTDwhpofhk4Ym1RUq4TeGw RIP1 - n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V RIP2 - n94rSdgTyBNGvYg8pZXGuNt59Y5bGAZGxbxyvjDaqD9ceRAgD85P RIP3 - n9LeQeDcLDMZKjx1TZtrXoLBLo5q1bR1sUQrWG7tEADFU6R27UBp RIP4 - n9KF6RpvktjNs2MDBkmxpJbup4BKrKeMKDXPhaXkq7cKTwLmWkFr RIP5 - -You should also raise your quorum to at least three by putting the following in your `rippled.cfg` file: - - [validation_quorum] - 3 - -If you are a validator, you should set your quorum to at least four. - -**IPs** - -A list of Ripple Labs server IP addresses can be found by resolving `r.ripple.com`. You can also add this to your `rippled.cfg` file to ensure you always have several peer connections to Ripple Labs servers: - - [ips] - 54.225.112.220 51235 - 54.225.123.13 51235 - 54.227.239.106 51235 - 107.21.251.218 51235 - 184.73.226.101 51235 - 23.23.201.55 51235 - -**New RocksDB back end** - -RocksDB is based on LevelDB with improvements from Facebook and the community. Preliminary tests show that it stall less often than HyperLevelDB. - -If you are switching over from an existing back end, you have two choices. You can remove your old database or you can import it. - -To remove your old database, make sure the server is shutdown. Remove the `db/ledger.db` and `db/transaction.db` files. Remove all the files in your back end store directory, `db/hashnode` by default. Then you can change your configuration file to use the RocksDB back end and restart. - -To import your old database, start by shutting the server down. Then modify the configuration file by renaming your `[node_db]` portion to `[import_db]`. Create a new `[node_db]` section specify a RocksDB back end and a different directory. Start the server with `rippled --import`. When the import finishes, stop the server (it can take several minutes to shut down after an import), remove the old database, put the new database into place, remove the `[import_db]` section, change the `[node_db]` section to refer to the final location, and restart the server. - -The recommended RocksDB configuration is: - - [node_db] - type=RocksDB - path=db/hashnode - open_files=1200 - filter_bits=12 - cache_mb=256 - file_size_mb=8 - file_size_mult=2 - -**Configuring your Node DB** - -You need to configure the [NodeBackEnd](https://wiki.ripple.com/NodeBackEnd) that you want the server to use. See above for an example RocksDB configuration. - -- **Note:** HyperLevelDB and RocksDB are not available on Windows platform. - - ------------------------------------------------------------ - -## Version 0.16 - -rippled version 0.16 has now been released. This release is currently the tip of the [master](https://github.com/ripple/rippled/tree/master) branch and the tag is [v0.16.0](https://github.com/ripple/rippled/tree/v0.16.0). - -Prior to building, please confirm you have the correct source tree with the `git log` command. The first log entry should be the change setting the version: - - commit 15ef43505473225af21bb7b575fb0b628d5e7f73 - Author: vinniefalco - Date: Wed Oct 2 2013 - - Set version to 0.16.0 - -**Significant Changes** - -- Improved peer discovery -- Improved pathfinding -- Ledger speed improvements -- Reduced memory consumption -- Improved server stability -- rippled no longer throws and exception on exiting -- Better error reporting -- Ripple-lib tests have been ported to use the Mocha testing framework - -**Validators** - -Ripple Labs is now running five validators. You can use this template for your `validators.txt` file: - - [validators] - n9KPnVLn7ewVzHvn218DcEYsnWLzKerTDwhpofhk4Ym1RUq4TeGw RIP1 - n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V RIP2 - n94rSdgTyBNGvYg8pZXGuNt59Y5bGAZGxbxyvjDaqD9ceRAgD85P RIP3 - n9LeQeDcLDMZKjx1TZtrXoLBLo5q1bR1sUQrWG7tEADFU6R27UBp RIP4 - n9KF6RpvktjNs2MDBkmxpJbup4BKrKeMKDXPhaXkq7cKTwLmWkFr RIP5 - -You should also raise your quorum to at least three by putting the following in your `rippled.cfg` file: - - [validation_quorum] - 3 - -If you are a validator, you should set your quorum to at least four. - -**IPs** - -A list of Ripple Labs server IP addresses can be found by resolving `r.ripple.com`. You can also add this to your `rippled.cfg` file to ensure you always have several peer connections to Ripple Labs servers: - - [ips] - 54.225.112.220 51235 - 54.225.123.13 51235 - 54.227.239.106 51235 - 107.21.251.218 51235 - 184.73.226.101 51235 - 23.23.201.55 51235 - -**Node DB** - -You need to configure the [NodeBackEnd](https://wiki.ripple.com/NodeBackEnd) that you want the server to use. In most cases, that will mean adding this to your configuration file: - - [node_db] - type=HyperLevelDB - path=db/hashnode - -- NOTE HyperLevelDB is not available on Windows platforms. - -**Release Candidates** - -**Issues** - -None known - - ------------------------------------------------------------ - -## Version 0.14 - -rippled version 0.14 has now been released. This release is currently the tip of the [master](https://github.com/ripple/rippled/tree/master) branch and the tag is [v0.12.0](https://github.com/ripple/rippled/tree/v0.14.0). - -Prior to building, please confirm you have the correct source tree with the `git log` command. The first log entry should be the change setting the version: - - commit b6d11c08d0245ee9bafbb97143f5d685dd2979fc - Author: vinniefalco - Date: Wed Oct 2 2013 - - Set version to 0.14.0 - -**Significant Changes** - -- Improved peer discovery -- Improved pathfinding -- Ledger speed improvements -- Reduced memory consumption -- Improved server stability -- rippled no longer throws and exception on exiting -- Better error reporting -- Ripple-lib tests have been ported to use the Mocha testing framework - -**Validators** - -Ripple Labs is now running five validators. You can use this template for your `validators.txt` file: - - [validators] - n9KPnVLn7ewVzHvn218DcEYsnWLzKerTDwhpofhk4Ym1RUq4TeGw RIP1 - n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V RIP2 - n94rSdgTyBNGvYg8pZXGuNt59Y5bGAZGxbxyvjDaqD9ceRAgD85P RIP3 - n9LeQeDcLDMZKjx1TZtrXoLBLo5q1bR1sUQrWG7tEADFU6R27UBp RIP4 - n9KF6RpvktjNs2MDBkmxpJbup4BKrKeMKDXPhaXkq7cKTwLmWkFr RIP5 - -You should also raise your quorum to at least three by putting the following in your `rippled.cfg` file: - - [validation_quorum] - 3 - -If you are a validator, you should set your quorum to at least four. - -**IPs** - -A list of Ripple Labs server IP addresses can be found by resolving `r.ripple.com`. You can also add this to your `rippled.cfg` file to ensure you always have several peer connections to Ripple Labs servers: - - [ips] - 54.225.112.220 51235 - 54.225.123.13 51235 - 54.227.239.106 51235 - 107.21.251.218 51235 - 184.73.226.101 51235 - 23.23.201.55 51235 - -**Node DB** - -You need to configure the [NodeBackEnd](https://wiki.ripple.com/NodeBackEnd) that you want the server to use. In most cases, that will mean adding this to your configuration file: - - [node_db] - type=HyperLevelDB - path=db/hashnode - -- NOTE HyperLevelDB is not available on Windows platforms. - -**Release Candidates** - -**Issues** - -None known - - ------------------------------------------------------------ - -## Version 0.12 - -rippled version 0.12 has now been released. This release is currently the tip of the [master branch](https://github.com/ripple/rippled/tree/master) and can be found on GitHub. The tag is [v0.12.0](https://github.com/ripple/rippled/tree/v0.12.0). - -Prior to building, please confirm you have the correct source tree with the `git log` command. The first log entry should be the change setting the version: - - commit d0a9da6f16f4083993e4b6c5728777ffebf80f3a - Author: JoelKatz - Date: Mon Aug 26 12:08:05 2013 -0700 - - Set version to v0.12.0 - -**Major Partner Issues Fixed** - -- Server Showing "Offline" - -This issue was caused by LevelDB periodically compacting its internal data structure. While compacting, rippled's processing would stall causing the node to lose sync with the rest of the network. This issue was solved by switching from LevelDB to HyperLevelDB. rippled operators will need to change their ripple.cfg file. See below for configuration details. - -- Premature Validation of Transactions - -On rare occasions, a transaction would show as locally validated before the full network consensus was confirmed. This issue was resolved by changing the way transactions are saved. - -- Missing Ledgers - -Occasionally, some rippled servers would fail to fetch all ledgers. This left gaps in the local history and caused some API calls to report incomplete results. The ledger fetch code was rewritten to both prevent this and to repair any existing gaps. - -**Significant Changes** - -- The way transactions are saved has been changed. This fixes a number of ways transactions can incorrectly be reported as fully-validated. -- `doTransactionEntry` now works against open ledgers. -- `doLedgerEntry` now supports a binary option. -- A bug in `getBookPage` that caused it to skip offers is fixed. -- `getNodeFat` now returns deeper chains, reducing ledger acquire latency. -- Catching up if the (published ledger stream falls behind the network) is now more aggressive. -- I/O stalls are drastically reduced by using the HyperLevelDB node back end. -- Persistent ledger gaps should no longer occur. -- Clusters now exchange load information. - -**Validators** - -Ripple Labs is now running five validators. You can use this template for your `validators.txt` file: - - - - [validators] - n9KPnVLn7ewVzHvn218DcEYsnWLzKerTDwhpofhk4Ym1RUq4TeGw RIP1 - n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V RIP2 - n94rSdgTyBNGvYg8pZXGuNt59Y5bGAZGxbxyvjDaqD9ceRAgD85P RIP3 - n9LeQeDcLDMZKjx1TZtrXoLBLo5q1bR1sUQrWG7tEADFU6R27UBp RIP4 - n9KF6RpvktjNs2MDBkmxpJbup4BKrKeMKDXPhaXkq7cKTwLmWkFr RIP5 - - - -**Update April 2014** - Due to a vulnerability in OpenSSL the validator keys above have been cycled out, the five validators by RippleLabs use the following keys now: - - [validators] - n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1 - n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2 - n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3 - n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4 - n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5 - -You should also raise your quorum to at least three by putting the following in your `rippled.cfg` file: - - [validation_quorum] - 3 - -If you are a validator, you should set your quorum to at least four. - -**IPs** - -A list of Ripple Labs server IP addresses can be found by resolving `r.ripple.com`. You can also add this to your `rippled.cfg` file to ensure you always have several peer connections to Ripple Labs servers: - - [ips] - 54.225.112.220 51235 - 54.225.123.13 51235 - 54.227.239.106 51235 - 107.21.251.218 51235 - 184.73.226.101 51235 - 23.23.201.55 51235 - -**Node DB** - -You need to configure the [NodeBackEnd](https://wiki.ripple.com/NodeBackEnd) that you want the server to use. In most cases, that will mean adding this to your configuration file: - - [node_db] - type=HyperLevelDB - path=db/hashnode - -- NOTE HyperLevelDB is not available on Windows platforms. - -**Release Candidates** - -RC1 was the first release candidate. - -RC2 fixed a bug that could cause ledger acquires to stall. - -RC3 fixed compilation under OSX. - -RC4 includes performance improvements in countAccountTx and numerous small fixes to ledger acquisition. - -RC5 changed the peer low water mark from 4 to 10 to acquire more server connections. - -RC6 fixed some possible load issues with the network state timer and cluster reporting timers. - -**Issues** - -Fetching of historical ledgers is slower in this build than in previous builds. This is being investigated. diff --git a/SECURITY.md b/SECURITY.md index eb7437d2f9d..3fd85bad0a4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,6 @@ For more details on operating an XRP Ledger server securely, please visit https://xrpl.org/manage-the-rippled-server.html. - # Security Policy ## Supported Versions @@ -77,13 +76,14 @@ The amount paid varies dramatically. Vulnerabilities that are harmless on their To report a qualifying bug, please send a detailed report to: -|Email Address|bugs@ripple.com | -|:-----------:|:----------------------------------------------------| -|Short Key ID | `0xC57929BE` | -|Long Key ID | `0xCD49A0AFC57929BE` | -|Fingerprint | `24E6 3B02 37E0 FA9C 5E96 8974 CD49 A0AF C579 29BE` | +| Email Address | bugs@ripple.com | +| :-----------: | :-------------------------------------------------- | +| Short Key ID | `0xC57929BE` | +| Long Key ID | `0xCD49A0AFC57929BE` | +| Fingerprint | `24E6 3B02 37E0 FA9C 5E96 8974 CD49 A0AF C579 29BE` | + +The full PGP key for this address, which is also available on several key servers (e.g. on [keyserver.ubuntu.com](https://keyserver.ubuntu.com)), is: -The full PGP key for this address, which is also available on several key servers (e.g. on [keyserver.ubuntu.com](https://keyserver.ubuntu.com)), is: ``` -----BEGIN PGP PUBLIC KEY BLOCK----- mQINBFUwGHYBEAC0wpGpBPkd8W1UdQjg9+cEFzeIEJRaoZoeuJD8mofwI5Ejnjdt diff --git a/bin/browser.js b/bin/browser.js deleted file mode 100755 index 81618bd0028..00000000000 --- a/bin/browser.js +++ /dev/null @@ -1,470 +0,0 @@ -#!/usr/bin/node -// -// ledger?l=L -// transaction?h=H -// ledger_entry?l=L&h=H -// account?l=L&a=A -// directory?l=L&dir_root=H&i=I -// directory?l=L&o=A&i=I // owner directory -// offer?l=L&offer=H -// offer?l=L&account=A&i=I -// ripple_state=l=L&a=A&b=A&c=C -// account_lines?l=L&a=A -// -// A=address -// C=currency 3 letter code -// H=hash -// I=index -// L=current | closed | validated | index | hash -// - -var async = require("async"); -var extend = require("extend"); -var http = require("http"); -var url = require("url"); - -var Remote = require("ripple-lib").Remote; - -var program = process.argv[1]; - -var httpd_response = function (res, opts) { - var self=this; - - res.statusCode = opts.statusCode; - res.end( - "" - + "Title" - + "" - + "State:" + self.state - + "" - + (opts.body || '') - + '
'
-      + (opts.url || '')
-      + '
' - + "" - + "" - ); -}; - -var html_link = function (generic) { - return '' + generic + ''; -}; - -// Build a link to a type. -var build_uri = function (params, opts) { - var c; - - if (params.type === 'account') { - c = { - pathname: 'account', - query: { - l: params.ledger, - a: params.account, - }, - }; - - } else if (params.type === 'ledger') { - c = { - pathname: 'ledger', - query: { - l: params.ledger, - }, - }; - - } else if (params.type === 'transaction') { - c = { - pathname: 'transaction', - query: { - h: params.hash, - }, - }; - } else { - c = {}; - } - - opts = opts || {}; - - c.protocol = "http"; - c.hostname = opts.hostname || self.base.hostname; - c.port = opts.port || self.base.port; - - return url.format(c); -}; - -var build_link = function (item, link) { -console.log(link); - return "" + item + ""; -}; - -var rewrite_field = function (type, obj, field, opts) { - if (field in obj) { - obj[field] = rewrite_type(type, obj[field], opts); - } -}; - -var rewrite_type = function (type, obj, opts) { - if ('amount' === type) { - if ('string' === typeof obj) { - // XRP. - return '' + obj + ''; - - } else { - rewrite_field('address', obj, 'issuer', opts); - - return obj; - } - return build_link( - obj, - build_uri({ - type: 'account', - account: obj - }, opts) - ); - } - if ('address' === type) { - return build_link( - obj, - build_uri({ - type: 'account', - account: obj - }, opts) - ); - } - else if ('ledger' === type) { - return build_link( - obj, - build_uri({ - type: 'ledger', - ledger: obj, - }, opts) - ); - } - else if ('node' === type) { - // A node - if ('PreviousTxnID' in obj) - obj.PreviousTxnID = rewrite_type('transaction', obj.PreviousTxnID, opts); - - if ('Offer' === obj.LedgerEntryType) { - if ('NewFields' in obj) { - if ('TakerGets' in obj.NewFields) - obj.NewFields.TakerGets = rewrite_type('amount', obj.NewFields.TakerGets, opts); - - if ('TakerPays' in obj.NewFields) - obj.NewFields.TakerPays = rewrite_type('amount', obj.NewFields.TakerPays, opts); - } - } - - obj.LedgerEntryType = '' + obj.LedgerEntryType + ''; - - return obj; - } - else if ('transaction' === type) { - // Reference to a transaction. - return build_link( - obj, - build_uri({ - type: 'transaction', - hash: obj - }, opts) - ); - } - - return 'ERROR: ' + type; -}; - -var rewrite_object = function (obj, opts) { - var out = extend({}, obj); - - rewrite_field('address', out, 'Account', opts); - - rewrite_field('ledger', out, 'parent_hash', opts); - rewrite_field('ledger', out, 'ledger_index', opts); - rewrite_field('ledger', out, 'ledger_current_index', opts); - rewrite_field('ledger', out, 'ledger_hash', opts); - - if ('ledger' in obj) { - // It's a ledger header. - out.ledger = rewrite_object(out.ledger, opts); - - if ('ledger_hash' in out.ledger) - out.ledger.ledger_hash = '' + out.ledger.ledger_hash + ''; - - delete out.ledger.hash; - delete out.ledger.totalCoins; - } - - if ('TransactionType' in obj) { - // It's a transaction. - out.TransactionType = '' + obj.TransactionType + ''; - - rewrite_field('amount', out, 'TakerGets', opts); - rewrite_field('amount', out, 'TakerPays', opts); - rewrite_field('ledger', out, 'inLedger', opts); - - out.meta.AffectedNodes = out.meta.AffectedNodes.map(function (node) { - var kind = 'CreatedNode' in node - ? 'CreatedNode' - : 'ModifiedNode' in node - ? 'ModifiedNode' - : 'DeletedNode' in node - ? 'DeletedNode' - : undefined; - - if (kind) { - node[kind] = rewrite_type('node', node[kind], opts); - } - return node; - }); - } - else if ('node' in obj && 'LedgerEntryType' in obj.node) { - // Its a ledger entry. - - if (obj.node.LedgerEntryType === 'AccountRoot') { - rewrite_field('address', out.node, 'Account', opts); - rewrite_field('transaction', out.node, 'PreviousTxnID', opts); - rewrite_field('ledger', out.node, 'PreviousTxnLgrSeq', opts); - } - - out.node.LedgerEntryType = '' + out.node.LedgerEntryType + ''; - } - - return out; -}; - -var augment_object = function (obj, opts, done) { - if (obj.node.LedgerEntryType == 'AccountRoot') { - var tx_hash = obj.node.PreviousTxnID; - var tx_ledger = obj.node.PreviousTxnLgrSeq; - - obj.history = []; - - async.whilst( - function () { return tx_hash; }, - function (callback) { -// console.log("augment_object: request: %s %s", tx_hash, tx_ledger); - opts.remote.request_tx(tx_hash) - .on('success', function (m) { - tx_hash = undefined; - tx_ledger = undefined; - -//console.log("augment_object: ", JSON.stringify(m)); - m.meta.AffectedNodes.filter(function(n) { -// console.log("augment_object: ", JSON.stringify(n)); -// if (n.ModifiedNode) -// console.log("augment_object: %s %s %s %s %s %s/%s", 'ModifiedNode' in n, n.ModifiedNode && (n.ModifiedNode.LedgerEntryType === 'AccountRoot'), n.ModifiedNode && n.ModifiedNode.FinalFields && (n.ModifiedNode.FinalFields.Account === obj.node.Account), Object.keys(n)[0], n.ModifiedNode && (n.ModifiedNode.LedgerEntryType), obj.node.Account, n.ModifiedNode && n.ModifiedNode.FinalFields && n.ModifiedNode.FinalFields.Account); -// if ('ModifiedNode' in n && n.ModifiedNode.LedgerEntryType === 'AccountRoot') -// { -// console.log("***: ", JSON.stringify(m)); -// console.log("***: ", JSON.stringify(n)); -// } - return 'ModifiedNode' in n - && n.ModifiedNode.LedgerEntryType === 'AccountRoot' - && n.ModifiedNode.FinalFields - && n.ModifiedNode.FinalFields.Account === obj.node.Account; - }) - .forEach(function (n) { - tx_hash = n.ModifiedNode.PreviousTxnID; - tx_ledger = n.ModifiedNode.PreviousTxnLgrSeq; - - obj.history.push({ - tx_hash: tx_hash, - tx_ledger: tx_ledger - }); -console.log("augment_object: next: %s %s", tx_hash, tx_ledger); - }); - - callback(); - }) - .on('error', function (m) { - callback(m); - }) - .request(); - }, - function (err) { - if (err) { - done(); - } - else { - async.forEach(obj.history, function (o, callback) { - opts.remote.request_account_info(obj.node.Account) - .ledger_index(o.tx_ledger) - .on('success', function (m) { -//console.log("augment_object: ", JSON.stringify(m)); - o.Balance = m.account_data.Balance; -// o.account_data = m.account_data; - callback(); - }) - .on('error', function (m) { - o.error = m; - callback(); - }) - .request(); - }, - function (err) { - done(err); - }); - } - }); - } - else { - done(); - } -}; - -if (process.argv.length < 4 || process.argv.length > 7) { - console.log("Usage: %s ws_ip ws_port [ [ []]]", program); -} -else { - var ws_ip = process.argv[2]; - var ws_port = process.argv[3]; - var ip = process.argv.length > 4 ? process.argv[4] : "127.0.0.1"; - var port = process.argv.length > 5 ? process.argv[5] : "8080"; - -// console.log("START"); - var self = this; - - var remote = (new Remote({ - websocket_ip: ws_ip, - websocket_port: ws_port, - trace: false - })) - .on('state', function (m) { - console.log("STATE: %s", m); - - self.state = m; - }) -// .once('ledger_closed', callback) - .connect() - ; - - self.base = { - hostname: ip, - port: port, - remote: remote, - }; - -// console.log("SERVE"); - var server = http.createServer(function (req, res) { - var input = ""; - - req.setEncoding(); - - req.on('data', function (buffer) { - // console.log("DATA: %s", buffer); - input = input + buffer; - }); - - req.on('end', function () { - // console.log("URL: %s", req.url); - // console.log("HEADERS: %s", JSON.stringify(req.headers, undefined, 2)); - - var _parsed = url.parse(req.url, true); - var _url = JSON.stringify(_parsed, undefined, 2); - - // console.log("HEADERS: %s", JSON.stringify(_parsed, undefined, 2)); - if (_parsed.pathname === "/account") { - var request = remote - .request_ledger_entry('account_root') - .ledger_index(-1) - .account_root(_parsed.query.a) - .on('success', function (m) { - // console.log("account_root: %s", JSON.stringify(m, undefined, 2)); - - augment_object(m, self.base, function() { - httpd_response(res, - { - statusCode: 200, - url: _url, - body: "
"
-                              + JSON.stringify(rewrite_object(m, self.base), undefined, 2)
-                              + "
" - }); - }); - }) - .request(); - - } else if (_parsed.pathname === "/ledger") { - var request = remote - .request_ledger(undefined, { expand: true, transactions: true }) - .on('success', function (m) { - // console.log("Ledger: %s", JSON.stringify(m, undefined, 2)); - - httpd_response(res, - { - statusCode: 200, - url: _url, - body: "
"
-                          + JSON.stringify(rewrite_object(m, self.base), undefined, 2)
-                          +"
" - }); - }) - - if (_parsed.query.l && _parsed.query.l.length === 64) { - request.ledger_hash(_parsed.query.l); - } - else if (_parsed.query.l) { - request.ledger_index(Number(_parsed.query.l)); - } - else { - request.ledger_index(-1); - } - - request.request(); - - } else if (_parsed.pathname === "/transaction") { - var request = remote - .request_tx(_parsed.query.h) -// .request_transaction_entry(_parsed.query.h) -// .ledger_select(_parsed.query.l) - .on('success', function (m) { - // console.log("transaction: %s", JSON.stringify(m, undefined, 2)); - - httpd_response(res, - { - statusCode: 200, - url: _url, - body: "
"
-                            + JSON.stringify(rewrite_object(m, self.base), undefined, 2)
-                            +"
" - }); - }) - .on('error', function (m) { - httpd_response(res, - { - statusCode: 200, - url: _url, - body: "
"
-                            + 'ERROR: ' + JSON.stringify(m, undefined, 2)
-                            +"
" - }); - }) - .request(); - - } else { - var test = build_uri({ - type: 'account', - ledger: 'closed', - account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', - }, self.base); - - httpd_response(res, - { - statusCode: req.url === "/" ? 200 : 404, - url: _url, - }); - } - }); - }); - - server.listen(port, ip, undefined, - function () { - console.log("Listening at: http://%s:%s", ip, port); - }); -} - -// vim:sw=2:sts=2:ts=8:et diff --git a/bin/debug_local_sign.js b/bin/debug_local_sign.js deleted file mode 100644 index 24f9aab4814..00000000000 --- a/bin/debug_local_sign.js +++ /dev/null @@ -1,64 +0,0 @@ -var ripple = require('ripple-lib'); - -var v = { - seed: "snoPBrXtMeMyMHUVTgbuqAfg1SUTb", - addr: "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" -}; - -var remote = ripple.Remote.from_config({ - "trusted" : true, - "websocket_ip" : "127.0.0.1", - "websocket_port" : 5006, - "websocket_ssl" : false, - "local_signing" : true -}); - -var tx_json = { - "Account" : v.addr, - "Amount" : "10000000", - "Destination" : "rEu2ULPiEQm1BAL8pYzmXnNX1aFX9sCks", - "Fee" : "10", - "Flags" : 0, - "Sequence" : 3, - "TransactionType" : "Payment" - - //"SigningPubKey": '0396941B22791A448E5877A44CE98434DB217D6FB97D63F0DAD23BE49ED45173C9' -}; - -remote.on('connected', function () { - var req = remote.request_sign(v.seed, tx_json); - req.message.debug_signing = true; - req.on('success', function (result) { - console.log("SERVER RESULT"); - console.log(result); - - var sim = {}; - var tx = remote.transaction(); - tx.tx_json = tx_json; - tx._secret = v.seed; - tx.complete(); - var unsigned = tx.serialize().to_hex(); - tx.sign(); - - sim.tx_blob = tx.serialize().to_hex(); - sim.tx_json = tx.tx_json; - sim.tx_signing_hash = tx.signing_hash().to_hex(); - sim.tx_unsigned = unsigned; - - console.log("\nLOCAL RESULT"); - console.log(sim); - - remote.connect(false); - }); - req.on('error', function (err) { - if (err.error === "remoteError" && err.remote.error === "srcActNotFound") { - console.log("Please fund account "+v.addr+" to run this test."); - } else { - console.log('error', err); - } - remote.connect(false); - }); - req.request(); - -}); -remote.connect(); diff --git a/bin/email_hash.js b/bin/email_hash.js deleted file mode 100755 index ab4f97c47ba..00000000000 --- a/bin/email_hash.js +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/node -// -// Returns a Gravatar style hash as per: http://en.gravatar.com/site/implement/hash/ -// - -if (3 != process.argv.length) { - process.stderr.write("Usage: " + process.argv[1] + " email_address\n\nReturns gravatar style hash.\n"); - process.exit(1); - -} else { - var md5 = require('crypto').createHash('md5'); - - md5.update(process.argv[2].trim().toLowerCase()); - - process.stdout.write(md5.digest('hex') + "\n"); -} - -// vim:sw=2:sts=2:ts=8:et diff --git a/bin/flash_policy.js b/bin/flash_policy.js deleted file mode 100755 index e1361d46dc7..00000000000 --- a/bin/flash_policy.js +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/node -// -// This program allows IE 9 ripple-clients to make websocket connections to -// rippled using flash. As IE 9 does not have websocket support, this required -// if you wish to support IE 9 ripple-clients. -// -// http://www.lightsphere.com/dev/articles/flash_socket_policy.html -// -// For better security, be sure to set the Port below to the port of your -// [websocket_public_port]. -// - -var net = require("net"), - port = "*", - domains = ["*:"+port]; // Domain:Port - -net.createServer( - function(socket) { - socket.write("\n"); - socket.write("\n"); - socket.write("\n"); - domains.forEach( - function(domain) { - var parts = domain.split(':'); - socket.write("\t\n"); - } - ); - socket.write("\n"); - socket.end(); - } -).listen(843); diff --git a/bin/getRippledInfo b/bin/getRippledInfo deleted file mode 100755 index abfa449bac4..00000000000 --- a/bin/getRippledInfo +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env bash - -# This script generates information about your rippled installation -# and system. It can be used to help debug issues that you may face -# in your installation. While this script endeavors to not display any -# sensitive information, it is recommended that you read the output -# before sharing with any third parties. - - -rippled_exe=/opt/ripple/bin/rippled -conf_file=/etc/opt/ripple/rippled.cfg - -while getopts ":e:c:" opt; do - case $opt in - e) - rippled_exe=${OPTARG} - ;; - c) - conf_file=${OPTARG} - ;; - \?) - echo "Invalid option: -$OPTARG" - exit -1 - esac -done - -tmp_loc=$(mktemp -d --tmpdir ripple_info.XXXXX) -chmod 751 ${tmp_loc} -awk_prog=${tmp_loc}/cfg.awk -summary_out=${tmp_loc}/rippled_info.md -printf "# rippled report info\n\n> generated at %s\n" "$(date -R)" > ${summary_out} - -function log_section { - printf "\n## %s\n" "$*" >> ${summary_out} - - while read -r l; do - echo " $l" >> ${summary_out} - done > ${awk_prog} - BEGIN {FS="[[:space:]]*=[[:space:]]*"; skip=0; db_path=""; print > OUT_FILE; split(exl,exa,"|")} - /^#/ {next} - save==2 && /^[[:space:]]*$/ {next} - /^\[.+\]$/ { - section=tolower(gensub(/^\[[[:space:]]*([a-zA-Z_]+)[[:space:]]*\]$/, "\\1", "g")) - skip = 0 - for (i in exa) { - if (section == exa[i]) - skip = 1 - } - if (section == "database_path") - save = 1 - } - skip==1 {next} - save==2 {save=0; db_path=$0} - save==1 {save=2} - $1 ~ /password/ {$0=$1"="} - {print >> OUT_FILE} - END {print db_path} -EOP - - db=$(\ - sed -r -e 's/\//g;s/^[[:space:]]*//;s/[[:space:]]*$//' ${conf_file} |\ - awk -v OUT_FILE=${cleaned_conf} -v exl="$(join_by '|' "${exclude[@]}")" -f ${awk_prog}) - rm ${awk_prog} - cat ${cleaned_conf} | log_section "cleaned config file" - rm ${cleaned_conf} - echo "${db}" | log_section "database path" - df ${db} | log_section "df: database" -fi - -# Send output from this script to a log file -## this captures any messages -## or errors from the script itself - -log_file=${tmp_loc}/get_info.log -exec 3>&1 1>>${log_file} 2>&1 - -## Send all stdout files to /tmp - -if [[ -x ${rippled_exe} ]] ; then - pgrep rippled && \ - ${rippled_exe} --conf ${conf_file} \ - -- server_info | log_section "server info" -fi - -cat /proc/meminfo | log_section "meminfo" -cat /proc/swaps | log_section "swap space" -ulimit -a | log_section "ulimit" - -if command -v lshw >/dev/null 2>&1 ; then - lshw 2>/dev/null | log_section "hardware info" -else - lscpu > ${tmp_loc}/hw_info.txt - hwinfo >> ${tmp_loc}/hw_info.txt - lspci >> ${tmp_loc}/hw_info.txt - lsblk >> ${tmp_loc}/hw_info.txt - cat ${tmp_loc}/hw_info.txt | log_section "hardware info" - rm ${tmp_loc}/hw_info.txt -fi - -if command -v iostat >/dev/null 2>&1 ; then - iostat -t -d -x 2 6 | log_section "iostat" -fi - -df -h | log_section "free disk space" -drives=($(df | awk '$1 ~ /^\/dev\// {print $1}' | xargs -n 1 basename)) -block_devs=($(ls /sys/block/)) -for d in "${drives[@]}"; do - for dev in "${block_devs[@]}"; do - #echo "D: [$d], DEV: [$dev]" - if [[ $d =~ $dev ]]; then - # this file (if exists) has 0 for SSD and 1 for HDD - if [[ "$(cat /sys/block/${dev}/queue/rotational 2>/dev/null)" == 0 ]] ; then - echo "${d} : SSD" >> ${tmp_loc}/is_ssd.txt - else - echo "${d} : NO SSD" >> ${tmp_loc}/is_ssd.txt - fi - fi - done -done - -if [[ -f ${tmp_loc}/is_ssd.txt ]] ; then - cat ${tmp_loc}/is_ssd.txt | log_section "SSD" - rm ${tmp_loc}/is_ssd.txt -fi - -cat ${log_file} | log_section "script log" - -cat << MSG | tee /dev/fd/3 -#################################################### - rippled info has been gathered. Please copy the - contents of ${summary_out} - to a github gist at https://gist.github.com/ - - PLEASE REVIEW THIS FILE FOR ANY SENSITIVE DATA - BEFORE POSTING! We have tried our best to omit - any sensitive information from this file, but you - should verify before posting. -#################################################### -MSG - diff --git a/bin/hexify.js b/bin/hexify.js deleted file mode 100755 index 1e2fb700094..00000000000 --- a/bin/hexify.js +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/node -// -// Returns hex of lowercasing a string. -// - -var stringToHex = function (s) { - return Array.prototype.map.call(s, function (c) { - var b = c.charCodeAt(0); - - return b < 16 ? "0" + b.toString(16) : b.toString(16); - }).join(""); -}; - -if (3 != process.argv.length) { - process.stderr.write("Usage: " + process.argv[1] + " string\n\nReturns hex of lowercasing string.\n"); - process.exit(1); - -} else { - - process.stdout.write(stringToHex(process.argv[2].toLowerCase()) + "\n"); -} - -// vim:sw=2:sts=2:ts=8:et diff --git a/bin/jsonrpc_request.js b/bin/jsonrpc_request.js deleted file mode 100755 index 0b9c08666de..00000000000 --- a/bin/jsonrpc_request.js +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/node -// -// This is a tool to issue JSON-RPC requests from the command line. -// -// This can be used to test a JSON-RPC server. -// -// Requires: npm simple-jsonrpc -// - -var jsonrpc = require('simple-jsonrpc'); - -var program = process.argv[1]; - -if (5 !== process.argv.length) { - console.log("Usage: %s ", program); -} -else { - var url = process.argv[2]; - var method = process.argv[3]; - var json_raw = process.argv[4]; - var json; - - try { - json = JSON.parse(json_raw); - } - catch (e) { - console.log("JSON parse error: %s", e.message); - throw e; - } - - var client = jsonrpc.client(url); - - client.call(method, json, - function (result) { - console.log(JSON.stringify(result, undefined, 2)); - }, - function (error) { - console.log(JSON.stringify(error, undefined, 2)); - }); -} - -// vim:sw=2:sts=2:ts=8:et diff --git a/bin/jsonrpc_server.js b/bin/jsonrpc_server.js deleted file mode 100755 index 4cd3ffb95ca..00000000000 --- a/bin/jsonrpc_server.js +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/node -// -// This is a tool to listen for JSON-RPC requests at an IP and port. -// -// This will report the request to console and echo back the request as the response. -// - -var http = require("http"); - -var program = process.argv[1]; - -if (4 !== process.argv.length) { - console.log("Usage: %s ", program); -} -else { - var ip = process.argv[2]; - var port = process.argv[3]; - - var server = http.createServer(function (req, res) { - console.log("CONNECT"); - var input = ""; - - req.setEncoding(); - - req.on('data', function (buffer) { - // console.log("DATA: %s", buffer); - input = input + buffer; - }); - - req.on('end', function () { - // console.log("END"); - - var json_req; - - console.log("URL: %s", req.url); - console.log("HEADERS: %s", JSON.stringify(req.headers, undefined, 2)); - - try { - json_req = JSON.parse(input); - - console.log("REQ: %s", JSON.stringify(json_req, undefined, 2)); - } - catch (e) { - console.log("BAD JSON: %s", e.message); - - json_req = { error : e.message } - } - - res.statusCode = 200; - res.end(JSON.stringify({ - jsonrpc: "2.0", - result: { request : json_req }, - id: req.id - })); - }); - - req.on('close', function () { - console.log("CLOSE"); - }); - }); - - server.listen(port, ip, undefined, - function () { - console.log("Listening at: %s:%s", ip, port); - }); -} - -// vim:sw=2:sts=2:ts=8:et diff --git a/bin/physical.sh b/bin/physical.sh deleted file mode 100755 index c2c5aad68db..00000000000 --- a/bin/physical.sh +++ /dev/null @@ -1,218 +0,0 @@ -#!/bin/bash - -set -o errexit - -marker_base=985c80fbc6131f3a8cedd0da7e8af98dfceb13c7 -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 ' -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 :' -# Make sure first-party includes use angle brackets and .h extension. -ripple_replace='s:include\s*["<]ripple/\(.*\)\.h\(pp\)\?[">]:include :' -beast_replace='s:include\s*:#include :" \ - -e "s:^#include ' -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 ' -./Builds/levelization/levelization.sh -git add --update . -git commit -m 'Recompute loops' --author 'Pretty Printer ' diff --git a/bin/rlint.js b/bin/rlint.js deleted file mode 100755 index ce12e9560a6..00000000000 --- a/bin/rlint.js +++ /dev/null @@ -1,252 +0,0 @@ -#!/usr/bin/node - -var async = require('async'); -var Remote = require('ripple-lib').Remote; -var Transaction = require('ripple-lib').Transaction; -var UInt160 = require('ripple-lib').UInt160; -var Amount = require('ripple-lib').Amount; - -var book_key = function (book) { - return book.taker_pays.currency - + ":" + book.taker_pays.issuer - + ":" + book.taker_gets.currency - + ":" + book.taker_gets.issuer; -}; - -var book_key_cross = function (book) { - return book.taker_gets.currency - + ":" + book.taker_gets.issuer - + ":" + book.taker_pays.currency - + ":" + book.taker_pays.issuer; -}; - -var ledger_verify = function (ledger) { - var dir_nodes = ledger.accountState.filter(function (entry) { - return entry.LedgerEntryType === 'DirectoryNode' // Only directories - && entry.index === entry.RootIndex // Only root nodes - && 'TakerGetsCurrency' in entry; // Only offer directories - }); - - var books = {}; - - dir_nodes.forEach(function (node) { - var book = { - taker_gets: { - currency: UInt160.from_generic(node.TakerGetsCurrency).to_json(), - issuer: UInt160.from_generic(node.TakerGetsIssuer).to_json() - }, - taker_pays: { - currency: UInt160.from_generic(node.TakerPaysCurrency).to_json(), - issuer: UInt160.from_generic(node.TakerPaysIssuer).to_json() - }, - quality: Amount.from_quality(node.RootIndex), - index: node.RootIndex - }; - - books[book_key(book)] = book; - -// console.log(JSON.stringify(node, undefined, 2)); - }); - -// console.log(JSON.stringify(dir_entry, undefined, 2)); - console.log("#%s books: %s", ledger.ledger_index, Object.keys(books).length); - - Object.keys(books).forEach(function (key) { - var book = books[key]; - var key_cross = book_key_cross(book); - var book_cross = books[key_cross]; - - if (book && book_cross && !book_cross.done) - { - var book_cross_quality_inverted = Amount.from_json("1.0/1/1").divide(book_cross.quality); - - if (book_cross_quality_inverted.compareTo(book.quality) >= 0) - { - // Crossing books - console.log("crossing: #%s :: %s :: %s :: %s :: %s :: %s :: %s", ledger.ledger_index, key, book.quality.to_text(), book_cross.quality.to_text(), book_cross_quality_inverted.to_text(), - book.index, book_cross.index); - } - - book_cross.done = true; - } - }); - - var ripple_selfs = {}; - - var accounts = {}; - var counts = {}; - - ledger.accountState.forEach(function (entry) { - if (entry.LedgerEntryType === 'Offer') - { - counts[entry.Account] = (counts[entry.Account] || 0) + 1; - } - else if (entry.LedgerEntryType === 'RippleState') - { - if (entry.Flags & (0x10000 | 0x40000)) - { - counts[entry.LowLimit.issuer] = (counts[entry.LowLimit.issuer] || 0) + 1; - } - - if (entry.Flags & (0x20000 | 0x80000)) - { - counts[entry.HighLimit.issuer] = (counts[entry.HighLimit.issuer] || 0) + 1; - } - - if (entry.HighLimit.issuer === entry.LowLimit.issuer) - ripple_selfs[entry.Account] = entry; - } - else if (entry.LedgerEntryType == 'AccountRoot') - { - accounts[entry.Account] = entry; - } - }); - - var low = 0; // Accounts with too low a count. - var high = 0; - var missing_accounts = 0; // Objects with no referencing account. - var missing_objects = 0; // Accounts specifying an object but having none. - - Object.keys(counts).forEach(function (account) { - if (account in accounts) - { - if (counts[account] !== accounts[account].OwnerCount) - { - if (counts[account] < accounts[account].OwnerCount) - { - high += 1; - console.log("%s: high count %s/%s", account, counts[account], accounts[account].OwnerCount); - } - else - { - low += 1; - console.log("%s: low count %s/%s", account, counts[account], accounts[account].OwnerCount); - } - } - } - else - { - missing_accounts += 1; - - console.log("%s: missing : count %s", account, counts[account]); - } - }); - - Object.keys(accounts).forEach(function (account) { - if (!('OwnerCount' in accounts[account])) - { - console.log("%s: bad entry : %s", account, JSON.stringify(accounts[account], undefined, 2)); - } - else if (!(account in counts) && accounts[account].OwnerCount) - { - missing_objects += 1; - - console.log("%s: no objects : %s/%s", account, 0, accounts[account].OwnerCount); - } - }); - - if (low) - console.log("counts too low = %s", low); - - if (high) - console.log("counts too high = %s", high); - - if (missing_objects) - console.log("missing_objects = %s", missing_objects); - - if (missing_accounts) - console.log("missing_accounts = %s", missing_accounts); - - if (Object.keys(ripple_selfs).length) - console.log("RippleState selfs = %s", Object.keys(ripple_selfs).length); - -}; - -var ledger_request = function (remote, ledger_index, done) { - remote.request_ledger(undefined, { - accounts: true, - expand: true, - }) - .ledger_index(ledger_index) - .on('success', function (m) { - // console.log("ledger: ", ledger_index); - // console.log("ledger: ", JSON.stringify(m, undefined, 2)); - done(m.ledger); - }) - .on('error', function (m) { - console.log("error"); - done(); - }) - .request(); -}; - -var usage = function () { - console.log("rlint.js _websocket_ip_ _websocket_port_ "); -}; - -var finish = function (remote) { - remote.disconnect(); - - // XXX Because remote.disconnect() doesn't work: - process.exit(); -}; - -console.log("args: ", process.argv.length); -console.log("args: ", process.argv); - -if (process.argv.length < 4) { - usage(); -} -else { - var remote = Remote.from_config({ - websocket_ip: process.argv[2], - websocket_port: process.argv[3], - }) - .once('ledger_closed', function (m) { - console.log("ledger_closed: ", JSON.stringify(m, undefined, 2)); - - if (process.argv.length === 5) { - var ledger_index = process.argv[4]; - - ledger_request(remote, ledger_index, function (l) { - if (l) { - ledger_verify(l); - } - - finish(remote); - }); - - } else if (process.argv.length === 6) { - var ledger_start = Number(process.argv[4]); - var ledger_end = Number(process.argv[5]); - var ledger_cursor = ledger_end; - - async.whilst( - function () { - return ledger_start <= ledger_cursor && ledger_cursor <=ledger_end; - }, - function (callback) { - // console.log(ledger_cursor); - - ledger_request(remote, ledger_cursor, function (l) { - if (l) { - ledger_verify(l); - } - - --ledger_cursor; - - callback(); - }); - }, - function (error) { - finish(remote); - }); - - } else { - finish(remote); - } - }) - .connect(); -} - -// vim:sw=2:sts=2:ts=8:et diff --git a/bin/sh/install-vcpkg.sh b/bin/sh/install-vcpkg.sh deleted file mode 100755 index 8cf8f2d0881..00000000000 --- a/bin/sh/install-vcpkg.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env bash -set -exu - -: ${TRAVIS_BUILD_DIR:=""} -: ${VCPKG_DIR:=".vcpkg"} -export VCPKG_ROOT=${VCPKG_DIR} -: ${VCPKG_DEFAULT_TRIPLET:="x64-windows-static"} - -export VCPKG_DEFAULT_TRIPLET - -EXE="vcpkg" -if [[ -z ${COMSPEC:-} ]]; then - EXE="${EXE}.exe" -fi - -if [[ -d "${VCPKG_DIR}" && -x "${VCPKG_DIR}/${EXE}" && -d "${VCPKG_DIR}/installed" ]] ; then - echo "Using cached vcpkg at ${VCPKG_DIR}" - ${VCPKG_DIR}/${EXE} list -else - if [[ -d "${VCPKG_DIR}" ]] ; then - rm -rf "${VCPKG_DIR}" - fi - git clone --branch 2021.04.30 https://github.com/Microsoft/vcpkg.git ${VCPKG_DIR} - pushd ${VCPKG_DIR} - BSARGS=() - if [[ "$(uname)" == "Darwin" ]] ; then - BSARGS+=(--allowAppleClang) - fi - if [[ -z ${COMSPEC:-} ]]; then - chmod +x ./bootstrap-vcpkg.sh - time ./bootstrap-vcpkg.sh "${BSARGS[@]}" - else - time ./bootstrap-vcpkg.bat - fi - popd -fi - -# TODO: bring boost in this way as well ? -# NOTE: can pin specific ports to a commit/version like this: -# git checkout ports/boost -if [ $# -eq 0 ]; then - echo "No extra packages specified..." - PKGS=() -else - PKGS=( "$@" ) -fi -for LIB in "${PKGS[@]}"; do - time ${VCPKG_DIR}/${EXE} --clean-after-build install ${LIB} -done - - diff --git a/bin/sh/setup-msvc.sh b/bin/sh/setup-msvc.sh deleted file mode 100755 index 8d61c9757fa..00000000000 --- a/bin/sh/setup-msvc.sh +++ /dev/null @@ -1,40 +0,0 @@ - -# NOTE: must be sourced from a shell so it can export vars - -cat << BATCH > ./getenv.bat -CALL %* -ENV -BATCH - -while read line ; do - IFS='"' read x path arg <<<"${line}" - if [ -f "${path}" ] ; then - echo "FOUND: $path" - export VCINSTALLDIR=$(./getenv.bat "${path}" ${arg} | grep "^VCINSTALLDIR=" | sed -E "s/^VCINSTALLDIR=//g") - if [ "${VCINSTALLDIR}" != "" ] ; then - echo "USING ${VCINSTALLDIR}" - export LIB=$(./getenv.bat "${path}" ${arg} | grep "^LIB=" | sed -E "s/^LIB=//g") - export LIBPATH=$(./getenv.bat "${path}" ${arg} | grep "^LIBPATH=" | sed -E "s/^LIBPATH=//g") - export INCLUDE=$(./getenv.bat "${path}" ${arg} | grep "^INCLUDE=" | sed -E "s/^INCLUDE=//g") - ADDPATH=$(./getenv.bat "${path}" ${arg} | grep "^PATH=" | sed -E "s/^PATH=//g") - export PATH="${ADDPATH}:${PATH}" - break - fi - fi -done <= 7 - -import argparse -import asyncio -import configparser -import contextlib -import json -import logging -import os -from pathlib import Path -import platform -import subprocess -import time -import urllib.error -import urllib.request - -# Enable asynchronous subprocesses on Windows. The default changed in 3.8. -# https://docs.python.org/3.7/library/asyncio-platforms.html#subprocess-support-on-windows -if (platform.system() == 'Windows' and sys.version_info.major == 3 - and sys.version_info.minor < 8): - asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) - -DEFAULT_EXE = 'rippled' -DEFAULT_CONFIGURATION_FILE = 'rippled.cfg' -# Number of seconds to wait before forcefully terminating. -PATIENCE = 120 -# Number of contiguous seconds in a sync state to be considered synced. -DEFAULT_SYNC_DURATION = 60 -# Number of seconds between polls of state. -DEFAULT_POLL_INTERVAL = 5 -SYNC_STATES = ('full', 'validating', 'proposing') - - -def read_config(config_file): - # strict = False: Allow duplicate keys, e.g. [rpc_startup]. - # allow_no_value = True: Allow keys with no values. Generally, these - # instances use the "key" as the value, and the section name is the key, - # e.g. [debug_logfile]. - # delimiters = ('='): Allow ':' as a character in Windows paths. Some of - # our "keys" are actually values, and we don't want to split them on ':'. - config = configparser.ConfigParser( - strict=False, - allow_no_value=True, - delimiters=('='), - ) - config.read(config_file) - return config - - -def to_list(value, separator=','): - """Parse a list from a delimited string value.""" - return [s.strip() for s in value.split(separator) if s] - - -def find_log_file(config_file): - """Try to figure out what log file the user has chosen. Raises all kinds - of exceptions if there is any possibility of ambiguity.""" - config = read_config(config_file) - values = list(config['debug_logfile'].keys()) - if len(values) < 1: - raise ValueError( - f'no [debug_logfile] in configuration file: {config_file}') - if len(values) > 1: - raise ValueError( - f'too many [debug_logfile] in configuration file: {config_file}') - return values[0] - - -def find_http_port(config_file): - config = read_config(config_file) - names = list(config['server'].keys()) - for name in names: - server = config[name] - if 'http' in to_list(server.get('protocol', '')): - return int(server['port']) - raise ValueError(f'no server in [server] for "http" protocol') - - -@contextlib.asynccontextmanager -async def rippled(exe=DEFAULT_EXE, config_file=DEFAULT_CONFIGURATION_FILE): - """A context manager for a rippled process.""" - # Start the server. - process = await asyncio.create_subprocess_exec( - str(exe), - '--conf', - str(config_file), - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - logging.info(f'rippled started with pid {process.pid}') - try: - yield process - finally: - # Ask it to stop. - logging.info(f'asking rippled (pid: {process.pid}) to stop') - start = time.time() - process.terminate() - - # Wait nicely. - try: - await asyncio.wait_for(process.wait(), PATIENCE) - except asyncio.TimeoutError: - # Ask the operating system to kill it. - logging.warning(f'killing rippled ({process.pid})') - try: - process.kill() - except ProcessLookupError: - pass - - code = await process.wait() - end = time.time() - logging.info( - f'rippled stopped after {end - start:.1f} seconds with code {code}' - ) - - -async def sync( - port, - *, - duration=DEFAULT_SYNC_DURATION, - interval=DEFAULT_POLL_INTERVAL, -): - """Poll rippled on an interval until it has been synced for a duration.""" - start = time.perf_counter() - while (time.perf_counter() - start) < duration: - await asyncio.sleep(interval) - - request = urllib.request.Request( - f'http://127.0.0.1:{port}', - data=json.dumps({ - 'method': 'server_state' - }).encode(), - headers={'Content-Type': 'application/json'}, - ) - with urllib.request.urlopen(request) as response: - try: - body = json.loads(response.read()) - except urllib.error.HTTPError as cause: - logging.warning(f'server_state returned not JSON: {cause}') - start = time.perf_counter() - continue - - try: - state = body['result']['state']['server_state'] - except KeyError as cause: - logging.warning(f'server_state response missing key: {cause.key}') - start = time.perf_counter() - continue - logging.info(f'server_state: {state}') - if state not in SYNC_STATES: - # Require a contiguous sync state. - start = time.perf_counter() - - -async def loop(test, - *, - exe=DEFAULT_EXE, - config_file=DEFAULT_CONFIGURATION_FILE): - """ - Start-test-stop rippled in an infinite loop. - - Moves log to a different file after each iteration. - """ - log_file = find_log_file(config_file) - id = 0 - while True: - logging.info(f'iteration: {id}') - async with rippled(exe, config_file) as process: - start = time.perf_counter() - exited = asyncio.create_task(process.wait()) - tested = asyncio.create_task(test()) - # Try to sync as long as the process is running. - done, pending = await asyncio.wait( - {exited, tested}, - return_when=asyncio.FIRST_COMPLETED, - ) - if done == {exited}: - code = exited.result() - logging.warning( - f'server halted for unknown reason with code {code}') - else: - assert done == {tested} - assert tested.exception() is None - end = time.perf_counter() - logging.info(f'synced after {end - start:.0f} seconds') - os.replace(log_file, f'debug.{id}.log') - id += 1 - - -logging.basicConfig( - format='%(asctime)s %(levelname)-8s %(message)s', - level=logging.INFO, - datefmt='%Y-%m-%d %H:%M:%S', -) - -parser = argparse.ArgumentParser( - formatter_class=argparse.ArgumentDefaultsHelpFormatter) -parser.add_argument( - 'rippled', - type=Path, - nargs='?', - default=DEFAULT_EXE, - help='Path to rippled.', -) -parser.add_argument( - '--conf', - type=Path, - default=DEFAULT_CONFIGURATION_FILE, - help='Path to configuration file.', -) -parser.add_argument( - '--duration', - type=int, - default=DEFAULT_SYNC_DURATION, - help='Number of contiguous seconds required in a synchronized state.', -) -parser.add_argument( - '--interval', - type=int, - default=DEFAULT_POLL_INTERVAL, - help='Number of seconds to wait between polls of state.', -) -args = parser.parse_args() - -port = find_http_port(args.conf) - - -def test(): - return sync(port, duration=args.duration, interval=args.interval) - - -try: - asyncio.run(loop(test, exe=args.rippled, config_file=args.conf)) -except KeyboardInterrupt: - # Squelch the message. This is a normal mode of exit. - pass diff --git a/bin/stop-test.js b/bin/stop-test.js deleted file mode 100644 index 45aa15e2717..00000000000 --- a/bin/stop-test.js +++ /dev/null @@ -1,133 +0,0 @@ -/* -------------------------------- REQUIRES -------------------------------- */ - -var child = require("child_process"); -var assert = require("assert"); - -/* --------------------------------- CONFIG --------------------------------- */ - -if (process.argv[2] == null) { - [ - 'Usage: ', - '', - ' `node bin/stop-test.js i,j [rippled_path] [rippled_conf]`', - '', - ' Launch rippled and stop it after n seconds for all n in [i, j}', - ' For all even values of n launch rippled with `--fg`', - ' For values of n where n % 3 == 0 launch rippled with `--fg`\n', - 'Examples: ', - '', - ' $ node bin/stop-test.js 5,10', - (' $ node bin/stop-test.js 1,4 ' + - 'build/clang.debug/rippled $HOME/.confs/rippled.cfg') - ] - .forEach(function(l){console.log(l)}); - - process.exit(); -} else { - var testRange = process.argv[2].split(',').map(Number); - var rippledPath = process.argv[3] || 'build/rippled' - var rippledConf = process.argv[4] || 'rippled.cfg' -} - -var options = { - env: process.env, - stdio: 'ignore' // we could dump the child io when it fails abnormally -}; - -// default args -var conf_args = ['--conf='+rippledConf]; -var start_args = conf_args.concat([/*'--net'*/]) -var stop_args = conf_args.concat(['stop']); - -/* --------------------------------- HELPERS -------------------------------- */ - -function start(args) { - return child.spawn(rippledPath, args, options); -} -function stop(rippled) { child.execFile(rippledPath, stop_args, options)} -function secs_l8r(ms, f) {setTimeout(f, ms * 1000); } - -function show_results_and_exit(results) { - console.log(JSON.stringify(results, undefined, 2)); - process.exit(); -} - -var timeTakes = function (range) { - function sumRange(n) {return (n+1) * n /2} - var ret = sumRange(range[1]); - if (range[0] > 1) { - ret = ret - sumRange(range[0] - 1) - } - var stopping = (range[1] - range[0]) * 0.5; - return ret + stopping; -} - -/* ---------------------------------- TEST ---------------------------------- */ - -console.log("Test will take ~%s seconds", timeTakes(testRange)); - -(function oneTest(n /* seconds */, results) { - if (n >= testRange[1]) { - // show_results_and_exit(results); - console.log(JSON.stringify(results, undefined, 2)); - oneTest(testRange[0], []); - return; - } - - var args = start_args; - if (n % 2 == 0) {args = args.concat(['--fg'])} - if (n % 3 == 0) {args = args.concat(['--net'])} - - var result = {args: args, alive_for: n}; - results.push(result); - - console.log("\nLaunching `%s` with `%s` for %d seconds", - rippledPath, JSON.stringify(args), n); - - rippled = start(args); - console.log("Rippled pid: %d", rippled.pid); - - // defaults - var b4StopSent = false; - var stopSent = false; - var stop_took = null; - - rippled.once('exit', function(){ - if (!stopSent && !b4StopSent) { - console.warn('\nRippled exited itself b4 stop issued'); - process.exit(); - }; - - // The io handles close AFTER exit, may have implications for - // `stdio:'inherit'` option to `child.spawn`. - rippled.once('close', function() { - result.stop_took = (+new Date() - stop_took) / 1000; // seconds - console.log("Stopping after %d seconds took %s seconds", - n, result.stop_took); - oneTest(n+1, results); - }); - }); - - secs_l8r(n, function(){ - console.log("Stopping rippled after %d seconds", n); - - // possible race here ? - // seems highly unlikely, but I was having issues at one point - b4StopSent=true; - stop_took = (+new Date()); - // when does `exit` actually get sent? - stop(); - stopSent=true; - - // Sometimes we want to attach with a debugger. - if (process.env.ABORT_TESTS_ON_STALL != null) { - // We wait 30 seconds, and if it hasn't stopped, we abort the process - secs_l8r(30, function() { - if (result.stop_took == null) { - console.log("rippled has stalled"); - process.exit(); - }; - }); - } - }) -}(testRange[0], [])); \ No newline at end of file diff --git a/bin/update_binformat.js b/bin/update_binformat.js deleted file mode 100644 index 7987f72c821..00000000000 --- a/bin/update_binformat.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * bin/update_bintypes.js - * - * This unholy abomination of a script generates the JavaScript file - * src/js/bintypes.js from various parts of the C++ source code. - * - * This should *NOT* be part of any automatic build process unless the C++ - * source data are brought into a more easily parseable format. Until then, - * simply run this script manually and fix as needed. - */ - -// XXX: Process LedgerFormats.(h|cpp) as well. - -var filenameProto = __dirname + '/../src/cpp/ripple/SerializeProto.h', - filenameTxFormatsH = __dirname + '/../src/cpp/ripple/TransactionFormats.h', - filenameTxFormats = __dirname + '/../src/cpp/ripple/TransactionFormats.cpp'; - -var fs = require('fs'); - -var output = []; - -// Stage 1: Get the field types and codes from SerializeProto.h -var types = {}, - fields = {}; -String(fs.readFileSync(filenameProto)).split('\n').forEach(function (line) { - line = line.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ''); - if (!line.length || line.slice(0, 2) === '//' || line.slice(-1) !== ')') return; - - var tmp = line.slice(0, -1).split('('), - type = tmp[0], - opts = tmp[1].split(','); - - if (type === 'TYPE') types[opts[1]] = [opts[0], +opts[2]]; - else if (type === 'FIELD') fields[opts[0]] = [types[opts[1]][0], +opts[2]]; -}); - -output.push('var ST = require("./serializedtypes");'); -output.push(''); -output.push('var REQUIRED = exports.REQUIRED = 0,'); -output.push(' OPTIONAL = exports.OPTIONAL = 1,'); -output.push(' DEFAULT = exports.DEFAULT = 2;'); -output.push(''); - -function pad(s, n) { while (s.length < n) s += ' '; return s; } -function padl(s, n) { while (s.length < n) s = ' '+s; return s; } - -Object.keys(types).forEach(function (type) { - output.push(pad('ST.'+types[type][0]+'.id', 25) + ' = '+types[type][1]+';'); -}); -output.push(''); - -// Stage 2: Get the transaction type IDs from TransactionFormats.h -var ttConsts = {}; -String(fs.readFileSync(filenameTxFormatsH)).split('\n').forEach(function (line) { - var regex = /tt([A-Z_]+)\s+=\s+([0-9-]+)/; - var match = line.match(regex); - if (match) ttConsts[match[1]] = +match[2]; -}); - -// Stage 3: Get the transaction formats from TransactionFormats.cpp -var base = [], - sections = [], - current = base; -String(fs.readFileSync(filenameTxFormats)).split('\n').forEach(function (line) { - line = line.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ''); - - var d_regex = /DECLARE_TF\(([A-Za-z]+),tt([A-Z_]+)/; - var d_match = line.match(d_regex); - - var s_regex = /SOElement\(sf([a-z]+),SOE_(REQUIRED|OPTIONAL|DEFAULT)/i; - var s_match = line.match(s_regex); - - if (d_match) sections.push(current = [d_match[1], ttConsts[d_match[2]]]); - else if (s_match) current.push([s_match[1], s_match[2]]); -}); - -function removeFinalComma(arr) { - arr[arr.length-1] = arr[arr.length-1].slice(0, -1); -} - -output.push('var base = ['); -base.forEach(function (field) { - var spec = fields[field[0]]; - output.push(' [ '+ - pad("'"+field[0]+"'", 21)+', '+ - pad(field[1], 8)+', '+ - padl(""+spec[1], 2)+', '+ - 'ST.'+pad(spec[0], 3)+ - ' ],'); -}); -removeFinalComma(output); -output.push('];'); -output.push(''); - - -output.push('exports.tx = {'); -sections.forEach(function (section) { - var name = section.shift(), - ttid = section.shift(); - - output.push(' '+name+': ['+ttid+'].concat(base, ['); - section.forEach(function (field) { - var spec = fields[field[0]]; - output.push(' [ '+ - pad("'"+field[0]+"'", 21)+', '+ - pad(field[1], 8)+', '+ - padl(""+spec[1], 2)+', '+ - 'ST.'+pad(spec[0], 3)+ - ' ],'); - }); - removeFinalComma(output); - output.push(' ]),'); -}); -removeFinalComma(output); -output.push('};'); -output.push(''); - -console.log(output.join('\n')); - diff --git a/cmake/RippledCompiler.cmake b/cmake/RippledCompiler.cmake index 7485605d950..bc3a62a48c4 100644 --- a/cmake/RippledCompiler.cmake +++ b/cmake/RippledCompiler.cmake @@ -90,28 +90,16 @@ if (MSVC) -errorreport:none -machine:X64) 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 INTERFACE + -Wall + -Wdeprecated + $<$:-Wno-deprecated-declarations> + $<$:-Wextra -Wno-unused-parameter> $<$:-Werror> - $<$: - -frtti - -Wnon-virtual-dtor - > - -Wno-sign-compare - -Wno-char-subscripts - -Wno-format - -Wno-unused-local-typedefs -fstack-protector - $<$: - -Wno-unused-but-set-variable - -Wno-deprecated - > + -Wno-sign-compare + -Wno-unused-but-set-variable $<$>:-fno-strict-aliasing> # tweak gcc optimization for debug $<$,$>:-O0> diff --git a/cmake/RippledSettings.cmake b/cmake/RippledSettings.cmake index b2d7b0d9a5a..9dc8609f58d 100644 --- a/cmake/RippledSettings.cmake +++ b/cmake/RippledSettings.cmake @@ -18,7 +18,7 @@ if(tests) 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(NOT is_ci) set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") diff --git a/cmake/deps/Boost.cmake b/cmake/deps/Boost.cmake index 041c2380e12..031202f4d28 100644 --- a/cmake/deps/Boost.cmake +++ b/cmake/deps/Boost.cmake @@ -2,7 +2,6 @@ find_package(Boost 1.82 REQUIRED COMPONENTS chrono container - context coroutine date_time filesystem @@ -24,7 +23,7 @@ endif() target_link_libraries(ripple_boost INTERFACE - Boost::boost + Boost::headers Boost::chrono Boost::container Boost::coroutine diff --git a/cmake/xrpl_add_test.cmake b/cmake/xrpl_add_test.cmake new file mode 100644 index 00000000000..d61f4ece3da --- /dev/null +++ b/cmake/xrpl_add_test.cmake @@ -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 $ + --target ${target} + ) + set_tests_properties(${target}.build PROPERTIES + FIXTURES_SETUP ${target}_fixture + ) +endfunction() diff --git a/conan/profiles/default b/conan/profiles/default new file mode 100644 index 00000000000..3a7bcda1c65 --- /dev/null +++ b/conan/profiles/default @@ -0,0 +1,34 @@ +{% 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 == "gcc" and compiler_version < 13 %} +tools.build:cxxflags=['-Wno-restrict'] +{% endif %} + +[tool_requires] +!cmake/*: cmake/[>=3 <4] diff --git a/conanfile.py b/conanfile.py index da8a09611d8..ab4657277cb 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,15 +25,19 @@ class Xrpl(ConanFile): requires = [ 'grpc/1.50.1', - 'libarchive/3.7.6', - 'nudb/2.0.8', - 'openssl/1.1.1v', + 'libarchive/3.8.1', + 'nudb/2.0.9', + 'openssl/1.1.1w', 'soci/4.0.3', 'zlib/1.3.1', ] + test_requires = [ + 'doctest/2.4.11', + ] + tool_requires = [ - 'protobuf/3.21.9', + 'protobuf/3.21.12', ] default_options = { @@ -85,12 +89,13 @@ class Xrpl(ConanFile): } def set_version(self): - path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp' - regex = r'versionString\s?=\s?\"(.*)\"' - with open(path, 'r') as file: - matches = (re.search(regex, line) for line in file) - match = next(m for m in matches if m) - self.version = match.group(1) + if self.version is None: + path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp' + regex = r'versionString\s?=\s?\"(.*)\"' + with open(path, encoding='utf-8') as file: + matches = (re.search(regex, line) for line in file) + match = next(m for m in matches if m) + self.version = match.group(1) def configure(self): if self.settings.compiler == 'apple-clang': @@ -99,20 +104,19 @@ def configure(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 {} - self.requires('boost/1.83.0', force=True, **transitive_headers_opt) - self.requires('date/3.0.3', **transitive_headers_opt) + 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('protobuf/3.21.9', force=True) - self.requires('sqlite3/3.47.0', force=True) + self.requires('protobuf/3.21.12', force=True) + self.requires('sqlite3/3.49.1', force=True) if self.options.jemalloc: self.requires('jemalloc/5.3.0') if self.options.rocksdb: - self.requires('rocksdb/9.7.3') - self.requires('xxhash/0.8.2', **transitive_headers_opt) + self.requires('rocksdb/10.0.1') + self.requires('xxhash/0.8.3', **transitive_headers_opt) exports_sources = ( 'CMakeLists.txt', - 'bin/getRippledInfo', 'cfg/*', 'cmake/*', 'external/*', @@ -163,7 +167,17 @@ def package_info(self): # `include/`, not `include/ripple/proto/`. libxrpl.includedirs = ['include', 'include/ripple/proto'] 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', 'grpc::grpc++', 'libarchive::libarchive', diff --git a/docs/0001-negative-unl/README.md b/docs/0001-negative-unl/README.md index 606b30aab15..f28ff63c6f0 100644 --- a/docs/0001-negative-unl/README.md +++ b/docs/0001-negative-unl/README.md @@ -30,7 +30,7 @@ the ledger (so the entire network has the same view). This will help the network see which validators are **currently** unreliable, and adjust their quorum calculation accordingly. -*Improving the liveness of the network is the main motivation for the negative UNL.* +_Improving the liveness of the network is the main motivation for the negative UNL._ ### Targeted Faults @@ -53,16 +53,17 @@ even if the number of remaining validators gets to 60%. Say we have a network with 10 validators on the UNL and everything is operating correctly. The quorum required for this network would be 8 (80% of 10). When validators fail, the quorum required would be as low as 6 (60% of 10), which is the absolute -***minimum quorum***. We need the absolute minimum quorum to be strictly greater +**_minimum quorum_**. We need the absolute minimum quorum to be strictly greater than 50% of the original UNL so that there cannot be two partitions of well-behaved nodes headed in different directions. We arbitrarily choose 60% as the minimum quorum to give a margin of safety. Consider these events in the absence of negative UNL: + 1. 1:00pm - validator1 fails, votes vs. quorum: 9 >= 8, we have quorum 1. 3:00pm - validator2 fails, votes vs. quorum: 8 >= 8, we have quorum 1. 5:00pm - validator3 fails, votes vs. quorum: 7 < 8, we don’t have quorum - * **network cannot validate new ledgers with 3 failed validators** + - **network cannot validate new ledgers with 3 failed validators** We're below 80% agreement, so new ledgers cannot be validated. This is how the XRP Ledger operates today, but if the negative UNL was enabled, the events would @@ -70,18 +71,20 @@ happen as follows. (Please note that the events below are from a simplified version of our protocol.) 1. 1:00pm - validator1 fails, votes vs. quorum: 9 >= 8, we have quorum -1. 1:40pm - network adds validator1 to negative UNL, quorum changes to ceil(9 * 0.8), or 8 +1. 1:40pm - network adds validator1 to negative UNL, quorum changes to ceil(9 \* 0.8), or 8 1. 3:00pm - validator2 fails, votes vs. quorum: 8 >= 8, we have quorum -1. 3:40pm - network adds validator2 to negative UNL, quorum changes to ceil(8 * 0.8), or 7 +1. 3:40pm - network adds validator2 to negative UNL, quorum changes to ceil(8 \* 0.8), or 7 1. 5:00pm - validator3 fails, votes vs. quorum: 7 >= 7, we have quorum -1. 5:40pm - network adds validator3 to negative UNL, quorum changes to ceil(7 * 0.8), or 6 +1. 5:40pm - network adds validator3 to negative UNL, quorum changes to ceil(7 \* 0.8), or 6 1. 7:00pm - validator4 fails, votes vs. quorum: 6 >= 6, we have quorum - * **network can still validate new ledgers with 4 failed validators** + - **network can still validate new ledgers with 4 failed validators** ## External Interactions ### Message Format Changes + This proposal will: + 1. add a new pseudo-transaction type 1. add the negative UNL to the ledger data structure. @@ -89,19 +92,20 @@ Any tools or systems that rely on the format of this data will have to be updated. ### Amendment + This feature **will** need an amendment to activate. ## Design This section discusses the following topics about the Negative UNL design: -* [Negative UNL protocol overview](#Negative-UNL-Protocol-Overview) -* [Validator reliability measurement](#Validator-Reliability-Measurement) -* [Format Changes](#Format-Changes) -* [Negative UNL maintenance](#Negative-UNL-Maintenance) -* [Quorum size calculation](#Quorum-Size-Calculation) -* [Filter validation messages](#Filter-Validation-Messages) -* [High level sequence diagram of code +- [Negative UNL protocol overview](#Negative-UNL-Protocol-Overview) +- [Validator reliability measurement](#Validator-Reliability-Measurement) +- [Format Changes](#Format-Changes) +- [Negative UNL maintenance](#Negative-UNL-Maintenance) +- [Quorum size calculation](#Quorum-Size-Calculation) +- [Filter validation messages](#Filter-Validation-Messages) +- [High level sequence diagram of code changes](#High-Level-Sequence-Diagram-of-Code-Changes) ### Negative UNL Protocol Overview @@ -114,9 +118,9 @@ with V in their UNL adjust the quorum and V’s validation message is not counte when verifying if a ledger is fully validated. V’s flow of messages and network interactions, however, will remain the same. -We define the ***effective UNL** = original UNL - negative UNL*, and the -***effective quorum*** as the quorum of the *effective UNL*. And we set -*effective quorum = Ceiling(80% * effective UNL)*. +We define the **\*effective UNL** = original UNL - negative UNL\*, and the +**_effective quorum_** as the quorum of the _effective UNL_. And we set +_effective quorum = Ceiling(80% _ effective UNL)\*. ### Validator Reliability Measurement @@ -126,16 +130,16 @@ measure about its validators, but we have chosen ledger validation messages. This is because every validator shall send one and only one signed validation message per ledger. This keeps the measurement simple and removes timing/clock-sync issues. A node will measure the percentage of agreeing -validation messages (*PAV*) received from each validator on the node's UNL. Note +validation messages (_PAV_) received from each validator on the node's UNL. Note that the node will only count the validation messages that agree with its own validations. We define the **PAV** as the **P**ercentage of **A**greed **V**alidation messages received for the last N ledgers, where N = 256 by default. -When the PAV drops below the ***low-water mark***, the validator is considered +When the PAV drops below the **_low-water mark_**, the validator is considered unreliable, and is a candidate to be disabled by being added to the negative -UNL. A validator must have a PAV higher than the ***high-water mark*** to be +UNL. A validator must have a PAV higher than the **_high-water mark_** to be re-enabled. The validator is re-enabled by removing it from the negative UNL. In the implementation, we plan to set the low-water mark as 50% and the high-water mark as 80%. @@ -143,22 +147,24 @@ mark as 80%. ### Format Changes The negative UNL component in a ledger contains three fields. -* ***NegativeUNL***: The current negative UNL, a list of unreliable validators. -* ***ToDisable***: The validator to be added to the negative UNL on the next + +- **_NegativeUNL_**: The current negative UNL, a list of unreliable validators. +- **_ToDisable_**: The validator to be added to the negative UNL on the next flag ledger. -* ***ToReEnable***: The validator to be removed from the negative UNL on the +- **_ToReEnable_**: The validator to be removed from the negative UNL on the next flag ledger. -All three fields are optional. When the *ToReEnable* field exists, the -*NegativeUNL* field cannot be empty. +All three fields are optional. When the _ToReEnable_ field exists, the +_NegativeUNL_ field cannot be empty. + +A new pseudo-transaction, **_UNLModify_**, is added. It has three fields -A new pseudo-transaction, ***UNLModify***, is added. It has three fields -* ***Disabling***: A flag indicating whether the modification is to disable or +- **_Disabling_**: A flag indicating whether the modification is to disable or to re-enable a validator. -* ***Seq***: The ledger sequence number. -* ***Validator***: The validator to be disabled or re-enabled. +- **_Seq_**: The ledger sequence number. +- **_Validator_**: The validator to be disabled or re-enabled. -There would be at most one *disable* `UNLModify` and one *re-enable* `UNLModify` +There would be at most one _disable_ `UNLModify` and one _re-enable_ `UNLModify` transaction per flag ledger. The full machinery is described further on. ### Negative UNL Maintenance @@ -167,19 +173,19 @@ The negative UNL can only be modified on the flag ledgers. If a validator's reliability status changes, it takes two flag ledgers to modify the negative UNL. Let's see an example of the algorithm: -* Ledger seq = 100: A validator V goes offline. -* Ledger seq = 256: This is a flag ledger, and V's reliability measurement *PAV* +- Ledger seq = 100: A validator V goes offline. +- Ledger seq = 256: This is a flag ledger, and V's reliability measurement _PAV_ is lower than the low-water mark. Other validators add `UNLModify` pseudo-transactions `{true, 256, V}` to the transaction set which goes through the consensus. Then the pseudo-transaction is applied to the negative UNL ledger component by setting `ToDisable = V`. -* Ledger seq = 257 ~ 511: The negative UNL ledger component is copied from the +- Ledger seq = 257 ~ 511: The negative UNL ledger component is copied from the parent ledger. -* Ledger seq=512: This is a flag ledger, and the negative UNL is updated +- Ledger seq=512: This is a flag ledger, and the negative UNL is updated `NegativeUNL = NegativeUNL + ToDisable`. The negative UNL may have up to `MaxNegativeListed = floor(original UNL * 25%)` -validators. The 25% is because of 75% * 80% = 60%, where 75% = 100% - 25%, 80% +validators. The 25% is because of 75% \* 80% = 60%, where 75% = 100% - 25%, 80% is the quorum of the effective UNL, and 60% is the absolute minimum quorum of the original UNL. Adding more than 25% validators to the negative UNL does not improve the liveness of the network, because adding more validators to the @@ -187,52 +193,43 @@ negative UNL cannot lower the effective quorum. The following is the detailed algorithm: -* **If** the ledger seq = x is a flag ledger - - 1. Compute `NegativeUNL = NegativeUNL + ToDisable - ToReEnable` if they - exist in the parent ledger - - 1. Try to find a candidate to disable if `sizeof NegativeUNL < MaxNegativeListed` - - 1. Find a validator V that has a *PAV* lower than the low-water - mark, but is not in `NegativeUNL`. - - 1. If two or more are found, their public keys are XORed with the hash - of the parent ledger and the one with the lowest XOR result is chosen. - - 1. If V is found, create a `UNLModify` pseudo-transaction - `TxDisableValidator = {true, x, V}` - - 1. Try to find a candidate to re-enable if `sizeof NegativeUNL > 0`: - - 1. Find a validator U that is in `NegativeUNL` and has a *PAV* higher - than the high-water mark. - - 1. If U is not found, try to find one in `NegativeUNL` but not in the - local *UNL*. - - 1. If two or more are found, their public keys are XORed with the hash - of the parent ledger and the one with the lowest XOR result is chosen. - - 1. If U is found, create a `UNLModify` pseudo-transaction - `TxReEnableValidator = {false, x, U}` - - 1. If any `UNLModify` pseudo-transactions are created, add them to the - transaction set. The transaction set goes through the consensus algorithm. - - 1. If have enough support, the `UNLModify` pseudo-transactions remain in the - transaction set agreed by the validators. Then the pseudo-transactions are - applied to the ledger: - - 1. If have `TxDisableValidator`, set `ToDisable=TxDisableValidator.V`. - Else clear `ToDisable`. - - 1. If have `TxReEnableValidator`, set - `ToReEnable=TxReEnableValidator.U`. Else clear `ToReEnable`. - -* **Else** (not a flag ledger) - - 1. Copy the negative UNL ledger component from the parent ledger +- **If** the ledger seq = x is a flag ledger + 1. Compute `NegativeUNL = NegativeUNL + ToDisable - ToReEnable` if they + exist in the parent ledger + + 1. Try to find a candidate to disable if `sizeof NegativeUNL < MaxNegativeListed` + + 1. Find a validator V that has a _PAV_ lower than the low-water + mark, but is not in `NegativeUNL`. + + 1. If two or more are found, their public keys are XORed with the hash + of the parent ledger and the one with the lowest XOR result is chosen. + 1. If V is found, create a `UNLModify` pseudo-transaction + `TxDisableValidator = {true, x, V}` + 1. Try to find a candidate to re-enable if `sizeof NegativeUNL > 0`: + 1. Find a validator U that is in `NegativeUNL` and has a _PAV_ higher + than the high-water mark. + 1. If U is not found, try to find one in `NegativeUNL` but not in the + local _UNL_. + 1. If two or more are found, their public keys are XORed with the hash + of the parent ledger and the one with the lowest XOR result is chosen. + 1. If U is found, create a `UNLModify` pseudo-transaction + `TxReEnableValidator = {false, x, U}` + + 1. If any `UNLModify` pseudo-transactions are created, add them to the + transaction set. The transaction set goes through the consensus algorithm. + 1. If have enough support, the `UNLModify` pseudo-transactions remain in the + transaction set agreed by the validators. Then the pseudo-transactions are + applied to the ledger: + + 1. If have `TxDisableValidator`, set `ToDisable=TxDisableValidator.V`. + Else clear `ToDisable`. + + 1. If have `TxReEnableValidator`, set + `ToReEnable=TxReEnableValidator.U`. Else clear `ToReEnable`. + +- **Else** (not a flag ledger) + 1. Copy the negative UNL ledger component from the parent ledger The negative UNL is stored on each ledger because we don't know when a validator may reconnect to the network. If the negative UNL was stored only on every flag @@ -273,31 +270,26 @@ not counted when checking if the ledger is fully validated. The diagram below is the sequence of one round of consensus. Classes and components with non-trivial changes are colored green. -* The `ValidatorList` class is modified to compute the quorum of the effective +- The `ValidatorList` class is modified to compute the quorum of the effective UNL. -* The `Validations` class provides an interface for querying the validation +- The `Validations` class provides an interface for querying the validation messages from trusted validators. -* The `ConsensusAdaptor` component: - - * The `RCLConsensus::Adaptor` class is modified for creating `UNLModify` - Pseudo-Transactions. - - * The `Change` class is modified for applying `UNLModify` - Pseudo-Transactions. - - * The `Ledger` class is modified for creating and adjusting the negative UNL - ledger component. - - * The `LedgerMaster` class is modified for filtering out validation messages - from negative UNL validators when verifying if a ledger is fully - validated. +- The `ConsensusAdaptor` component: + - The `RCLConsensus::Adaptor` class is modified for creating `UNLModify` + Pseudo-Transactions. + - The `Change` class is modified for applying `UNLModify` + Pseudo-Transactions. + - The `Ledger` class is modified for creating and adjusting the negative UNL + ledger component. + - The `LedgerMaster` class is modified for filtering out validation messages + from negative UNL validators when verifying if a ledger is fully + validated. ![Sequence diagram](./negativeUNL_highLevel_sequence.png?raw=true "Negative UNL Changes") - ## Roads Not Taken ### Use a Mechanism Like Fee Voting to Process UNLModify Pseudo-Transactions @@ -311,7 +303,7 @@ and different quorums for the same ledger. As a result, the network's safety is impacted. This updated version does not impact safety though operates a bit more slowly. -The negative UNL modifications in the *UNLModify* pseudo-transaction approved by +The negative UNL modifications in the _UNLModify_ pseudo-transaction approved by the consensus will take effect at the next flag ledger. The extra time of the 256 ledgers should be enough for nodes to be in sync of the negative UNL modifications. @@ -334,29 +326,28 @@ expiration approach cannot be simply applied. ### Validator Reliability Measurement and Flag Ledger Frequency If the ledger time is about 4.5 seconds and the low-water mark is 50%, then in -the worst case, it takes 48 minutes *((0.5 * 256 + 256 + 256) * 4.5 / 60 = 48)* +the worst case, it takes 48 minutes _((0.5 _ 256 + 256 + 256) _ 4.5 / 60 = 48)_ to put an offline validator on the negative UNL. We considered lowering the flag ledger frequency so that the negative UNL can be more responsive. We also considered decoupling the reliability measurement and flag ledger frequency to be more flexible. In practice, however, their benefits are not clear. - ## New Attack Vectors A group of malicious validators may try to frame a reliable validator and put it on the negative UNL. But they cannot succeed. Because: 1. A reliable validator sends a signed validation message every ledger. A -sufficient peer-to-peer network will propagate the validation messages to other -validators. The validators will decide if another validator is reliable or not -only by its local observation of the validation messages received. So an honest -validator’s vote on another validator’s reliability is accurate. + sufficient peer-to-peer network will propagate the validation messages to other + validators. The validators will decide if another validator is reliable or not + only by its local observation of the validation messages received. So an honest + validator’s vote on another validator’s reliability is accurate. 1. Given the votes are accurate, and one vote per validator, an honest validator -will not create a UNLModify transaction of a reliable validator. + will not create a UNLModify transaction of a reliable validator. 1. A validator can be added to a negative UNL only through a UNLModify -transaction. + transaction. Assuming the group of malicious validators is less than the quorum, they cannot frame a reliable validator. @@ -365,32 +356,32 @@ frame a reliable validator. The bullet points below briefly summarize the current proposal: -* The motivation of the negative UNL is to improve the liveness of the network. +- The motivation of the negative UNL is to improve the liveness of the network. -* The targeted faults are the ones frequently observed in the production +- The targeted faults are the ones frequently observed in the production network. -* Validators propose negative UNL candidates based on their local measurements. +- Validators propose negative UNL candidates based on their local measurements. -* The absolute minimum quorum is 60% of the original UNL. +- The absolute minimum quorum is 60% of the original UNL. -* The format of the ledger is changed, and a new *UNLModify* pseudo-transaction +- The format of the ledger is changed, and a new _UNLModify_ pseudo-transaction is added. Any tools or systems that rely on the format of these data will have to be updated. -* The negative UNL can only be modified on the flag ledgers. +- The negative UNL can only be modified on the flag ledgers. -* At most one validator can be added to the negative UNL at a flag ledger. +- At most one validator can be added to the negative UNL at a flag ledger. -* At most one validator can be removed from the negative UNL at a flag ledger. +- At most one validator can be removed from the negative UNL at a flag ledger. -* If a validator's reliability status changes, it takes two flag ledgers to +- If a validator's reliability status changes, it takes two flag ledgers to modify the negative UNL. -* The quorum is the larger of 80% of the effective UNL and 60% of the original +- The quorum is the larger of 80% of the effective UNL and 60% of the original UNL. -* If a validator is on the negative UNL, its validation messages are ignored +- If a validator is on the negative UNL, its validation messages are ignored when the local node verifies if a ledger is fully validated. ## FAQ @@ -415,7 +406,7 @@ lower quorum size while keeping the network safe. validator removed from the negative UNL? A validator’s reliability is measured by other validators. If a validator -becomes unreliable, at a flag ledger, other validators propose *UNLModify* +becomes unreliable, at a flag ledger, other validators propose _UNLModify_ pseudo-transactions which vote the validator to add to the negative UNL during the consensus session. If agreed, the validator is added to the negative UNL at the next flag ledger. The mechanism of removing a validator from the negative @@ -423,32 +414,32 @@ UNL is the same. ### Question: Given a negative UNL, what happens if the UNL changes? -Answer: Let’s consider the cases: +Answer: Let’s consider the cases: -1. A validator is added to the UNL, and it is already in the negative UNL. This -case could happen when not all the nodes have the same UNL. Note that the -negative UNL on the ledger lists unreliable nodes that are not necessarily the -validators for everyone. +1. A validator is added to the UNL, and it is already in the negative UNL. This + case could happen when not all the nodes have the same UNL. Note that the + negative UNL on the ledger lists unreliable nodes that are not necessarily the + validators for everyone. - In this case, the liveness is affected negatively. Because the minimum - quorum could be larger but the usable validators are not increased. + In this case, the liveness is affected negatively. Because the minimum + quorum could be larger but the usable validators are not increased. -1. A validator is removed from the UNL, and it is in the negative UNL. +1. A validator is removed from the UNL, and it is in the negative UNL. In this case, the liveness is affected positively. Because the quorum could be smaller but the usable validators are not reduced. -1. A validator is added to the UNL, and it is not in the negative UNL. -1. A validator is removed from the UNL, and it is not in the negative UNL. - +1. A validator is added to the UNL, and it is not in the negative UNL. +1. A validator is removed from the UNL, and it is not in the negative UNL. + Case 3 and 4 are not affected by the negative UNL protocol. -### Question: Can we simply lower the quorum to 60% without the negative UNL? +### Question: Can we simply lower the quorum to 60% without the negative UNL? Answer: No, because the negative UNL approach is safer. -First let’s compare the two approaches intuitively, (1) the *negative UNL* -approach, and (2) *lower quorum*: simply lowering the quorum from 80% to 60% +First let’s compare the two approaches intuitively, (1) the _negative UNL_ +approach, and (2) _lower quorum_: simply lowering the quorum from 80% to 60% without the negative UNL. The negative UNL approach uses consensus to come up with a list of unreliable validators, which are then removed from the effective UNL temporarily. With this approach, the list of unreliable validators is agreed @@ -462,75 +453,75 @@ Next we compare the two approaches quantitatively with examples, and apply Theorem 8 of [Analysis of the XRP Ledger Consensus Protocol](https://arxiv.org/abs/1802.07242) paper: -*XRP LCP guarantees fork safety if **Oi,j > nj / 2 + +_XRP LCP guarantees fork safety if **Oi,j > nj / 2 + ni − qi + ti,j** for every pair of nodes -Pi, Pj,* +Pi, Pj,_ -where *Oi,j* is the overlapping requirement, nj and +where _Oi,j_ is the overlapping requirement, nj and ni are UNL sizes, qi is the quorum size of Pi, -*ti,j = min(ti, tj, Oi,j)*, and +_ti,j = min(ti, tj, Oi,j)_, and ti and tj are the number of faults can be tolerated by Pi and Pj. -We denote *UNLi* as *Pi's UNL*, and *|UNLi|* as -the size of *Pi's UNL*. +We denote _UNLi_ as _Pi's UNL_, and _|UNLi|_ as +the size of _Pi's UNL_. -Assuming *|UNLi| = |UNLj|*, let's consider the following +Assuming _|UNLi| = |UNLj|_, let's consider the following three cases: -1. With 80% quorum and 20% faults, *Oi,j > 100% / 2 + 100% - 80% + -20% = 90%*. I.e. fork safety requires > 90% UNL overlaps. This is one of the -results in the analysis paper. - -1. If the quorum is 60%, the relationship between the overlapping requirement -and the faults that can be tolerated is *Oi,j > 90% + -ti,j*. Under the same overlapping condition (i.e. 90%), to guarantee -the fork safety, the network cannot tolerate any faults. So under the same -overlapping condition, if the quorum is simply lowered, the network can tolerate -fewer faults. - -1. With the negative UNL approach, we want to argue that the inequation -*Oi,j > nj / 2 + ni − qi + -ti,j* is always true to guarantee fork safety, while the negative UNL -protocol runs, i.e. the effective quorum is lowered without weakening the -network's fault tolerance. To make the discussion easier, we rewrite the -inequation as *Oi,j > nj / 2 + (ni − -qi) + min(ti, tj)*, where Oi,j is -dropped from the definition of ti,j because *Oi,j > -min(ti, tj)* always holds under the parameters we will -use. Assuming a validator V is added to the negative UNL, now let's consider the -4 cases: - - 1. V is not on UNLi nor UNLj - - The inequation holds because none of the variables change. - - 1. V is on UNLi but not on UNLj - - The value of *(ni − qi)* is smaller. The value of - *min(ti, tj)* could be smaller too. Other - variables do not change. Overall, the left side of the inequation does - not change, but the right side is smaller. So the inequation holds. - - 1. V is not on UNLi but on UNLj - - The value of *nj / 2* is smaller. The value of - *min(ti, tj)* could be smaller too. Other - variables do not change. Overall, the left side of the inequation does - not change, but the right side is smaller. So the inequation holds. - - 1. V is on both UNLi and UNLj - - The value of *Oi,j* is reduced by 1. The values of - *nj / 2*, *(ni − qi)*, and - *min(ti, tj)* are reduced by 0.5, 0.2, and 1 - respectively. The right side is reduced by 1.7. Overall, the left side - of the inequation is reduced by 1, and the right side is reduced by 1.7. - So the inequation holds. - - The inequation holds for all the cases. So with the negative UNL approach, - the network's fork safety is preserved, while the quorum is lowered that - increases the network's liveness. +1. With 80% quorum and 20% faults, _Oi,j > 100% / 2 + 100% - 80% + + 20% = 90%_. I.e. fork safety requires > 90% UNL overlaps. This is one of the + results in the analysis paper. + +1. If the quorum is 60%, the relationship between the overlapping requirement + and the faults that can be tolerated is _Oi,j > 90% + + ti,j_. Under the same overlapping condition (i.e. 90%), to guarantee + the fork safety, the network cannot tolerate any faults. So under the same + overlapping condition, if the quorum is simply lowered, the network can tolerate + fewer faults. + +1. With the negative UNL approach, we want to argue that the inequation + _Oi,j > nj / 2 + ni − qi + + ti,j_ is always true to guarantee fork safety, while the negative UNL + protocol runs, i.e. the effective quorum is lowered without weakening the + network's fault tolerance. To make the discussion easier, we rewrite the + inequation as _Oi,j > nj / 2 + (ni − + qi) + min(ti, tj)_, where Oi,j is + dropped from the definition of ti,j because _Oi,j > + min(ti, tj)_ always holds under the parameters we will + use. Assuming a validator V is added to the negative UNL, now let's consider the + 4 cases: + + 1. V is not on UNLi nor UNLj + + The inequation holds because none of the variables change. + + 1. V is on UNLi but not on UNLj + + The value of *(ni − qi)* is smaller. The value of + *min(ti, tj)* could be smaller too. Other + variables do not change. Overall, the left side of the inequation does + not change, but the right side is smaller. So the inequation holds. + + 1. V is not on UNLi but on UNLj + + The value of *nj / 2* is smaller. The value of + *min(ti, tj)* could be smaller too. Other + variables do not change. Overall, the left side of the inequation does + not change, but the right side is smaller. So the inequation holds. + + 1. V is on both UNLi and UNLj + + The value of *Oi,j* is reduced by 1. The values of + *nj / 2*, *(ni − qi)*, and + *min(ti, tj)* are reduced by 0.5, 0.2, and 1 + respectively. The right side is reduced by 1.7. Overall, the left side + of the inequation is reduced by 1, and the right side is reduced by 1.7. + So the inequation holds. + + The inequation holds for all the cases. So with the negative UNL approach, + the network's fork safety is preserved, while the quorum is lowered that + increases the network's liveness.

Question: We have observed that occasionally a validator wanders off on its own chain. How is this case handled by the negative UNL algorithm?

@@ -565,11 +556,11 @@ will be used after that. We want to see the test cases still pass with real network delay. A test case specifies: 1. a UNL with different number of validators for different test cases, -1. a network with zero or more non-validator nodes, +1. a network with zero or more non-validator nodes, 1. a sequence of validator reliability change events (by killing/restarting nodes, or by running modified rippled that does not send all validation messages), -1. the correct outcomes. +1. the correct outcomes. For all the test cases, the correct outcomes are verified by examining logs. We will grep the log to see if the correct negative UNLs are generated, and whether @@ -579,6 +570,7 @@ timing parameters of rippled will be changed to have faster ledger time. Most if not all test cases do not need client transactions. For example, the test cases for the prototype: + 1. A 10-validator UNL. 1. The network does not have other nodes. 1. The validators will be started from the genesis. Once they start to produce @@ -587,11 +579,11 @@ For example, the test cases for the prototype: 1. A sequence of events (or the lack of events) such as a killed validator is added to the negative UNL. -#### Roads Not Taken: Test with Extended CSF +#### Roads Not Taken: Test with Extended CSF We considered testing with the current unit test framework, specifically the [Consensus Simulation Framework](https://github.com/ripple/rippled/blob/develop/src/test/csf/README.md) (CSF). However, the CSF currently can only test the generic consensus algorithm as in the paper: [Analysis of the XRP Ledger Consensus -Protocol](https://arxiv.org/abs/1802.07242). \ No newline at end of file +Protocol](https://arxiv.org/abs/1802.07242). diff --git a/docs/0010-ledger-replay/README.md b/docs/0010-ledger-replay/README.md index 170fd15c43e..c82d9b1906d 100644 --- a/docs/0010-ledger-replay/README.md +++ b/docs/0010-ledger-replay/README.md @@ -82,7 +82,9 @@ pattern and the way coroutines are implemented, where every yield saves the spot in the code where it left off and every resume jumps back to that spot. ### Sequence Diagram + ![Sequence diagram](./ledger_replay_sequence.png?raw=true "A successful ledger replay") ### Class Diagram + ![Class diagram](./ledger_replay_classes.png?raw=true "Ledger replay classes") diff --git a/docs/CheatSheet.md b/docs/CheatSheet.md index 3b70c7c8f72..60a99f587ac 100644 --- a/docs/CheatSheet.md +++ b/docs/CheatSheet.md @@ -16,5 +16,5 @@ ## Function - Minimize external dependencies - * Pass options in the ctor instead of using theConfig - * Use as few other classes as possible + - Pass options in the ctor instead of using theConfig + - Use as few other classes as possible diff --git a/docs/CodingStyle.md b/docs/CodingStyle.md index 0ff50c780d2..3c26709047e 100644 --- a/docs/CodingStyle.md +++ b/docs/CodingStyle.md @@ -1,18 +1,18 @@ # Coding Standards -Coding standards used here gradually evolve and propagate through +Coding standards used here gradually evolve and propagate through code reviews. Some aspects are enforced more strictly than others. ## Rules -These rules only apply to our own code. We can't enforce any sort of +These rules only apply to our own code. We can't enforce any sort of style on the external repositories and libraries we include. The best guideline is to maintain the standards that are used in those libraries. -* Tab inserts 4 spaces. No tab characters. -* Braces are indented in the [Allman style][1]. -* Modern C++ principles. No naked ```new``` or ```delete```. -* Line lengths limited to 80 characters. Exceptions limited to data and tables. +- Tab inserts 4 spaces. No tab characters. +- Braces are indented in the [Allman style][1]. +- Modern C++ principles. No naked `new` or `delete`. +- Line lengths limited to 80 characters. Exceptions limited to data and tables. ## Guidelines @@ -21,17 +21,17 @@ why you're doing it. Think, use common sense, and consider that this your changes will probably need to be maintained long after you've moved on to other projects. -* Use white space and blank lines to guide the eye and keep your intent clear. -* Put private data members at the top of a class, and the 6 public special -members immediately after, in the following order: - * Destructor - * Default constructor - * Copy constructor - * Copy assignment - * Move constructor - * Move assignment -* Don't over-inline by defining large functions within the class -declaration, not even for template classes. +- Use white space and blank lines to guide the eye and keep your intent clear. +- Put private data members at the top of a class, and the 6 public special + members immediately after, in the following order: + - Destructor + - Default constructor + - Copy constructor + - Copy assignment + - Move constructor + - Move assignment +- Don't over-inline by defining large functions within the class + declaration, not even for template classes. ## Formatting @@ -39,44 +39,44 @@ The goal of source code formatting should always be to make things as easy to read as possible. White space is used to guide the eye so that details are not overlooked. Blank lines are used to separate code into "paragraphs." -* Always place a space before and after all binary operators, +- Always place a space before and after all binary operators, especially assignments (`operator=`). -* The `!` operator should be preceded by a space, but not followed by one. -* The `~` operator should be preceded by a space, but not followed by one. -* The `++` and `--` operators should have no spaces between the operator and +- The `!` operator should be preceded by a space, but not followed by one. +- The `~` operator should be preceded by a space, but not followed by one. +- The `++` and `--` operators should have no spaces between the operator and the operand. -* A space never appears before a comma, and always appears after a comma. -* Don't put spaces after a parenthesis. A typical member function call might +- A space never appears before a comma, and always appears after a comma. +- Don't put spaces after a parenthesis. A typical member function call might look like this: `foobar (1, 2, 3);` -* In general, leave a blank line before an `if` statement. -* In general, leave a blank line after a closing brace `}`. -* Do not place code on the same line as any opening or +- In general, leave a blank line before an `if` statement. +- In general, leave a blank line after a closing brace `}`. +- Do not place code on the same line as any opening or closing brace. -* Do not write `if` statements all-on-one-line. The exception to this is when +- Do not write `if` statements all-on-one-line. The exception to this is when you've got a sequence of similar `if` statements, and are aligning them all vertically to highlight their similarities. -* In an `if-else` statement, if you surround one half of the statement with +- In an `if-else` statement, if you surround one half of the statement with braces, you also need to put braces around the other half, to match. -* When writing a pointer type, use this spacing: `SomeObject* myObject`. +- When writing a pointer type, use this spacing: `SomeObject* myObject`. Technically, a more correct spacing would be `SomeObject *myObject`, but it makes more sense for the asterisk to be grouped with the type name, since being a pointer is part of the type, not the variable name. The only time that this can lead to any problems is when you're declaring multiple pointers of the same type in the same statement - which leads on to the next rule: -* When declaring multiple pointers, never do so in a single statement, e.g. +- When declaring multiple pointers, never do so in a single statement, e.g. `SomeObject* p1, *p2;` - instead, always split them out onto separate lines and write the type name again, to make it quite clear what's going on, and avoid the danger of missing out any vital asterisks. -* The previous point also applies to references, so always put the `&` next to +- The previous point also applies to references, so always put the `&` next to the type rather than the variable, e.g. `void foo (Thing const& thing)`. And don't put a space on both sides of the `*` or `&` - always put a space after it, but never before it. -* The word `const` should be placed to the right of the thing that it modifies, +- The word `const` should be placed to the right of the thing that it modifies, for consistency. For example `int const` refers to an int which is const. `int const*` is a pointer to an int which is const. `int *const` is a const pointer to an int. -* Always place a space in between the template angle brackets and the type +- Always place a space in between the template angle brackets and the type name. Template code is already hard enough to read! [1]: http://en.wikipedia.org/wiki/Indent_style#Allman_style diff --git a/docs/HeapProfiling.md b/docs/HeapProfiling.md index c8de1eb26f6..2871cccaba9 100644 --- a/docs/HeapProfiling.md +++ b/docs/HeapProfiling.md @@ -31,7 +31,7 @@ and header under /opt/local/include: $ scons clang profile-jemalloc=/opt/local ----------------------- +--- ## Using the jemalloc library from within the code @@ -60,4 +60,3 @@ Linking against the jemalloc library will override the system's default `malloc()` and related functions with jemalloc's implementation. This is the case even if the code is not instrumented to use jemalloc's specific API. - diff --git a/docs/README.md b/docs/README.md index 55b9e30e04d..c95a8717292 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,7 +7,6 @@ Install these dependencies: - [Doxygen](http://www.doxygen.nl): All major platforms have [official binary distributions](http://www.doxygen.nl/download.html#srcbin), or you can build from [source](http://www.doxygen.nl/download.html#srcbin). - - MacOS: We recommend installing via Homebrew: `brew install doxygen`. The executable will be installed in `/usr/local/bin` which is already in the default `PATH`. @@ -21,18 +20,15 @@ Install these dependencies: $ ln -s /Applications/Doxygen.app/Contents/Resources/doxygen /usr/local/bin/doxygen ``` -- [PlantUML](http://plantuml.com): - +- [PlantUML](http://plantuml.com): 1. Install a functioning Java runtime, if you don't already have one. 2. Download [`plantuml.jar`](http://sourceforge.net/projects/plantuml/files/plantuml.jar/download). - [Graphviz](https://www.graphviz.org): - - Linux: Install from your package manager. - Windows: Use an [official installer](https://graphviz.gitlab.io/_pages/Download/Download_windows.html). - MacOS: Install via Homebrew: `brew install graphviz`. - ## Docker Instead of installing the above dependencies locally, you can use the official @@ -40,14 +36,16 @@ build environment Docker image, which has all of them installed already. 1. Install [Docker](https://docs.docker.com/engine/installation/) 2. Pull the image: - ``` - sudo docker pull rippleci/rippled-ci-builder:2944b78d22db - ``` + +``` +sudo docker pull rippleci/rippled-ci-builder:2944b78d22db +``` + 3. Run the image from the project folder: - ``` - sudo docker run -v $PWD:/opt/rippled --rm rippleci/rippled-ci-builder:2944b78d22db - ``` +``` +sudo docker run -v $PWD:/opt/rippled --rm rippleci/rippled-ci-builder:2944b78d22db +``` ## Build diff --git a/docs/build/conan.md b/docs/build/conan.md index 5f1ff7ae983..9dcd2c8f1c9 100644 --- a/docs/build/conan.md +++ b/docs/build/conan.md @@ -5,7 +5,6 @@ we should first understand _why_ we use Conan, and to understand that, we need to understand how we use CMake. - ### CMake Technically, you don't need CMake to build this project. @@ -33,9 +32,9 @@ Parameters include: - where to find the compiler and linker - where to find dependencies, e.g. libraries and headers - how to link dependencies, e.g. any special compiler or linker flags that - need to be used with them, including preprocessor definitions + need to be used with them, including preprocessor definitions - how to compile translation units, e.g. with optimizations, debug symbols, - position-independent code, etc. + position-independent code, etc. - on Windows, which runtime library to link with For some of these parameters, like the build system and compiler, @@ -54,7 +53,6 @@ Most humans prefer to put them into a configuration file, once, that CMake can read every time it is configured. For CMake, that file is a [toolchain file][toolchain]. - ### Conan These next few paragraphs on Conan are going to read much like the ones above @@ -79,10 +77,10 @@ Those files include: - A single toolchain file. - For every dependency, a CMake [package configuration file][pcf], - [package version file][pvf], and for every build type, a package - targets file. - Together, these files implement version checking and define `IMPORTED` - targets for the dependencies. + [package version file][pvf], and for every build type, a package + targets file. + Together, these files implement version checking and define `IMPORTED` + targets for the dependencies. The toolchain file itself amends the search path ([`CMAKE_PREFIX_PATH`][prefix_path]) so that [`find_package()`][find_package] diff --git a/docs/build/depend.md b/docs/build/depend.md index 42fd41a26e8..2fa14378aa3 100644 --- a/docs/build/depend.md +++ b/docs/build/depend.md @@ -2,8 +2,7 @@ We recommend two different methods to depend on libxrpl in your own [CMake][] project. Both methods add a CMake library target named `xrpl::libxrpl`. - -## Conan requirement +## Conan requirement The first method adds libxrpl as a [Conan][] requirement. With this method, there is no need for a Git [submodule][]. @@ -48,7 +47,6 @@ cmake \ cmake --build . --parallel ``` - ## CMake subdirectory The second method adds the [rippled][] project as a CMake @@ -90,7 +88,6 @@ cmake \ cmake --build . --parallel ``` - [add_subdirectory]: https://cmake.org/cmake/help/latest/command/add_subdirectory.html [submodule]: https://git-scm.com/book/en/v2/Git-Tools-Submodules [rippled]: https://github.com/ripple/rippled diff --git a/docs/build/environment.md b/docs/build/environment.md index 760be144d8d..c6b735ba48d 100644 --- a/docs/build/environment.md +++ b/docs/build/environment.md @@ -5,42 +5,39 @@ platforms: Linux, macOS, or Windows. [BUILD.md]: ../../BUILD.md - ## Linux Package ecosystems vary across Linux distributions, so there is no one set of instructions that will work for every Linux user. -These instructions are written for Ubuntu 22.04. -They are largely copied from the [script][1] used to configure our Docker -container for continuous integration. -That script handles many more responsibilities. -These instructions are just the bare minimum to build one configuration of -rippled. -You can check that codebase for other Linux distributions and versions. -If you cannot find yours there, -then we hope that these instructions can at least guide you in the right -direction. +The instructions below are written for Debian 12 (Bookworm). ``` -apt update -apt install --yes curl git libssl-dev pipx python3.10-dev python3-pip make g++-11 libprotobuf-dev protobuf-compiler - -curl --location --remote-name \ - "https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1.tar.gz" -tar -xzf cmake-3.25.1.tar.gz -rm cmake-3.25.1.tar.gz -cd cmake-3.25.1 -./bootstrap --parallel=$(nproc) -make --jobs $(nproc) -make install -cd .. - -pipx install 'conan<2' -pipx ensurepath +export GCC_RELEASE=12 +sudo apt update +sudo apt install --yes gcc-${GCC_RELEASE} g++-${GCC_RELEASE} python3-pip \ + python-is-python3 python3-venv python3-dev curl wget ca-certificates \ + git build-essential cmake ninja-build libc6-dev +sudo pip install --break-system-packages conan + +sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${GCC_RELEASE} 999 +sudo update-alternatives --install \ + /usr/bin/gcc gcc /usr/bin/gcc-${GCC_RELEASE} 100 \ + --slave /usr/bin/g++ g++ /usr/bin/g++-${GCC_RELEASE} \ + --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-${GCC_RELEASE} \ + --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-${GCC_RELEASE} \ + --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-${GCC_RELEASE} \ + --slave /usr/bin/gcov gcov /usr/bin/gcov-${GCC_RELEASE} \ + --slave /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-tool-${GCC_RELEASE} \ + --slave /usr/bin/gcov-dump gcov-dump /usr/bin/gcov-dump-${GCC_RELEASE} \ + --slave /usr/bin/lto-dump lto-dump /usr/bin/lto-dump-${GCC_RELEASE} +sudo update-alternatives --auto cc +sudo update-alternatives --auto gcc ``` -[1]: https://github.com/thejohnfreeman/rippled-docker/blob/master/ubuntu-22.04/install.sh - +If you use different Linux distribution, hope the instruction above can guide +you in the right direction. We try to maintain compatibility with all recent +compiler releases, so if you use a rolling distribution like e.g. Arch or CentOS +then there is a chance that everything will "just work". ## macOS @@ -53,6 +50,33 @@ minimum required (see [BUILD.md][]). clang --version ``` +### Install Xcode Specific Version (Optional) + +If you develop other applications using XCode you might be consistently updating to the newest version of Apple Clang. +This will likely cause issues building rippled. You may want to install a specific version of Xcode: + +1. **Download Xcode** + - Visit [Apple Developer Downloads](https://developer.apple.com/download/more/) + - Sign in with your Apple Developer account + - Search for an Xcode version that includes **Apple Clang (Expected Version)** + - Download the `.xip` file + +2. **Install and Configure Xcode** + + ```bash + # Extract the .xip file and rename for version management + # Example: Xcode_16.2.app + + # Move to Applications directory + sudo mv Xcode_16.2.app /Applications/ + + # Set as default toolchain (persistent) + sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + + # Set as environment variable (temporary) + export DEVELOPER_DIR=/Applications/Xcode_16.2.app/Contents/Developer + ``` + The command line developer tools should include Git too: ``` @@ -72,10 +96,10 @@ and use it to install Conan: brew update brew install xz brew install pyenv -pyenv install 3.10-dev -pyenv global 3.10-dev +pyenv install 3.11 +pyenv global 3.11 eval "$(pyenv init -)" -pip install 'conan<2' +pip install 'conan' ``` Install CMake with Homebrew too: diff --git a/docs/build/install.md b/docs/build/install.md index af0d6f335c0..7be01ce726f 100644 --- a/docs/build/install.md +++ b/docs/build/install.md @@ -6,7 +6,6 @@ like CentOS. Installing from source is an option for all platforms, and the only supported option for installing custom builds. - ## From source From a source build, you can install rippled and libxrpl using CMake's @@ -21,25 +20,23 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and [1]: https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html - ## With the APT package manager -1. Update repositories: +1. Update repositories: sudo apt update -y -2. Install utilities: +2. Install utilities: sudo apt install -y apt-transport-https ca-certificates wget gnupg -3. Add Ripple's package-signing GPG key to your list of trusted keys: +3. Add Ripple's package-signing GPG key to your list of trusted keys: sudo mkdir /usr/local/share/keyrings/ wget -q -O - "https://repos.ripple.com/repos/api/gpg/key/public" | gpg --dearmor > ripple-key.gpg sudo mv ripple-key.gpg /usr/local/share/keyrings - -4. Check the fingerprint of the newly-added key: +4. Check the fingerprint of the newly-added key: gpg /usr/local/share/keyrings/ripple-key.gpg @@ -51,37 +48,34 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and uid TechOps Team at Ripple sub rsa3072 2019-02-14 [E] [expires: 2026-02-17] - In particular, make sure that the fingerprint matches. (In the above example, the fingerprint is on the third line, starting with `C001`.) -4. Add the appropriate Ripple repository for your operating system version: +5. Add the appropriate Ripple repository for your operating system version: echo "deb [signed-by=/usr/local/share/keyrings/ripple-key.gpg] https://repos.ripple.com/repos/rippled-deb focal stable" | \ sudo tee -a /etc/apt/sources.list.d/ripple.list The above example is appropriate for **Ubuntu 20.04 Focal Fossa**. For other operating systems, replace the word `focal` with one of the following: - - `jammy` for **Ubuntu 22.04 Jammy Jellyfish** - `bionic` for **Ubuntu 18.04 Bionic Beaver** - `bullseye` for **Debian 11 Bullseye** - `buster` for **Debian 10 Buster** If you want access to development or pre-release versions of `rippled`, use one of the following instead of `stable`: - - `unstable` - Pre-release builds ([`release` branch](https://github.com/ripple/rippled/tree/release)) - `nightly` - Experimental/development builds ([`develop` branch](https://github.com/ripple/rippled/tree/develop)) **Warning:** Unstable and nightly builds may be broken at any time. Do not use these builds for production servers. -5. Fetch the Ripple repository. +6. Fetch the Ripple repository. sudo apt -y update -6. Install the `rippled` software package: +7. Install the `rippled` software package: sudo apt -y install rippled -7. Check the status of the `rippled` service: +8. Check the status of the `rippled` service: systemctl status rippled.service @@ -89,24 +83,22 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and sudo systemctl start rippled.service -8. Optional: allow `rippled` to bind to privileged ports. +9. Optional: allow `rippled` to bind to privileged ports. This allows you to serve incoming API requests on port 80 or 443. (If you want to do so, you must also update the config file's port settings.) sudo setcap 'cap_net_bind_service=+ep' /opt/ripple/bin/rippled - ## With the YUM package manager -1. Install the Ripple RPM repository: +1. Install the Ripple RPM repository: Choose the appropriate RPM repository for the stability of releases you want: - - `stable` for the latest production release (`master` branch) - `unstable` for pre-release builds (`release` branch) - `nightly` for experimental/development builds (`develop` branch) - *Stable* + _Stable_ cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo [ripple-stable] @@ -118,7 +110,7 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and gpgkey=https://repos.ripple.com/repos/rippled-rpm/stable/repodata/repomd.xml.key REPOFILE - *Unstable* + _Unstable_ cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo [ripple-unstable] @@ -130,7 +122,7 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and gpgkey=https://repos.ripple.com/repos/rippled-rpm/unstable/repodata/repomd.xml.key REPOFILE - *Nightly* + _Nightly_ cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo [ripple-nightly] @@ -142,18 +134,18 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and gpgkey=https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key REPOFILE -2. Fetch the latest repo updates: +2. Fetch the latest repo updates: sudo yum -y update -3. Install the new `rippled` package: +3. Install the new `rippled` package: sudo yum install -y rippled -4. Configure the `rippled` service to start on boot: +4. Configure the `rippled` service to start on boot: sudo systemctl enable rippled.service -5. Start the `rippled` service: +5. Start the `rippled` service: sudo systemctl start rippled.service diff --git a/docs/consensus.md b/docs/consensus.md index 4ee5aa70dca..067e15d0c87 100644 --- a/docs/consensus.md +++ b/docs/consensus.md @@ -3,7 +3,7 @@ **This section is a work in progress!!** Consensus is the task of reaching agreement within a distributed system in the -presence of faulty or even malicious participants. This document outlines the +presence of faulty or even malicious participants. This document outlines the [XRP Ledger Consensus Algorithm](https://arxiv.org/abs/1802.07242) as implemented in [rippled](https://github.com/ripple/rippled), but focuses on its utility as a generic consensus algorithm independent of the @@ -15,38 +15,38 @@ collectively trusted subnetworks. ## Distributed Agreement A challenge for distributed systems is reaching agreement on changes in shared -state. For the Ripple network, the shared state is the current ledger--account -information, account balances, order books and other financial data. We will +state. For the Ripple network, the shared state is the current ledger--account +information, account balances, order books and other financial data. We will refer to shared distributed state as a /ledger/ throughout the remainder of this document. ![Ledger Chain](images/consensus/ledger_chain.png "Ledger Chain") As shown above, new ledgers are made by applying a set of transactions to the -prior ledger. For the Ripple network, transactions include payments, +prior ledger. For the Ripple network, transactions include payments, modification of account settings, updates to offers and more. In a centralized system, generating the next ledger is trivial since there is a single unique arbiter of which transactions to include and how to apply them to -a ledger. For decentralized systems, participants must resolve disagreements on +a ledger. For decentralized systems, participants must resolve disagreements on the set of transactions to include, the order to apply those transactions, and -even the resulting ledger after applying the transactions. This is even more +even the resulting ledger after applying the transactions. This is even more difficult when some participants are faulty or malicious. -The Ripple network is a decentralized and **trust-full** network. Anyone is free +The Ripple network is a decentralized and **trust-full** network. Anyone is free to join and participants are free to choose a subset of peers that are collectively trusted to not collude in an attempt to defraud the participant. Leveraging this network of trust, the Ripple algorithm has two main components. -* *Consensus* in which network participants agree on the transactions to apply +- _Consensus_ in which network participants agree on the transactions to apply to a prior ledger, based on the positions of their chosen peers. -* *Validation* in which network participants agree on what ledger was +- _Validation_ in which network participants agree on what ledger was generated, based on the ledgers generated by chosen peers. These phases are continually repeated to process transactions submitted to the network, generating successive ledgers and giving rise to the blockchain ledger -history depicted below. In this diagram, time is flowing to the right, but -links between ledgers point backward to the parent. Also note the alternate +history depicted below. In this diagram, time is flowing to the right, but +links between ledgers point backward to the parent. Also note the alternate Ledger 2 that was generated by some participants, but which failed validation and was abandoned. @@ -54,7 +54,7 @@ and was abandoned. The remainder of this section describes the Consensus and Validation algorithms in more detail and is meant as a companion guide to understanding the generic -implementation in `rippled`. The document **does not** discuss correctness, +implementation in `rippled`. The document **does not** discuss correctness, fault-tolerance or liveness properties of the algorithms or the full details of how they integrate within `rippled` to support the Ripple Consensus Ledger. @@ -62,76 +62,76 @@ how they integrate within `rippled` to support the Ripple Consensus Ledger. ### Definitions -* The *ledger* is the shared distributed state. Each ledger has a unique ID to - distinguish it from all other ledgers. During consensus, the *previous*, - *prior* or *last-closed* ledger is the most recent ledger seen by consensus +- The _ledger_ is the shared distributed state. Each ledger has a unique ID to + distinguish it from all other ledgers. During consensus, the _previous_, + _prior_ or _last-closed_ ledger is the most recent ledger seen by consensus and is the basis upon which it will build the next ledger. -* A *transaction* is an instruction for an atomic change in the ledger state. A +- A _transaction_ is an instruction for an atomic change in the ledger state. A unique ID distinguishes a transaction from other transactions. -* A *transaction set* is a set of transactions under consideration by consensus. - The goal of consensus is to reach agreement on this set. The generic +- A _transaction set_ is a set of transactions under consideration by consensus. + The goal of consensus is to reach agreement on this set. The generic consensus algorithm does not rely on an ordering of transactions within the set, nor does it specify how to apply a transaction set to a ledger to - generate a new ledger. A unique ID distinguishes a set of transactions from + generate a new ledger. A unique ID distinguishes a set of transactions from all other sets of transactions. -* A *node* is one of the distributed actors running the consensus algorithm. It +- A _node_ is one of the distributed actors running the consensus algorithm. It has a unique ID to distinguish it from all other nodes. -* A *peer* of a node is another node that it has chosen to follow and which it - believes will not collude with other chosen peers. The choice of peers is not +- A _peer_ of a node is another node that it has chosen to follow and which it + believes will not collude with other chosen peers. The choice of peers is not symmetric, since participants can decide on their chosen sets independently. -* A /position/ is the current belief of the next ledger's transaction set and +- A /position/ is the current belief of the next ledger's transaction set and close time. Position can refer to the node's own position or the position of a peer. -* A *proposal* is one of a sequence of positions a node shares during consensus. +- A _proposal_ is one of a sequence of positions a node shares during consensus. An initial proposal contains the starting position taken by a node before it - considers any peer positions. If a node subsequently updates its position in - response to its peers, it will issue an updated proposal. A proposal is + considers any peer positions. If a node subsequently updates its position in + response to its peers, it will issue an updated proposal. A proposal is uniquely identified by the ID of the proposing node, the ID of the position taken, the ID of the prior ledger the proposal is for, and the sequence number of the proposal. -* A *dispute* is a transaction that is either not part of a node's position or +- A _dispute_ is a transaction that is either not part of a node's position or not in a peer's position. During consensus, the node will add or remove disputed transactions from its position based on that transaction's support amongst its peers. Note that most types have an ID as a lightweight identifier of instances of that -type. Consensus often operates on the IDs directly since the underlying type is -potentially expensive to share over the network. For example, proposal's only -contain the ID of the position of a peer. Since many peers likely have the same +type. Consensus often operates on the IDs directly since the underlying type is +potentially expensive to share over the network. For example, proposal's only +contain the ID of the position of a peer. Since many peers likely have the same position, this reduces the need to send the full transaction set multiple times. Instead, a node can request the transaction set from the network if necessary. -### Overview +### Overview ![Consensus Overview](images/consensus/consensus_overview.png "Consensus Overview") The diagram above is an overview of the consensus process from the perspective -of a single participant. Recall that during a single consensus round, a node is +of a single participant. Recall that during a single consensus round, a node is trying to agree with its peers on which transactions to apply to its prior -ledger when generating the next ledger. It also attempts to agree on the -[network time when the ledger closed](#effective_close_time). There are +ledger when generating the next ledger. It also attempts to agree on the +[network time when the ledger closed](#effective_close_time). There are 3 main phases to a consensus round: -* A call to `startRound` places the node in the `Open` phase. In this phase, -the node is waiting for transactions to include in its open ledger. -* At some point, the node will `Close` the open ledger and transition to the -`Establish` phase. In this phase, the node shares/receives peer proposals on -which transactions should be accepted in the closed ledger. -* At some point, the node determines it has reached consensus with its peers on -which transactions to include. It transitions to the `Accept` phase. In this -phase, the node works on applying the transactions to the prior ledger to -generate a new closed ledger. Once the new ledger is completed, the node shares -the validated ledger hash with the network and makes a call to `startRound` to -start the cycle again for the next ledger. +- A call to `startRound` places the node in the `Open` phase. In this phase, + the node is waiting for transactions to include in its open ledger. +- At some point, the node will `Close` the open ledger and transition to the + `Establish` phase. In this phase, the node shares/receives peer proposals on + which transactions should be accepted in the closed ledger. +- At some point, the node determines it has reached consensus with its peers on + which transactions to include. It transitions to the `Accept` phase. In this + phase, the node works on applying the transactions to the prior ledger to + generate a new closed ledger. Once the new ledger is completed, the node shares + the validated ledger hash with the network and makes a call to `startRound` to + start the cycle again for the next ledger. Throughout, a heartbeat timer calls `timerEntry` at a regular frequency to drive the process forward. Although the `startRound` call occurs at arbitrary times based on when the initial round began and the time it takes to apply transactions, the transitions from `Open` to `Establish` and `Establish` to -`Accept` only occur during calls to `timerEntry`. Similarly, transactions can +`Accept` only occur during calls to `timerEntry`. Similarly, transactions can arrive at arbitrary times, independent of the heartbeat timer. Transactions received after the `Open` to `Close` transition and not part of peer proposals -won't be considered until the next consensus round. They are represented above +won't be considered until the next consensus round. They are represented above by the light green triangles. Peer proposals are issued by a node during a `timerEntry` call, but since peers @@ -139,16 +139,16 @@ do not synchronize `timerEntry` calls, they are received by other peers at arbitrary times. Peer proposals are only considered if received prior to the `Establish` to `Accept` transition, and only if the peer is working on the same prior ledger. Peer proposals received after consensus is reached will not be -meaningful and are represented above by the circle with the X in it. Only +meaningful and are represented above by the circle with the X in it. Only proposals from chosen peers are considered. -### Effective Close Time ### {#effective_close_time} - +### Effective Close Time ### {#effective_close_time} + In addition to agreeing on a transaction set, each consensus round tries to -agree on the time the ledger closed. Each node calculates its own close time -when it closes the open ledger. This exact close time is rounded to the nearest -multiple of the current *effective close time resolution*. It is this -*effective close time* that nodes seek to agree on. This allows servers to +agree on the time the ledger closed. Each node calculates its own close time +when it closes the open ledger. This exact close time is rounded to the nearest +multiple of the current _effective close time resolution_. It is this +_effective close time_ that nodes seek to agree on. This allows servers to derive a common time for a ledger without the need for perfectly synchronized clocks. As depicted below, the 3 pink arrows represent exact close times from 3 consensus nodes that round to the same effective close time given the current @@ -158,9 +158,9 @@ different effective close time given the current resolution. ![Effective Close Time](images/consensus/EffCloseTime.png "Effective Close Time") The effective close time is part of the node's position and is shared with peers -in its proposals. Just like the position on the consensus transaction set, a +in its proposals. Just like the position on the consensus transaction set, a node will update its close time position in response to its peers' effective -close time positions. Peers can agree to disagree on the close time, in which +close time positions. Peers can agree to disagree on the close time, in which case the effective close time is taken as 1 second past the prior close. The close time resolution is itself dynamic, decreasing (coarser) resolution in @@ -173,12 +173,12 @@ reach close time consensus. Internally, a node operates under one of the following consensus modes. Either of the first two modes may be chosen when a consensus round starts. -* *Proposing* indicates the node is a full-fledged consensus participant. It +- _Proposing_ indicates the node is a full-fledged consensus participant. It takes on positions and sends proposals to its peers. -* *Observing* indicates the node is a passive consensus participant. It +- _Observing_ indicates the node is a passive consensus participant. It maintains a position internally, but does not propose that position to its peers. Instead, it receives peer proposals and updates its position - to track the majority of its peers. This may be preferred if the node is only + to track the majority of its peers. This may be preferred if the node is only being used to track the state of the network or during a start-up phase while it is still synchronizing with the network. @@ -186,14 +186,14 @@ The other two modes are set internally during the consensus round when the node believes it is no longer working on the dominant ledger chain based on peer validations. It checks this on every call to `timerEntry`. -* *Wrong Ledger* indicates the node is not working on the correct prior ledger - and does not have it available. It requests that ledger from the network, but - continues to work towards consensus this round while waiting. If it had been - *proposing*, it will send a special "bowout" proposal to its peers to indicate +- _Wrong Ledger_ indicates the node is not working on the correct prior ledger + and does not have it available. It requests that ledger from the network, but + continues to work towards consensus this round while waiting. If it had been + _proposing_, it will send a special "bowout" proposal to its peers to indicate its change in mode for the rest of this round. For the duration of the round, it defers to peer positions for determining the consensus outcome as if it - were just *observing*. -* *Switch Ledger* indicates that the node has acquired the correct prior ledger + were just _observing_. +- _Switch Ledger_ indicates that the node has acquired the correct prior ledger from the network. Although it now has the correct prior ledger, the fact that it had the wrong one at some point during this round means it is likely behind and should defer to peer positions for determining the consensus outcome. @@ -201,7 +201,7 @@ validations. It checks this on every call to `timerEntry`. ![Consensus Modes](images/consensus/consensus_modes.png "Consensus Modes") Once either wrong ledger or switch ledger are reached, the node cannot -return to proposing or observing until the next consensus round. However, +return to proposing or observing until the next consensus round. However, the node could change its view of the correct prior ledger, so going from switch ledger to wrong ledger and back again is possible. @@ -215,16 +215,16 @@ decide how best to generate the next ledger once it declares consensus. ### Phases As depicted in the overview diagram, consensus is best viewed as a progression -through 3 phases. There are 4 public methods of the generic consensus algorithm +through 3 phases. There are 4 public methods of the generic consensus algorithm that determine this progression -* `startRound` begins a consensus round. -* `timerEntry` is called at a regular frequency (`LEDGER_MIN_CLOSE`) and is the - only call to consensus that can change the phase from `Open` to `Establish` +- `startRound` begins a consensus round. +- `timerEntry` is called at a regular frequency (`LEDGER_MIN_CLOSE`) and is the + only call to consensus that can change the phase from `Open` to `Establish` or `Accept`. -* `peerProposal` is called whenever a peer proposal is received and is what +- `peerProposal` is called whenever a peer proposal is received and is what allows a node to update its position in a subsequent `timerEntry` call. -* `gotTxSet` is called when a transaction set is received from the network. This +- `gotTxSet` is called when a transaction set is received from the network. This is typically in response to a prior request from the node to acquire the transaction set corresponding to a disagreeing peer's position. @@ -234,13 +234,13 @@ actions are taken in response to these calls. #### Open The `Open` phase is a quiescent period to allow transactions to build up in the -node's open ledger. The duration is a trade-off between latency and throughput. +node's open ledger. The duration is a trade-off between latency and throughput. A shorter window reduces the latency to generating the next ledger, but also reduces transaction throughput due to fewer transactions accepted into the ledger. A call to `startRound` would forcibly begin the next consensus round, skipping -completion of the current round. This is not expected during normal operation. +completion of the current round. This is not expected during normal operation. Calls to `peerProposal` or `gotTxSet` simply store the proposal or transaction set for use in the coming `Establish` phase. @@ -254,28 +254,27 @@ the ledger. Under normal circumstances, the open ledger period ends when one of the following is true -* if there are transactions in the open ledger and more than `LEDGER_MIN_CLOSE` - have elapsed. This is the typical behavior. -* if there are no open transactions and a suitably longer idle interval has - elapsed. This increases the opportunity to get some transaction into +- if there are transactions in the open ledger and more than `LEDGER_MIN_CLOSE` + have elapsed. This is the typical behavior. +- if there are no open transactions and a suitably longer idle interval has + elapsed. This increases the opportunity to get some transaction into the next ledger and avoids doing useless work closing an empty ledger. -* if more than half the number of prior round peers have already closed or finished +- if more than half the number of prior round peers have already closed or finished this round. This indicates the node is falling behind and needs to catch up. - When closing the ledger, the node takes its initial position based on the transactions in the open ledger and uses the current time as -its initial close time estimate. If in the proposing mode, the node shares its -initial position with peers. Now that the node has taken a position, it will -consider any peer positions for this round that arrived earlier. The node +its initial close time estimate. If in the proposing mode, the node shares its +initial position with peers. Now that the node has taken a position, it will +consider any peer positions for this round that arrived earlier. The node generates disputed transactions for each transaction not in common with a peer's -position. The node also records the vote of each peer for each disputed +position. The node also records the vote of each peer for each disputed transaction. -In the example below, we suppose our node has closed with transactions 1,2 and 3. It creates disputes +In the example below, we suppose our node has closed with transactions 1,2 and 3. It creates disputes for transactions 2,3 and 4, since at least one peer position differs on each. -##### disputes ##### {#disputes_image} +##### disputes ##### {#disputes_image} ![Disputes](images/consensus/disputes.png "Disputes") @@ -286,22 +285,22 @@ exchanges proposals with peers in an attempt to reach agreement on the consensus transactions and effective close time. A call to `startRound` would forcibly begin the next consensus round, skipping -completion of the current round. This is not expected during normal operation. +completion of the current round. This is not expected during normal operation. Calls to `peerProposal` or `gotTxSet` that reflect new positions will generate disputed transactions for any new disagreements and will update the peer's vote for all disputed transactions. A call to `timerEntry` first checks that the node is working from the correct -prior ledger. If not, the node will update the mode and request the correct -ledger. Otherwise, the node updates the node's position and considers whether -to switch to the `Accepted` phase and declare consensus reached. However, at -least `LEDGER_MIN_CONSENSUS` time must have elapsed before doing either. This +prior ledger. If not, the node will update the mode and request the correct +ledger. Otherwise, the node updates the node's position and considers whether +to switch to the `Accepted` phase and declare consensus reached. However, at +least `LEDGER_MIN_CONSENSUS` time must have elapsed before doing either. This allows peers an opportunity to take an initial position and share it. ##### Update Position In order to achieve consensus, the node is looking for a transaction set that is -supported by a super-majority of peers. The node works towards this set by +supported by a super-majority of peers. The node works towards this set by adding or removing disputed transactions from its position based on an increasing threshold for inclusion. @@ -310,23 +309,23 @@ increasing threshold for inclusion. By starting with a lower threshold, a node initially allows a wide set of transactions into its position. If the establish round continues and the node is "stuck", a higher threshold can focus on accepting transactions with the most -support. The constants that define the thresholds and durations at which the +support. The constants that define the thresholds and durations at which the thresholds change are given by `AV_XXX_CONSENSUS_PCT` and `AV_XXX_CONSENSUS_TIME` respectively, where `XXX` is `INIT`,`MID`,`LATE` and -`STUCK`. The effective close time position is updated using the same +`STUCK`. The effective close time position is updated using the same thresholds. Given the [example disputes above](#disputes_image) and an initial threshold of 50%, our node would retain its position since transaction 1 was not in -dispute and transactions 2 and 3 have 75% support. Since its position did not -change, it would not need to send a new proposal to peers. Peer C would not +dispute and transactions 2 and 3 have 75% support. Since its position did not +change, it would not need to send a new proposal to peers. Peer C would not change either. Peer A would add transaction 3 to its position and Peer B would remove transaction 4 from its position; both would then send an updated position. Conversely, if the diagram reflected a later call to =timerEntry= that occurs in the stuck region with a threshold of say 95%, our node would remove transactions -2 and 3 from its candidate set and send an updated position. Likewise, all the +2 and 3 from its candidate set and send an updated position. Likewise, all the other peers would end up with only transaction 1 in their position. Lastly, if our node were not in the proposing mode, it would not include its own @@ -336,7 +335,7 @@ our node would maintain its position of transactions 1, 2 and 3. ##### Checking Consensus After updating its position, the node checks for supermajority agreement with -its peers on its current position. This agreement is of the exact transaction +its peers on its current position. This agreement is of the exact transaction set, not just the support of individual transactions. That is, if our position is a subset of a peer's position, that counts as a disagreement. Also recall that effective close time agreement allows a supermajority of participants @@ -344,10 +343,10 @@ agreeing to disagree. Consensus is declared when the following 3 clauses are true: -* `LEDGER_MIN_CONSENSUS` time has elapsed in the establish phase -* At least 75% of the prior round proposers have proposed OR this establish +- `LEDGER_MIN_CONSENSUS` time has elapsed in the establish phase +- At least 75% of the prior round proposers have proposed OR this establish phase is `LEDGER_MIN_CONSENSUS` longer than the last round's establish phase -* `minimumConsensusPercentage` of ourself and our peers share the same position +- `minimumConsensusPercentage` of ourself and our peers share the same position The middle condition ensures slower peers have a chance to share positions, but prevents waiting too long on peers that have disconnected. Additionally, a node @@ -364,22 +363,22 @@ logic. Once consensus is reached (or moved on), the node switches to the `Accept` phase and signals to the implementing code that the round is complete. That code is responsible for using the consensus transaction set to generate the next ledger -and calling `startRound` to begin the next round. The implementation has total +and calling `startRound` to begin the next round. The implementation has total freedom on ordering transactions, deciding what to do if consensus moved on, determining whether to retry or abandon local transactions that did not make the consensus set and updating any internal state based on the consensus progress. #### Accept -The `Accept` phase is the terminal phase of the consensus algorithm. Calls to +The `Accept` phase is the terminal phase of the consensus algorithm. Calls to `timerEntry`, `peerProposal` and `gotTxSet` will not change the internal -consensus state while in the accept phase. The expectation is that the +consensus state while in the accept phase. The expectation is that the application specific code is working to generate the new ledger based on the consensus outcome. Once complete, that code should make a call to `startRound` to kick off the next consensus round. The `startRound` call includes the new prior ledger, prior ledger ID and whether the round should begin in the -proposing or observing mode. After setting some initial state, the phase -transitions to `Open`. The node will also check if the provided prior ledger +proposing or observing mode. After setting some initial state, the phase +transitions to `Open`. The node will also check if the provided prior ledger and ID are correct, updating the mode and requesting the proper ledger from the network if necessary. @@ -448,9 +447,9 @@ struct TxSet ### Ledger The `Ledger` type represents the state shared amongst the -distributed participants. Notice that the details of how the next ledger is +distributed participants. Notice that the details of how the next ledger is generated from the prior ledger and the consensus accepted transaction set is -not part of the interface. Within the generic code, this type is primarily used +not part of the interface. Within the generic code, this type is primarily used to know that peers are working on the same tip of the ledger chain and to provide some basic timing data for consensus. @@ -626,7 +625,7 @@ struct Adaptor // Called when consensus operating mode changes void onModeChange(ConsensuMode before, ConsensusMode after); - + // Called when ledger closes. Implementation should generate an initial Result // with position based on the current open ledger's transactions. ConsensusResult onClose(Ledger const &, Ledger const & prev, ConsensusMode mode); @@ -657,27 +656,24 @@ struct Adaptor The implementing class hides many details of the peer communication model from the generic code. -* The `share` member functions are responsible for sharing the given type with a +- The `share` member functions are responsible for sharing the given type with a node's peers, but are agnostic to the mechanism. Ideally, messages are delivered - faster than `LEDGER_GRANULARITY`. -* The generic code does not specify how transactions are submitted by clients, + faster than `LEDGER_GRANULARITY`. +- The generic code does not specify how transactions are submitted by clients, propagated through the network or stored in the open ledger. Indeed, the open ledger is only conceptual from the perspective of the generic code---the initial position and transaction set are opaquely generated in a `Consensus::Result` instance returned from the `onClose` callback. -* The calls to `acquireLedger` and `acquireTxSet` only have non-trivial return - if the ledger or transaction set of interest is available. The implementing +- The calls to `acquireLedger` and `acquireTxSet` only have non-trivial return + if the ledger or transaction set of interest is available. The implementing class is free to block while acquiring, or return the empty option while - servicing the request asynchronously. Due to legacy reasons, the two calls + servicing the request asynchronously. Due to legacy reasons, the two calls are not symmetric. `acquireTxSet` requires the host application to call `gotTxSet` when an asynchronous `acquire` completes. Conversely, `acquireLedger` will be called again later by the consensus code if it still desires the ledger with the hope that the asynchronous acquisition is complete. - ## Validation Coming Soon! - - diff --git a/external/README.md b/external/README.md index c810539fd7d..99ce2c337e5 100644 --- a/external/README.md +++ b/external/README.md @@ -1,14 +1,10 @@ # External Conan recipes -The subdirectories in this directory contain either copies or Conan recipes -of external libraries used by rippled. -The Conan recipes include patches we have not yet pushed upstream. +The subdirectories in this directory contain copies of external libraries used +by rippled. -| 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++ | -| `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 | -| `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. | +| 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++ | +| `ed25519-donna` | [Project](https://github.com/floodyberry/ed25519-donna) | [Ed25519](http://ed25519.cr.yp.to/) digital signatures | +| `secp256k1` | [Project](https://github.com/bitcoin-core/secp256k1) | ECDSA digital signatures using the **secp256k1** curve | diff --git a/external/antithesis-sdk/CMakeLists.txt b/external/antithesis-sdk/CMakeLists.txt index d2c1f536afd..46c7b4bf7ae 100644 --- a/external/antithesis-sdk/CMakeLists.txt +++ b/external/antithesis-sdk/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.25) +cmake_minimum_required(VERSION 3.18) # Note, version set explicitly by rippled project project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX) diff --git a/external/antithesis-sdk/README.md b/external/antithesis-sdk/README.md index eb0237868de..46056ec5123 100644 --- a/external/antithesis-sdk/README.md +++ b/external/antithesis-sdk/README.md @@ -1,8 +1,9 @@ # Antithesis C++ SDK 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. -* Lifecycle functions that inform the Antithesis environment that particular test phases or milestones have been reached. + +- 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. +- 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/) diff --git a/external/ed25519-donna/CMakeLists.txt b/external/ed25519-donna/CMakeLists.txt index 418dc38326b..f060d530aa4 100644 --- a/external/ed25519-donna/CMakeLists.txt +++ b/external/ed25519-donna/CMakeLists.txt @@ -17,6 +17,9 @@ add_library(ed25519 STATIC ) add_library(ed25519::ed25519 ALIAS ed25519) target_link_libraries(ed25519 PUBLIC OpenSSL::SSL) +if(NOT MSVC) + target_compile_options(ed25519 PRIVATE -Wno-implicit-fallthrough) +endif() include(GNUInstallDirs) diff --git a/external/ed25519-donna/README.md b/external/ed25519-donna/README.md index e09fc27e31a..31b2431632f 100644 --- a/external/ed25519-donna/README.md +++ b/external/ed25519-donna/README.md @@ -1,12 +1,12 @@ -[ed25519](http://ed25519.cr.yp.to/) is an -[Elliptic Curve Digital Signature Algortithm](http://en.wikipedia.org/wiki/Elliptic_Curve_DSA), -developed by [Dan Bernstein](http://cr.yp.to/djb.html), -[Niels Duif](http://www.nielsduif.nl/), -[Tanja Lange](http://hyperelliptic.org/tanja), -[Peter Schwabe](http://www.cryptojedi.org/users/peter/), +[ed25519](http://ed25519.cr.yp.to/) is an +[Elliptic Curve Digital Signature Algortithm](http://en.wikipedia.org/wiki/Elliptic_Curve_DSA), +developed by [Dan Bernstein](http://cr.yp.to/djb.html), +[Niels Duif](http://www.nielsduif.nl/), +[Tanja Lange](http://hyperelliptic.org/tanja), +[Peter Schwabe](http://www.cryptojedi.org/users/peter/), 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. #### Performance @@ -52,35 +52,35 @@ are made. #### Compilation -No configuration is needed **if you are compiling against OpenSSL**. +No configuration is needed **if you are compiling against OpenSSL**. ##### Hash Options 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. -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 - struct ed25519_hash_context; + struct ed25519_hash_context; - 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_final(ed25519_hash_context *ctx, uint8_t *hash); - void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); + 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_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); ##### Random Options 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: - 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) ##### Minor options @@ -91,80 +91,79 @@ Use `-DED25519_FORCE_32BIT` to force the use of 32 bit routines even when compil ##### 32-bit - gcc ed25519.c -m32 -O3 -c + gcc ed25519.c -m32 -O3 -c ##### 64-bit - gcc ed25519.c -m64 -O3 -c + gcc ed25519.c -m64 -O3 -c ##### SSE2 - gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2 - gcc ed25519.c -m64 -O3 -c -DED25519_SSE2 + gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2 + gcc ed25519.c -m64 -O3 -c -DED25519_SSE2 clang and icc are also supported - #### Usage 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). To generate a private key, simply generate 32 bytes from a secure cryptographic source: - ed25519_secret_key sk; - randombytes(sk, sizeof(ed25519_secret_key)); + ed25519_secret_key sk; + randombytes(sk, sizeof(ed25519_secret_key)); To generate a public key: - ed25519_public_key pk; - ed25519_publickey(sk, pk); + ed25519_public_key pk; + ed25519_publickey(sk, pk); To sign a message: - ed25519_signature sig; - ed25519_sign(message, message_len, sk, pk, signature); + ed25519_signature sig; + ed25519_sign(message, message_len, sk, pk, 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: - const unsigned char *mp[num] = {message1, message2..} - size_t ml[num] = {message_len1, message_len2..} - const unsigned char *pkp[num] = {pk1, pk2..} - const unsigned char *sigp[num] = {signature1, signature2..} - int valid[num] + const unsigned char *mp[num] = {message1, message2..} + size_t ml[num] = {message_len1, message_len2..} + const unsigned char *pkp[num] = {pk1, pk2..} + const unsigned char *sigp[num] = {signature1, signature2..} + int valid[num] - /* 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; + /* 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; -**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in -`ed25519-randombytes.h`, to generate random scalars for the verification code. +**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in +`ed25519-randombytes.h`, to generate random scalars for the verification code. The default implementation now uses OpenSSLs `RAND_bytes`. 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. -Additionally, the secret key does not contain a copy of the public key, so it is +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 32 bytes instead of 64 bytes, and the public key must be provided to the signing function. ##### Curve25519 -Curve25519 public keys can be generated thanks to -[Adam Langley](http://www.imperialviolet.org/2013/05/10/fastercurve25519.html) +Curve25519 public keys can be generated thanks to +[Adam Langley](http://www.imperialviolet.org/2013/05/10/fastercurve25519.html) leveraging Ed25519's precomputed basepoint scalar multiplication. - curved25519_key sk, pk; - randombytes(sk, sizeof(curved25519_key)); - curved25519_scalarmult_basepoint(pk, sk); + curved25519_key sk, pk; + randombytes(sk, sizeof(curved25519_key)); + 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 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 -[Available on the Ed25519 website](http://ed25519.cr.yp.to/papers.html) \ No newline at end of file +[Available on the Ed25519 website](http://ed25519.cr.yp.to/papers.html) diff --git a/external/ed25519-donna/fuzz/README.md b/external/ed25519-donna/fuzz/README.md index 306ddfe08c0..0a5cd491777 100644 --- a/external/ed25519-donna/fuzz/README.md +++ b/external/ed25519-donna/fuzz/README.md @@ -1,78 +1,78 @@ 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). Curve25519 tests that generating a public key from a secret key # Building -## *nix + PHP +## \*nix + PHP `php build-nix.php (required parameters) (optional parameters)` Required parameters: -* `--function=[curve25519,ed25519]` -* `--bits=[32,64]` +- `--function=[curve25519,ed25519]` +- `--bits=[32,64]` Optional parameters: -* `--with-sse2` +- `--with-sse2` - Also fuzz against ed25519-donna-sse2 -* `--with-openssl` + Also fuzz against ed25519-donna-sse2 - 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: - - 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 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 Add the following files to the project: -* `fuzz/curve25519-ref10.c` -* `fuzz/ed25519-ref10.c` -* `fuzz/ed25519-donna.c` -* `fuzz/ed25519-donna-sse2.c` (optional) -* `fuzz-[curve25519/ed25519].c` (depending on which you want to fuzz) +- `fuzz/curve25519-ref10.c` +- `fuzz/ed25519-ref10.c` +- `fuzz/ed25519-donna.c` +- `fuzz/ed25519-donna-sse2.c` (optional) +- `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. # 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): fuzzing: ref10 curved25519 curved25519-sse2 - + ................................ [0000000000020000] ................................ [0000000000040000] ................................ [0000000000060000] ................................ [0000000000080000] ................................ [00000000000a0000] ................................ [00000000000c0000] - + 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. ## Example errors @@ -83,21 +83,21 @@ These are example error dumps (with intentionally introduced errors). Random data: -* sk, or Secret Key -* m, or Message +- sk, or Secret Key +- m, or Message Generated data: -* pk, or Public Key -* sig, or Signature -* valid, or if the signature of the message is valid with the public key +- pk, or Public Key +- sig, or Signature +- valid, or if the signature of the message is valid with the public key Dump: sk: 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, - + m: 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, @@ -107,67 +107,66 @@ Dump: 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, 0x69,0x83,0x92,0x70,0x95,0x76,0xa0,0x8e,0x16,0x79,0xcc,0xaa,0xb5,0x7c,0xf8,0x7a, - + ref10: pk: 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, - + sig: 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, 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, - + valid: yes - + ed25519-donna: pk diff: ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____, ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____, - + sig diff: 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, 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, - + 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. ### Curve25519 Random data: -* sk, or Secret Key +- sk, or Secret Key Generated data: -* pk, or Public Key +- pk, or Public Key Dump: sk: 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, - - + + ref10: 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, - - + + curved25519 diff: 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, - - + + curved25519-sse2 diff: ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____, ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____, - -In this case, curved25519 is totally wrong, while curved25519-sse2 matches the reference -implementation. \ No newline at end of file +In this case, curved25519 is totally wrong, while curved25519-sse2 matches the reference +implementation. diff --git a/external/nudb/conandata.yml b/external/nudb/conandata.yml deleted file mode 100644 index 721129f88e7..00000000000 --- a/external/nudb/conandata.yml +++ /dev/null @@ -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" diff --git a/external/nudb/conanfile.py b/external/nudb/conanfile.py deleted file mode 100644 index a046e2ba898..00000000000 --- a/external/nudb/conanfile.py +++ /dev/null @@ -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" diff --git a/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch b/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch deleted file mode 100644 index 2d5264f3ce4..00000000000 --- a/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch +++ /dev/null @@ -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 - #include - #include -+#include - - 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 -+#include - - namespace nudb { - diff --git a/external/rocksdb/conandata.yml b/external/rocksdb/conandata.yml deleted file mode 100644 index 7d7a575d980..00000000000 --- a/external/rocksdb/conandata.yml +++ /dev/null @@ -1,12 +0,0 @@ -sources: - "9.7.3": - url: "https://github.com/facebook/rocksdb/archive/refs/tags/v9.7.3.tar.gz" - sha256: "acfabb989cbfb5b5c4d23214819b059638193ec33dad2d88373c46448d16d38b" -patches: - "9.7.3": - - patch_file: "patches/9.x.x-0001-exclude-thirdparty.patch" - patch_description: "Do not include thirdparty.inc" - patch_type: "portability" - - patch_file: "patches/9.7.3-0001-memory-leak.patch" - patch_description: "Fix a leak of obsolete blob files left open until DB::Close()" - patch_type: "portability" diff --git a/external/rocksdb/conanfile.py b/external/rocksdb/conanfile.py deleted file mode 100644 index 8b85ce1540d..00000000000 --- a/external/rocksdb/conanfile.py +++ /dev/null @@ -1,235 +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" - description = "A library that provides an embeddable, persistent key-value store for fast storage" - license = ("GPL-2.0-only", "Apache-2.0") - url = "https://github.com/conan-io/conan-center-index" - homepage = "https://github.com/facebook/rocksdb" - 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") - if self.options.with_zstd: - deps.set_property("zstd", "cmake_target_name", "zstd::zstd") - 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") diff --git a/external/rocksdb/patches/9.7.3-0001-memory-leak.patch b/external/rocksdb/patches/9.7.3-0001-memory-leak.patch deleted file mode 100644 index bb086e6cb21..00000000000 --- a/external/rocksdb/patches/9.7.3-0001-memory-leak.patch +++ /dev/null @@ -1,319 +0,0 @@ -diff --git a/HISTORY.md b/HISTORY.md -index 36d472229..05ad1a202 100644 ---- a/HISTORY.md -+++ b/HISTORY.md -@@ -1,6 +1,10 @@ - # Rocksdb Change Log - > NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt` - -+## 9.7.4 (10/31/2024) -+### Bug Fixes -+* Fix a leak of obsolete blob files left open until DB::Close(). This bug was introduced in version 9.4.0. -+ - ## 9.7.3 (10/16/2024) - ### Behavior Changes - * OPTIONS file to be loaded by remote worker is now preserved so that it does not get purged by the primary host. A similar technique as how we are preserving new SST files from getting purged is used for this. min_options_file_numbers_ is tracked like pending_outputs_ is tracked. -diff --git a/db/blob/blob_file_cache.cc b/db/blob/blob_file_cache.cc -index 5f340aadf..1b9faa238 100644 ---- a/db/blob/blob_file_cache.cc -+++ b/db/blob/blob_file_cache.cc -@@ -42,6 +42,7 @@ Status BlobFileCache::GetBlobFileReader( - assert(blob_file_reader); - assert(blob_file_reader->IsEmpty()); - -+ // NOTE: sharing same Cache with table_cache - const Slice key = GetSliceForKey(&blob_file_number); - - assert(cache_); -@@ -98,4 +99,13 @@ Status BlobFileCache::GetBlobFileReader( - return Status::OK(); - } - -+void BlobFileCache::Evict(uint64_t blob_file_number) { -+ // NOTE: sharing same Cache with table_cache -+ const Slice key = GetSliceForKey(&blob_file_number); -+ -+ assert(cache_); -+ -+ cache_.get()->Erase(key); -+} -+ - } // namespace ROCKSDB_NAMESPACE -diff --git a/db/blob/blob_file_cache.h b/db/blob/blob_file_cache.h -index 740e67ada..6858d012b 100644 ---- a/db/blob/blob_file_cache.h -+++ b/db/blob/blob_file_cache.h -@@ -36,6 +36,15 @@ class BlobFileCache { - uint64_t blob_file_number, - CacheHandleGuard* blob_file_reader); - -+ // Called when a blob file is obsolete to ensure it is removed from the cache -+ // to avoid effectively leaking the open file and assicated memory -+ void Evict(uint64_t blob_file_number); -+ -+ // Used to identify cache entries for blob files (not normally useful) -+ static const Cache::CacheItemHelper* GetHelper() { -+ return CacheInterface::GetBasicHelper(); -+ } -+ - private: - using CacheInterface = - BasicTypedCacheInterface; -diff --git a/db/column_family.h b/db/column_family.h -index e4b7adde8..86637736a 100644 ---- a/db/column_family.h -+++ b/db/column_family.h -@@ -401,6 +401,7 @@ class ColumnFamilyData { - SequenceNumber earliest_seq); - - TableCache* table_cache() const { return table_cache_.get(); } -+ BlobFileCache* blob_file_cache() const { return blob_file_cache_.get(); } - BlobSource* blob_source() const { return blob_source_.get(); } - - // See documentation in compaction_picker.h -diff --git a/db/db_impl/db_impl.cc b/db/db_impl/db_impl.cc -index 261593423..06573ac2e 100644 ---- a/db/db_impl/db_impl.cc -+++ b/db/db_impl/db_impl.cc -@@ -659,8 +659,9 @@ Status DBImpl::CloseHelper() { - // We need to release them before the block cache is destroyed. The block - // cache may be destroyed inside versions_.reset(), when column family data - // list is destroyed, so leaving handles in table cache after -- // versions_.reset() may cause issues. -- // Here we clean all unreferenced handles in table cache. -+ // versions_.reset() may cause issues. Here we clean all unreferenced handles -+ // in table cache, and (for certain builds/conditions) assert that no obsolete -+ // files are hanging around unreferenced (leak) in the table/blob file cache. - // Now we assume all user queries have finished, so only version set itself - // can possibly hold the blocks from block cache. After releasing unreferenced - // handles here, only handles held by version set left and inside -@@ -668,6 +669,9 @@ Status DBImpl::CloseHelper() { - // time a handle is released, we erase it from the cache too. By doing that, - // we can guarantee that after versions_.reset(), table cache is empty - // so the cache can be safely destroyed. -+#ifndef NDEBUG -+ TEST_VerifyNoObsoleteFilesCached(/*db_mutex_already_held=*/true); -+#endif // !NDEBUG - table_cache_->EraseUnRefEntries(); - - for (auto& txn_entry : recovered_transactions_) { -@@ -3227,6 +3231,8 @@ Status DBImpl::MultiGetImpl( - s = Status::Aborted(); - break; - } -+ // This could be a long-running operation -+ ROCKSDB_THREAD_YIELD_HOOK(); - } - - // Post processing (decrement reference counts and record statistics) -diff --git a/db/db_impl/db_impl.h b/db/db_impl/db_impl.h -index 5e4fa310b..ccc0abfa7 100644 ---- a/db/db_impl/db_impl.h -+++ b/db/db_impl/db_impl.h -@@ -1241,9 +1241,14 @@ class DBImpl : public DB { - static Status TEST_ValidateOptions(const DBOptions& db_options) { - return ValidateOptions(db_options); - } -- - #endif // NDEBUG - -+ // In certain configurations, verify that the table/blob file cache only -+ // contains entries for live files, to check for effective leaks of open -+ // files. This can only be called when purging of obsolete files has -+ // "settled," such as during parts of DB Close(). -+ void TEST_VerifyNoObsoleteFilesCached(bool db_mutex_already_held) const; -+ - // persist stats to column family "_persistent_stats" - void PersistStats(); - -diff --git a/db/db_impl/db_impl_debug.cc b/db/db_impl/db_impl_debug.cc -index 790a50d7a..67f5b4aaf 100644 ---- a/db/db_impl/db_impl_debug.cc -+++ b/db/db_impl/db_impl_debug.cc -@@ -9,6 +9,7 @@ - - #ifndef NDEBUG - -+#include "db/blob/blob_file_cache.h" - #include "db/column_family.h" - #include "db/db_impl/db_impl.h" - #include "db/error_handler.h" -@@ -328,5 +329,49 @@ size_t DBImpl::TEST_EstimateInMemoryStatsHistorySize() const { - InstrumentedMutexLock l(&const_cast(this)->stats_history_mutex_); - return EstimateInMemoryStatsHistorySize(); - } -+ -+void DBImpl::TEST_VerifyNoObsoleteFilesCached( -+ bool db_mutex_already_held) const { -+ // This check is somewhat expensive and obscure to make a part of every -+ // unit test in every build variety. Thus, we only enable it for ASAN builds. -+ if (!kMustFreeHeapAllocations) { -+ return; -+ } -+ -+ std::optional l; -+ if (db_mutex_already_held) { -+ mutex_.AssertHeld(); -+ } else { -+ l.emplace(&mutex_); -+ } -+ -+ std::vector live_files; -+ for (auto cfd : *versions_->GetColumnFamilySet()) { -+ if (cfd->IsDropped()) { -+ continue; -+ } -+ // Sneakily add both SST and blob files to the same list -+ cfd->current()->AddLiveFiles(&live_files, &live_files); -+ } -+ std::sort(live_files.begin(), live_files.end()); -+ -+ auto fn = [&live_files](const Slice& key, Cache::ObjectPtr, size_t, -+ const Cache::CacheItemHelper* helper) { -+ if (helper != BlobFileCache::GetHelper()) { -+ // Skip non-blob files for now -+ // FIXME: diagnose and fix the leaks of obsolete SST files revealed in -+ // unit tests. -+ return; -+ } -+ // See TableCache and BlobFileCache -+ assert(key.size() == sizeof(uint64_t)); -+ uint64_t file_number; -+ GetUnaligned(reinterpret_cast(key.data()), &file_number); -+ // Assert file is in sorted live_files -+ assert( -+ std::binary_search(live_files.begin(), live_files.end(), file_number)); -+ }; -+ table_cache_->ApplyToAllEntries(fn, {}); -+} - } // namespace ROCKSDB_NAMESPACE - #endif // NDEBUG -diff --git a/db/db_iter.cc b/db/db_iter.cc -index e02586377..bf4749eb9 100644 ---- a/db/db_iter.cc -+++ b/db/db_iter.cc -@@ -540,6 +540,8 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key, - } else { - iter_.Next(); - } -+ // This could be a long-running operation due to tombstones, etc. -+ ROCKSDB_THREAD_YIELD_HOOK(); - } while (iter_.Valid()); - - valid_ = false; -diff --git a/db/table_cache.cc b/db/table_cache.cc -index 71fc29c32..8a5be75e8 100644 ---- a/db/table_cache.cc -+++ b/db/table_cache.cc -@@ -164,6 +164,7 @@ Status TableCache::GetTableReader( - } - - Cache::Handle* TableCache::Lookup(Cache* cache, uint64_t file_number) { -+ // NOTE: sharing same Cache with BlobFileCache - Slice key = GetSliceForFileNumber(&file_number); - return cache->Lookup(key); - } -@@ -179,6 +180,7 @@ Status TableCache::FindTable( - size_t max_file_size_for_l0_meta_pin, Temperature file_temperature) { - PERF_TIMER_GUARD_WITH_CLOCK(find_table_nanos, ioptions_.clock); - uint64_t number = file_meta.fd.GetNumber(); -+ // NOTE: sharing same Cache with BlobFileCache - Slice key = GetSliceForFileNumber(&number); - *handle = cache_.Lookup(key); - TEST_SYNC_POINT_CALLBACK("TableCache::FindTable:0", -diff --git a/db/version_builder.cc b/db/version_builder.cc -index ed8ab8214..c98f53f42 100644 ---- a/db/version_builder.cc -+++ b/db/version_builder.cc -@@ -24,6 +24,7 @@ - #include - - #include "cache/cache_reservation_manager.h" -+#include "db/blob/blob_file_cache.h" - #include "db/blob/blob_file_meta.h" - #include "db/dbformat.h" - #include "db/internal_stats.h" -@@ -744,12 +745,9 @@ class VersionBuilder::Rep { - return Status::Corruption("VersionBuilder", oss.str()); - } - -- // Note: we use C++11 for now but in C++14, this could be done in a more -- // elegant way using generalized lambda capture. -- VersionSet* const vs = version_set_; -- const ImmutableCFOptions* const ioptions = ioptions_; -- -- auto deleter = [vs, ioptions](SharedBlobFileMetaData* shared_meta) { -+ auto deleter = [vs = version_set_, ioptions = ioptions_, -+ bc = cfd_ ? cfd_->blob_file_cache() -+ : nullptr](SharedBlobFileMetaData* shared_meta) { - if (vs) { - assert(ioptions); - assert(!ioptions->cf_paths.empty()); -@@ -758,6 +756,9 @@ class VersionBuilder::Rep { - vs->AddObsoleteBlobFile(shared_meta->GetBlobFileNumber(), - ioptions->cf_paths.front().path); - } -+ if (bc) { -+ bc->Evict(shared_meta->GetBlobFileNumber()); -+ } - - delete shared_meta; - }; -@@ -766,7 +767,7 @@ class VersionBuilder::Rep { - blob_file_number, blob_file_addition.GetTotalBlobCount(), - blob_file_addition.GetTotalBlobBytes(), - blob_file_addition.GetChecksumMethod(), -- blob_file_addition.GetChecksumValue(), deleter); -+ blob_file_addition.GetChecksumValue(), std::move(deleter)); - - mutable_blob_file_metas_.emplace( - blob_file_number, MutableBlobFileMetaData(std::move(shared_meta))); -diff --git a/db/version_set.h b/db/version_set.h -index 9336782b1..024f869e7 100644 ---- a/db/version_set.h -+++ b/db/version_set.h -@@ -1514,7 +1514,6 @@ class VersionSet { - void GetLiveFilesMetaData(std::vector* metadata); - - void AddObsoleteBlobFile(uint64_t blob_file_number, std::string path) { -- // TODO: Erase file from BlobFileCache? - obsolete_blob_files_.emplace_back(blob_file_number, std::move(path)); - } - -diff --git a/include/rocksdb/version.h b/include/rocksdb/version.h -index 2a19796b8..0afa2cab1 100644 ---- a/include/rocksdb/version.h -+++ b/include/rocksdb/version.h -@@ -13,7 +13,7 @@ - // minor or major version number planned for release. - #define ROCKSDB_MAJOR 9 - #define ROCKSDB_MINOR 7 --#define ROCKSDB_PATCH 3 -+#define ROCKSDB_PATCH 4 - - // Do not use these. We made the mistake of declaring macros starting with - // double underscore. Now we have to live with our choice. We'll deprecate these -diff --git a/port/port.h b/port/port.h -index 13aa56d47..141716e5b 100644 ---- a/port/port.h -+++ b/port/port.h -@@ -19,3 +19,19 @@ - #elif defined(OS_WIN) - #include "port/win/port_win.h" - #endif -+ -+#ifdef OS_LINUX -+// A temporary hook into long-running RocksDB threads to support modifying their -+// priority etc. This should become a public API hook once the requirements -+// are better understood. -+extern "C" void RocksDbThreadYield() __attribute__((__weak__)); -+#define ROCKSDB_THREAD_YIELD_HOOK() \ -+ { \ -+ if (RocksDbThreadYield) { \ -+ RocksDbThreadYield(); \ -+ } \ -+ } -+#else -+#define ROCKSDB_THREAD_YIELD_HOOK() \ -+ {} -+#endif diff --git a/external/rocksdb/patches/9.x.x-0001-exclude-thirdparty.patch b/external/rocksdb/patches/9.x.x-0001-exclude-thirdparty.patch deleted file mode 100644 index 7b5858bc1e9..00000000000 --- a/external/rocksdb/patches/9.x.x-0001-exclude-thirdparty.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 93b884d..b715cb6 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -106,14 +106,9 @@ endif() - include(CMakeDependentOption) - - if(MSVC) -- option(WITH_GFLAGS "build with GFlags" OFF) - option(WITH_XPRESS "build with windows built in compression" OFF) -- option(ROCKSDB_SKIP_THIRDPARTY "skip thirdparty.inc" OFF) -- -- if(NOT ROCKSDB_SKIP_THIRDPARTY) -- include(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty.inc) -- endif() --else() -+endif() -+if(TRUE) - if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD" AND NOT CMAKE_SYSTEM_NAME MATCHES "kFreeBSD") - # FreeBSD has jemalloc as default malloc - # but it does not have all the jemalloc files in include/... -@@ -126,7 +121,7 @@ else() - endif() - endif() - -- if(MINGW) -+ if(MSVC OR MINGW) - option(WITH_GFLAGS "build with GFlags" OFF) - else() - option(WITH_GFLAGS "build with GFlags" ON) diff --git a/external/secp256k1/CHANGELOG.md b/external/secp256k1/CHANGELOG.md index ee447c0c1c7..a000672887b 100644 --- a/external/secp256k1/CHANGELOG.md +++ b/external/secp256k1/CHANGELOG.md @@ -8,153 +8,189 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.6.0] - 2024-11-04 #### 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. - - Document `doc/musig.md` for further notes on API usage. - - Usage example `examples/musig.c`. - - New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command. + +- 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. + - Document `doc/musig.md` for further notes on API usage. + - Usage example `examples/musig.c`. +- New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command. #### 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++). - - Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility. + +- 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++). +- 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 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 + 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. ## [0.5.1] - 2024-08-01 #### Added - - Added usage example for an ElligatorSwift key exchange. + +- Added usage example for an ElligatorSwift key exchange. #### 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 compilation when the extrakeys module is disabled. + +- Fixed compilation when the extrakeys module is disabled. #### ABI Compatibility + The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x. ## [0.5.0] - 2024-05-06 #### 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 - - 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). - - 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 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). + - 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 + The ABI is backward compatible with versions 0.4.x and 0.3.x. ## [0.4.1] - 2023-12-21 #### 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 + The ABI is backward compatible with versions 0.4.0 and 0.3.x. ## [0.4.0] - 2023-09-04 #### 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: - - Header file `include/secp256k1_ellswift.h` which defines the new API. - - Document `doc/ellswift.md` which explains the mathematical background of the scheme. - - 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). + +- 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: + - Header file `include/secp256k1_ellswift.h` which defines the new API. + - Document `doc/ellswift.md` which explains the mathematical background of the scheme. + - 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 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 - - 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 + 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 + 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 - - 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 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 - - Various improvements and changes to CMake builds. CMake builds remain experimental. - - Made API versioning consistent with GNU Autotools builds. - - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library. - - 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). + +- Various improvements and changes to CMake builds. CMake builds remain experimental. + - Made API versioning consistent with GNU Autotools builds. + - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library. + - 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 + The ABI is compatible with versions 0.3.0 and 0.3.1. ## [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`. #### 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 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 - - 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 + The ABI is compatible with version 0.3.0. ## [0.3.0] - 2023-03-08 #### 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. - - 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. + +- 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. +- 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 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 - - 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 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 -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 #### 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 support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms. + +- 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 support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms. #### 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 context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead. - - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`. - - Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`. + +- Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead. +- Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`. +- Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`. #### ABI Compatibility + 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 diff --git a/external/secp256k1/CMakePresets.json b/external/secp256k1/CMakePresets.json index b35cd80579f..60138c16bf4 100644 --- a/external/secp256k1/CMakePresets.json +++ b/external/secp256k1/CMakePresets.json @@ -1,5 +1,9 @@ { - "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0}, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, "version": 3, "configurePresets": [ { diff --git a/external/secp256k1/CONTRIBUTING.md b/external/secp256k1/CONTRIBUTING.md index a366d38b0ec..88c22af02bb 100644 --- a/external/secp256k1/CONTRIBUTING.md +++ b/external/secp256k1/CONTRIBUTING.md @@ -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. Contributors are recommended to provide the following in addition to the new code: -* **Specification:** - 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. - If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code. -* **Security Arguments:** - 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. -* **Relevance Arguments:** - The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases. +- **Specification:** + 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. + If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code. +- **Security Arguments:** + 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. +- **Relevance Arguments:** + 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. 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: -* 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)). -* 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. -* 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)). +- 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)). +- 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. +- 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)). #### 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. -* 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: - ```C - void secp256k_foo(void) { - unsigned int x; /* declaration */ - int y = 2*x; /* declaration */ - x = 17; /* statement */ - { - int a, b; /* declaration */ - a = x + y; /* statement */ - secp256k_bar(x, &b); /* statement */ - } - } - ``` -* Use `unsigned int` instead of just `unsigned`. -* 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). -* User-facing comment lines in headers should be limited to 80 chars if possible. -* All identifiers in file scope should start with `secp256k1_`. -* Avoid trailing whitespace. +- 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. +- 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 + void secp256k_foo(void) { + unsigned int x; /* declaration */ + int y = 2*x; /* declaration */ + x = 17; /* statement */ + { + int a, b; /* declaration */ + a = x + y; /* statement */ + secp256k_bar(x, &b); /* statement */ + } + } + ``` +- Use `unsigned int` instead of just `unsigned`. +- 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). +- User-facing comment lines in headers should be limited to 80 chars if possible. +- All identifiers in file scope should start with `secp256k1_`. +- Avoid trailing whitespace. ### Tests @@ -101,7 +101,7 @@ To create a HTML report with coloured and annotated source code: #### Exhaustive tests 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 diff --git a/external/secp256k1/README.md b/external/secp256k1/README.md index 222e5fb7685..4cd64c7fee3 100644 --- a/external/secp256k1/README.md +++ b/external/secp256k1/README.md @@ -1,5 +1,4 @@ -libsecp256k1 -============ +# libsecp256k1 ![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) [![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](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. 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 ----------------------- - -* 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 ------------------------ + +- 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 + +- 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 $ ./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. -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. @@ -109,18 +106,19 @@ In "Developer Command Prompt for VS 2022": >cmake -G "Visual Studio 17 2022" -A x64 -S . -B build >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`. - * [ECDSA example](examples/ecdsa.c) - * [Schnorr signatures example](examples/schnorr.c) - * [Deriving a shared secret (ECDH) example](examples/ecdh.c) - * [ElligatorSwift key exchange example](examples/ellswift.c) + +- [ECDSA example](examples/ecdsa.c) +- [Schnorr signatures example](examples/schnorr.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`. -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. 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 -Reporting a vulnerability ------------- +## Reporting a vulnerability See [SECURITY.md](SECURITY.md) -Contributing to libsecp256k1 ------------- +## Contributing to libsecp256k1 See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/external/secp256k1/SECURITY.md b/external/secp256k1/SECURITY.md index b515cc1c8e2..cb438707ce5 100644 --- a/external/secp256k1/SECURITY.md +++ b/external/secp256k1/SECURITY.md @@ -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: -| Name | Fingerprint | -|------|-------------| -| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 | -| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 | -| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 | +| Name | Fingerprint | +| ------------- | ------------------------------------------------- | +| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 | +| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 | +| 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 ""` Ensure that you put quotes around fingerprints containing spaces. diff --git a/external/secp256k1/doc/ellswift.md b/external/secp256k1/doc/ellswift.md index 9d60e6be0b6..ffbe9d02acc 100644 --- a/external/secp256k1/doc/ellswift.md +++ b/external/secp256k1/doc/ellswift.md @@ -5,17 +5,17 @@ construction in the ["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. -* [1. Introduction](#1-introduction) -* [2. The decoding function](#2-the-decoding-function) - + [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1) -* [3. The encoding function](#3-the-encoding-function) - + [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.3 Finding the inverse](#33-finding-the-inverse) - + [3.4 Dealing with special cases](#34-dealing-with-special-cases) - + [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.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1) +- [1. Introduction](#1-introduction) +- [2. The decoding function](#2-the-decoding-function) + - [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1) +- [3. The encoding function](#3-the-encoding-function) + - [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.3 Finding the inverse](#33-finding-the-inverse) + - [3.4 Dealing with special cases](#34-dealing-with-special-cases) + - [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.1 Full _(x, y)_ coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1) ## 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). **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). 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 @@ -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 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. -* 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$ + +- $\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. +- 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. - 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. - * 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 $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 $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. -* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below. + - 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 $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 $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. +- $\psi_u$ is a function from $S_u$ to $V$ that will be defined below. **Note**: In the paper: -* $F_u$ corresponds to $F_{0,u}$ there. -* $P_u(t)$ is called $P$ there. -* All $S_u$ sets together correspond to $S$ there. -* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there. + +- $F_u$ corresponds to $F_{0,u}$ there. +- $P_u(t)$ is called $P$ 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 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. -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$, 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. **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: @@ -98,12 +102,13 @@ Y(u, t) & = & \left\\{\begin{array}{ll} $$ $P_u(t)$ is defined: -* For $a=0$, unless: - * $u = 0$ or $t = 0$ (division by zero) - * $g(u) = -t^2$ (would give $Y=0$). -* For $a \neq 0$, unless: - * $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$). + +- For $a=0$, unless: + - $u = 0$ or $t = 0$ (division by zero) + - $g(u) = -t^2$ (would give $Y=0$). +- For $a \neq 0$, unless: + - $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.$ @@ -123,20 +128,22 @@ $$ Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is: **Define** $F_u(t)$ as: -* Let $X = \dfrac{u^3 + b - t^2}{2t}.$ -* 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. + +- Let $X = \dfrac{u^3 + b - t^2}{2t}.$ +- 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 $P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$): **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 $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$). -* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ -* 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. + +- 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 $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$). +- Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ +- 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, 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 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).$ -* For each of the found $t$ values, verify that $F_u(t) = x.$ -* Return the remaining $t$ values. + +- 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).$ +- 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:$ @@ -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; 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 $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).$ -* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where + +- $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).$ +- $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where $$ \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\\}$ 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_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_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_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 -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. 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, picking a uniformly random element from that, restarting whenever $\bot$ is picked: -**Define** *ElligatorSwift(x)* as: -* Loop: - * Pick a uniformly random field element $u.$ - * Compute the set $L = F_u^{-1}(x).$ - * Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$ - * Select a uniformly random $t \in T.$ - * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. +**Define** _ElligatorSwift(x)_ as: + +- Loop: + - Pick a uniformly random field element $u.$ + - Compute the set $L = F_u^{-1}(x).$ + - Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$ + - 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 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), 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). -* 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. + +- 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). +- 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 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, the loop can be simplified to only compute one of the inverses instead of all of them: -**Define** *ElligatorSwift(x)* as: -* Loop: - * Pick a uniformly random field element $u.$ - * Pick a uniformly random integer $c$ in $[0,8).$ - * Let $t = G_{c,u}(x).$ - * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. +**Define** _ElligatorSwift(x)_ as: + +- Loop: + - Pick a uniformly random field element $u.$ + - Pick a uniformly random integer $c$ in $[0,8).$ + - Let $t = G_{c,u}(x).$ + - If $t \neq \bot$, return $(u, t)$; restart loop otherwise. 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: **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, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula) - * Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows). -* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas): - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ - * Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise. -* Let $w = \sqrt{s}.$ -* Depending on $c:$ - * 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).$ + +- 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, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula) + - Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows). +- Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas): + - Let $s = x-u.$ + - Let $r = \sqrt{-s(4g(u) + sh(u))}.$ + - Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise. +- Let $w = \sqrt{s}.$ +- Depending on $c:$ + - 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 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: **Define** $G_{c,u}(x)$ as: -* If $c \in \\{0, 1, 4, 5\\}:$ - * If $g(-u-x)$ is square, return $\bot.$ - * Let $s = -g(u)/(u^2 + ux + x^2 + a).$ - * Let $v = x.$ -* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ - * Let $v = (r/s - u)/2.$ -* Let $w = \sqrt{s}.$ -* Depending on $c:$ - * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$ - * If $c \in \\{1, 3\\}:$ 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).$ + +- If $c \in \\{0, 1, 4, 5\\}:$ + - If $g(-u-x)$ is square, return $\bot.$ + - Let $s = -g(u)/(u^2 + ux + x^2 + a).$ + - Let $v = x.$ +- Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + - Let $s = x-u.$ + - Let $r = \sqrt{-s(4g(u) + sh(u))}.$ + - Let $v = (r/s - u)/2.$ +- Let $w = \sqrt{s}.$ +- Depending on $c:$ + - If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$ + - If $c \in \\{1, 3\\}:$ 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. 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 $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\\}$): - * 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. +- 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. 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). 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 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$. This is again only possible on even-ordered curves. -* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$): - * 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. +- In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$): + - 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. 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. 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. -* 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 \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$. +- 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 \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: -* If $a=0$ and $u=0$, return $\bot.$ -* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$ -* If $c \in \\{0, 1, 4, 5\\}:$ - * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). - * If $g(-u-x)$ is square, return $\bot.$ - * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). - * Let $v = x.$ -* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. - * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ - * If $s = 0$, return $\bot.$ - * Let $v = (r/s - u)/2.$ -* Let $w = \sqrt{s}$; return $\bot$ if not square. -* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$ -* Depending on $c:$ - * If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$ - * If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$ - * If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$ - * If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$ -* If $a=0$ and $t=0$, return $\bot$ (even curves only). -* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$ -* Return $t.$ + +- If $a=0$ and $u=0$, return $\bot.$ +- If $a \neq 0$ and $X_0(u)=0$, return $\bot.$ +- If $c \in \\{0, 1, 4, 5\\}:$ + - If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). + - If $g(-u-x)$ is square, return $\bot.$ + - Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). + - Let $v = x.$ +- Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + - Let $s = x-u.$ + - Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. + - If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ + - If $s = 0$, return $\bot.$ + - Let $v = (r/s - u)/2.$ +- Let $w = \sqrt{s}$; return $\bot$ if not square. +- If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$ +- Depending on $c:$ + - If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$ + - If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$ + - If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$ + - If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$ +- If $a=0$ and $t=0$, return $\bot$ (even curves only). +- 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, 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.$ - * 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. + +- All cases where $P_u(t)$ is not defined: + - For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$ + - 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. @@ -370,40 +387,42 @@ These cases form a negligible subset of all $(u, t)$ for cryptographically sized Specialized for odd-ordered $a=0$ curves: **Define** $G_{c,u}(x)$ as: -* If $u=0$, return $\bot.$ -* If $c \in \\{0, 1, 4, 5\\}:$ - * If $(-u-x)^3 + b$ is square, return $\bot$ - * Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0). - * Let $v = x.$ -* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square. - * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ - * If $s = 0$, return $\bot.$ - * Let $v = (r/s - u)/2.$ -* Let $w = \sqrt{s}$; return $\bot$ if not square. -* Depending on $c:$ - * If $c \in \\{0, 2\\}:$ 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 \\{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).$ + +- If $u=0$, return $\bot.$ +- If $c \in \\{0, 1, 4, 5\\}:$ + - If $(-u-x)^3 + b$ is square, return $\bot$ + - Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0). + - Let $v = x.$ +- Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + - Let $s = x-u.$ + - Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square. + - If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ + - If $s = 0$, return $\bot.$ + - Let $v = (r/s - u)/2.$ +- Let $w = \sqrt{s}$; return $\bot$ if not square. +- Depending on $c:$ + - If $c \in \\{0, 2\\}:$ 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 \\{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`. And the x-only ElligatorSwift encoding algorithm is still: -**Define** *ElligatorSwift(x)* as: -* Loop: - * Pick a uniformly random field element $u.$ - * Pick a uniformly random integer $c$ in $[0,8).$ - * Let $t = G_{c,u}(x).$ - * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. +**Define** _ElligatorSwift(x)_ as: + +- Loop: + - Pick a uniformly random field element $u.$ + - Pick a uniformly random integer $c$ in $[0,8).$ + - 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. 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. -## 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 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:$ -**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 $y = \sqrt{g(x)}.$ -* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$ +**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 $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: **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 $g(-u-x)$ is square, return $\bot.$ - * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). - * Let $v = x.$ -* Otherwise, when $c \in \\{2, 3\\}:$ - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. - * If $c = 3$ and $r = 0$, return $\bot.$ - * Let $v = (r/s - u)/2.$ -* Let $w = \sqrt{s}$; return $\bot$ if not square. -* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise. -* Depending on $c:$ - * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$ - * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$ + +- If $c \in \\{0, 1\\}:$ + - If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). + - If $g(-u-x)$ is square, return $\bot.$ + - Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). + - Let $v = x.$ +- Otherwise, when $c \in \\{2, 3\\}:$ + - Let $s = x-u.$ + - Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. + - If $c = 3$ and $r = 0$, return $\bot.$ + - Let $v = (r/s - u)/2.$ +- Let $w = \sqrt{s}$; return $\bot$ if not square. +- Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise. +- Depending on $c:$ + - 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.$ 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 $-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, 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 as decoder: -**Define** *Decode(u, t)* as: -* Let $u'=u$ if $u \neq 0$; $1$ otherwise. -* Let $t'=t$ if $t \neq 0$; $1$ otherwise. -* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise. -* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ -* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ -* 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 = \sqrt{g(x)}.$ -* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise. +**Define** _Decode(u, t)_ as: + +- Let $u'=u$ if $u \neq 0$; $1$ otherwise. +- Let $t'=t$ if $t \neq 0$; $1$ otherwise. +- Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise. +- Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ +- Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ +- 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 = \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).$ diff --git a/external/secp256k1/doc/musig.md b/external/secp256k1/doc/musig.md index ae21f9b131c..176b131da66 100644 --- a/external/secp256k1/doc/musig.md +++ b/external/secp256k1/doc/musig.md @@ -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`). A usage example can be found in `examples/musig.c`. diff --git a/external/secp256k1/doc/release-process.md b/external/secp256k1/doc/release-process.md index a64bae0f0d6..4ac9ca0d23d 100644 --- a/external/secp256k1/doc/release-process.md +++ b/external/secp256k1/doc/release-process.md @@ -2,7 +2,7 @@ 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. 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. ## Sanity checks + Perform these checks when reviewing the release PR (see below): 1. Ensure `make distcheck` doesn't fail. @@ -42,15 +43,15 @@ Perform these checks when reviewing the release PR (see below): ## Regular release 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 - * 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, - * 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, - * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and, - * if this is not a patch release, - * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and - * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. + - 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), + - removing the `[Unreleased]` section header, + - 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, + - sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and, + - if this is not a patch release, + - updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and + - updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. 2. Perform the [sanity checks](#sanity-checks) on the PR branch. 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 ``` 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`, - * 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). + - 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 + - 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. + 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. @@ -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 ``` 2. Open a pull request to the `$MAJOR.$MINOR` branch that - * includes the bug fixes, - * finalizes the release notes similar to a regular release, - * increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` + - includes the bug fixes, + - finalizes the release notes similar to a regular release, + - 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` (with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example). 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 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). -7. 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). +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. +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). diff --git a/external/secp256k1/doc/safegcd_implementation.md b/external/secp256k1/doc/safegcd_implementation.md index 5dbbb7bbd2d..72d99daad33 100644 --- a/external/secp256k1/doc/safegcd_implementation.md +++ b/external/secp256k1/doc/safegcd_implementation.md @@ -29,65 +29,67 @@ def gcd(f, g): return abs(f) ``` -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 -*g=0* is reached. At that point, *|f|* gives the GCD. Each of the transitions in the loop is called a +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 +_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). -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* -- Take the first branch: *δ=-1 f=7 g=-7* -- Take the second branch: *δ=0 f=7 g=0* -- The answer *|f| = 7*. +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_ +- Take the first branch: _δ=-1 f=7 g=-7_ +- Take the second branch: _δ=0 f=7 g=0_ +- The answer _|f| = 7_. Why it works: + - 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*. - - (b) Replace *(f,g)* with *(f,g/2)* (where *g* is guaranteed to be even). + - (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). - 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* - 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 + - 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 + common factor _c_. Reasoning in the other direction shows that no common factor can be added by doing so either. - - For (b), we know that *f* is odd, so *gcd(f,g)* clearly has no factor *2*, and we can remove - it from *g*. -- 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 - gcd of *f'* and *0* is *|f'|* by definition, that is our answer. + - For (b), we know that _f_ is odd, so _gcd(f,g)_ clearly has no factor _2_, and we can remove + it from _g_. +- 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 + 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 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 at high order bits. 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 -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 -prime and *0 < x < M*. In what follows, assume that the modular inverse exists. +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 +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 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)). -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 -mod M*. +mod M\*. 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 -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* -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*). +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)_. +_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 += 1_). ```python def div2(M, x): @@ -119,17 +121,16 @@ def modinv(M, x): 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 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 be faster at the level of optimization we're able to do in C. - ## 3. Batching multiple divsteps -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): +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): ``` 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 ] ``` -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. +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. Performing multiple divsteps corresponds to a multiplication with the product of all the 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 *2N* (see also -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 *2N*, and -do one division by *2N* as a final step: +divided by _2_, the product of these matrices will consist of integers divided by _2N_ (see also +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 _2N_, and +do one division by _2N_ as a final step: ```python def divsteps_n_matrix(delta, f, g): @@ -166,13 +167,13 @@ def divsteps_n_matrix(delta, f, g): 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 -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 -integers could set *N=62* and compute the full transition matrix for 62 steps at once without any +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 +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 -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: @@ -184,8 +185,8 @@ We still need functions to compute: [ 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* -and *g* will be multiple of *2N*, and division by *2N* is simply shifting them down: +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 _2N_, and division by _2N_ is simply shifting them down: ```python def update_fg(f, g, t): @@ -199,8 +200,8 @@ def update_fg(f, g, t): 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 *2N mod M*. -This is easy if we have precomputed *1/M mod 2N* (which always exists for odd *M*): +The same is not true for _d_ and _e_, and we need an equivalent of the `div2` function for division by _2N mod M_. +This is easy if we have precomputed _1/M mod 2N_ (which always exists for odd _M_): ```python 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) ``` -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 def modinv(M, Mi, x): @@ -242,20 +243,19 @@ def modinv(M, Mi, x): return (d * f) % M ``` -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 +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 increasing). For variable time code such excess iterations will be mostly optimized away in later sections. - ## 4. Avoiding modulus operations -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 -sign of *f*. These are relatively expensive operations when done generically. +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 +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 -*[0,M)* all the time. Let's start by inlining `div2n` into `update_de`, and dropping the modulus +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 operation at the end: ```python @@ -272,15 +272,15 @@ def update_de(d, e, t, M, Mi): 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|* -never exceed *2N* (see paragraph 8.3 in the paper), and thus a multiplication with *t* will have -outputs whose absolute values are at most *2N* 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 -*M > 1*, the multiplication results in numbers in range *(-2NM,2NM)*. Subtracting less than *2N* -times *M* to cancel out *N* bits brings that up to *(-2N+1M,2NM)*, and -dividing by *2N* 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 -counteracted by incrementing *d* and *e* by *M* whenever they're negative: +Let's look at bounds on the ranges of these numbers. It can be shown that _|u|+|v|_ and _|q|+|r|_ +never exceed _2N_ (see paragraph 8.3 in the paper), and thus a multiplication with _t_ will have +outputs whose absolute values are at most _2N_ 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 +_M > 1_, the multiplication results in numbers in range _(-2NM,2NM)_. Subtracting less than _2N_ +times _M_ to cancel out _N_ bits brings that up to _(-2N+1M,2NM)_, and +dividing by _2N_ 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 +counteracted by incrementing _d_ and _e_ by _M_ whenever they're negative: ```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 -output will again be in *(-2M,M)*, and this remains the case regardless of how many `update_de` +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` 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, -increasing *e* by *M* is equal to incrementing *cd* by *v M* and *ce* by *r M*. So we could instead write: +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: ```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 -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: +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: ```python 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 ``` -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: +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: ```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 -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 -conditional negation of *d* (based on the sign of *f*) into it as well: +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 +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: ```python def normalize(sign, v, M): @@ -391,22 +391,21 @@ And calling it in `modinv` is simply: return normalize(f, d, M) ``` - ## 5. Constant-time operation The primary selling point of the algorithm is fast constant-time operation. What code flow still 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 sign checks in `update_de` - the sign checks in `normalize` 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 -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 -*⌈724/N⌉* times. +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 +sufficient even. Given that every loop iteration performs _N_ divsteps, it will run a total of +_⌈724/N⌉_ times. 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 @@ -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 -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 -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*. +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 +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_. Using this we can write: @@ -444,13 +443,13 @@ in constant-time form as: x = (f ^ c1) - c1 ``` -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 -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 -numbers in range *[-263,0)* to *-1*, and numbers in range *[0,263)* to *0*. +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 +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 +numbers in range _[-263,0)_ to _-1_, and numbers in range _[0,263)_ 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 if g & 1: @@ -498,8 +497,8 @@ becomes: ``` It turns out that this can be implemented more efficiently by applying the substitution -*η=-δ*. In this representation, negating *δ* corresponds to negating *η*, and incrementing -*δ* corresponds to decrementing *η*. This allows us to remove the negation in the *c1* +_η=-δ_. In this representation, negating _δ_ corresponds to negating _η_, and incrementing +_δ_ corresponds to decrementing _η_. This allows us to remove the negation in the _c1_ computation: ```python @@ -519,12 +518,12 @@ computation: g >>= 1 ``` -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 -(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 -decrementing *ζ* by *1*, but negating *δ* now corresponds to going from *ζ* to *-(ζ+1)*, or -*~ζ*. Doing that conditionally based on *c3* is simply: +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 +(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 +decrementing _ζ_ by _1_, but negating _δ_ now corresponds to going from _ζ_ to _-(ζ+1)_, or +_~ζ_. Doing that conditionally based on _c3_ is simply: ```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 -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. These bit fiddling tricks can also be used to make the conditional negations and additions in `update_de` and `normalize` constant-time. - ## 6. Variable-time optimizations 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 `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 for _ in range(N): @@ -562,7 +560,7 @@ for _ in range(N): 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 efficiently, which is possible on most platforms; it is abstracted here as the function `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. ``` -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 +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 well. -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 *η* -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. +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 _η_ +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. -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 2L = 0*, or *w = -g/f mod 2L*. 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 -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*. +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 2L = 0_, or _w = -g/f mod 2L_. 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 +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_. 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: - Instead of a 3-bit table: - - *-f* or *f ^ 6* + - _-f_ or _f ^ 6_ - Instead of a 4-bit table: - - *1 - f(f + 1)* - - *-(f + (((f + 1) & 4) << 1))* -- For larger tables the following technique can be used: if *w=-1/f mod 2L*, then *w(w f+2)* is - *-1/f mod 22L*. This allows extending the previous formulas (or tables). In particular we + - _1 - f(f + 1)_ + - _-(f + (((f + 1) & 4) << 1))_ +- For larger tables the following technique can be used: if _w=-1/f mod 2L_, then _w(w f+2)_ is + _-1/f mod 22L_. This allows extending the previous formulas (or tables). In particular we have this 6-bit function (based on the 3-bit function above): - - *f(f2 - 2)* + - _f(f2 - 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. - ## 7. Final Python version All together we need the following functions: - 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 - section 5, extended to handle *u*, *v*, *q*, *r*: + section 5, extended to handle _u_, _v_, _q_, _r_: ```python def divsteps_n_matrix(zeta, f, g): @@ -684,7 +681,7 @@ def divsteps_n_matrix(zeta, f, g): 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: ```python @@ -723,7 +720,7 @@ def normalize(sign, v, M): 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: ```python @@ -772,20 +769,21 @@ def modinv_var(M, Mi, x): ## 8. From GCDs to Jacobi symbol -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 -make corresponding updates to *j* using +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 +make corresponding updates to _j_ using [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 -very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this +- _((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 +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 -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 -positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative +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 values. We resolve this by using the following modified steps: ```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 -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 -that the vast majority of nonzero inputs converge to *f=g=gcd(f0, g0)* in a +that the vast majority of nonzero inputs converge to _f=g=gcd(f0, g0)_ in a number of steps proportional to their logarithm. 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 need to update the termination condition from *g=0* to *f=1*. + +- 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 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 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 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. diff --git a/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json b/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json index 9c90747993d..04e34f5a179 100644 --- a/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json +++ b/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json @@ -1,6358 +1,6358 @@ { - "algorithm" : "ECDSA", - "schema" : "ecdsa_bitcoin_verify_schema.json", - "generatorVersion" : "0.9rc5", - "numberOfTests" : 463, - "header" : [ + "algorithm": "ECDSA", + "schema": "ecdsa_bitcoin_verify_schema.json", + "generatorVersion": "0.9rc5", + "numberOfTests": 463, + "header": [ "Test vectors of type EcdsaBitcoinVerify are meant for the verification", "of a ECDSA variant used for bitcoin, that add signature non-malleability." ], - "notes" : { - "ArithmeticError" : { - "bugType" : "EDGE_CASE", - "description" : "Some implementations of ECDSA have arithmetic errors that occur when intermediate results have extreme values. This test vector has been constructed to test such occurences.", - "cves" : [ + "notes": { + "ArithmeticError": { + "bugType": "EDGE_CASE", + "description": "Some implementations of ECDSA have arithmetic errors that occur when intermediate results have extreme values. This test vector has been constructed to test such occurences.", + "cves": [ "CVE-2017-18146" ] }, - "BerEncodedSignature" : { - "bugType" : "BER_ENCODING", - "description" : "ECDSA signatures are usually DER encoded. This signature contains valid values for r and s, but it uses alternative BER encoding.", - "effect" : "Accepting alternative BER encodings may be benign in some cases, or be an issue if protocol requires signature malleability.", - "cves" : [ + "BerEncodedSignature": { + "bugType": "BER_ENCODING", + "description": "ECDSA signatures are usually DER encoded. This signature contains valid values for r and s, but it uses alternative BER encoding.", + "effect": "Accepting alternative BER encodings may be benign in some cases, or be an issue if protocol requires signature malleability.", + "cves": [ "CVE-2020-14966", "CVE-2020-13822", "CVE-2019-14859", "CVE-2016-1000342" ] }, - "EdgeCasePublicKey" : { - "bugType" : "EDGE_CASE", - "description" : "The test vector uses a special case public key. " + "EdgeCasePublicKey": { + "bugType": "EDGE_CASE", + "description": "The test vector uses a special case public key. " }, - "EdgeCaseShamirMultiplication" : { - "bugType" : "EDGE_CASE", - "description" : "Shamir proposed a fast method for computing the sum of two scalar multiplications efficiently. This test vector has been constructed so that an intermediate result is the point at infinity if Shamir's method is used." + "EdgeCaseShamirMultiplication": { + "bugType": "EDGE_CASE", + "description": "Shamir proposed a fast method for computing the sum of two scalar multiplications efficiently. This test vector has been constructed so that an intermediate result is the point at infinity if Shamir's method is used." }, - "IntegerOverflow" : { - "bugType" : "CAN_OF_WORMS", - "description" : "The test vector contains an r and s that has been modified, so that the original value is restored if the implementation ignores the most significant bits.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + "IntegerOverflow": { + "bugType": "CAN_OF_WORMS", + "description": "The test vector contains an r and s that has been modified, so that the original value is restored if the implementation ignores the most significant bits.", + "effect": "Without further analysis it is unclear if the modification can be used to forge signatures." }, - "InvalidEncoding" : { - "bugType" : "CAN_OF_WORMS", - "description" : "ECDSA signatures are encoded using ASN.1. This test vector contains an incorrectly encoded signature. The test vector itself was generated from a valid signature by modifying its encoding.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + "InvalidEncoding": { + "bugType": "CAN_OF_WORMS", + "description": "ECDSA signatures are encoded using ASN.1. This test vector contains an incorrectly encoded signature. The test vector itself was generated from a valid signature by modifying its encoding.", + "effect": "Without further analysis it is unclear if the modification can be used to forge signatures." }, - "InvalidSignature" : { - "bugType" : "AUTH_BYPASS", - "description" : "The signature contains special case values such as r=0 and s=0. Buggy implementations may accept such values, if the implementation does not check boundaries and computes s^(-1) == 0.", - "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", - "cves" : [ + "InvalidSignature": { + "bugType": "AUTH_BYPASS", + "description": "The signature contains special case values such as r=0 and s=0. Buggy implementations may accept such values, if the implementation does not check boundaries and computes s^(-1) == 0.", + "effect": "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", + "cves": [ "CVE-2022-21449", "CVE-2021-43572", "CVE-2022-24884" ] }, - "InvalidTypesInSignature" : { - "bugType" : "AUTH_BYPASS", - "description" : "The signature contains invalid types. Dynamic typed languages sometime coerce such values of different types into integers. If an implementation is careless and has additional bugs, such as not checking integer boundaries then it may be possible that such signatures are accepted.", - "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", - "cves" : [ + "InvalidTypesInSignature": { + "bugType": "AUTH_BYPASS", + "description": "The signature contains invalid types. Dynamic typed languages sometime coerce such values of different types into integers. If an implementation is careless and has additional bugs, such as not checking integer boundaries then it may be possible that such signatures are accepted.", + "effect": "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", + "cves": [ "CVE-2022-21449" ] }, - "ModifiedInteger" : { - "bugType" : "CAN_OF_WORMS", - "description" : "The test vector contains an r and s that has been modified. The goal is to check for arithmetic errors.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + "ModifiedInteger": { + "bugType": "CAN_OF_WORMS", + "description": "The test vector contains an r and s that has been modified. The goal is to check for arithmetic errors.", + "effect": "Without further analysis it is unclear if the modification can be used to forge signatures." }, - "ModifiedSignature" : { - "bugType" : "CAN_OF_WORMS", - "description" : "The test vector contains an invalid signature that was generated from a valid signature by modifying it.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + "ModifiedSignature": { + "bugType": "CAN_OF_WORMS", + "description": "The test vector contains an invalid signature that was generated from a valid signature by modifying it.", + "effect": "Without further analysis it is unclear if the modification can be used to forge signatures." }, - "ModularInverse" : { - "bugType" : "EDGE_CASE", - "description" : "The test vectors contains a signature where computing the modular inverse of s hits an edge case.", - "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", - "cves" : [ + "ModularInverse": { + "bugType": "EDGE_CASE", + "description": "The test vectors contains a signature where computing the modular inverse of s hits an edge case.", + "effect": "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", + "cves": [ "CVE-2019-0865" ] }, - "PointDuplication" : { - "bugType" : "EDGE_CASE", - "description" : "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.", - "cves" : [ + "PointDuplication": { + "bugType": "EDGE_CASE", + "description": "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.", + "cves": [ "2020-12607", "CVE-2015-2730" ] }, - "RangeCheck" : { - "bugType" : "CAN_OF_WORMS", - "description" : "The test vector contains an r and s that has been modified. By adding or subtracting the order of the group (or other values) the test vector checks whether signature verification verifies the range of r and s.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + "RangeCheck": { + "bugType": "CAN_OF_WORMS", + "description": "The test vector contains an r and s that has been modified. By adding or subtracting the order of the group (or other values) the test vector checks whether signature verification verifies the range of r and s.", + "effect": "Without further analysis it is unclear if the modification can be used to forge signatures." }, - "SignatureMalleabilityBitcoin" : { - "bugType" : "SIGNATURE_MALLEABILITY", - "description" : "\"BitCoins\"-curves are curves where signature malleability can be a serious issue. An implementation should only accept a signature s where s < n/2. If an implementation is not meant for uses cases that require signature malleability then this implemenation should be tested with another set of test vectors.", - "effect" : "In bitcoin exchanges, it may be used to make a double deposits or double withdrawals", - "links" : [ + "SignatureMalleabilityBitcoin": { + "bugType": "SIGNATURE_MALLEABILITY", + "description": "\"BitCoins\"-curves are curves where signature malleability can be a serious issue. An implementation should only accept a signature s where s < n/2. If an implementation is not meant for uses cases that require signature malleability then this implemenation should be tested with another set of test vectors.", + "effect": "In bitcoin exchanges, it may be used to make a double deposits or double withdrawals", + "links": [ "https://en.bitcoin.it/wiki/Transaction_malleability", "https://en.bitcoinwiki.org/wiki/Transaction_Malleability" ] }, - "SmallRandS" : { - "bugType" : "EDGE_CASE", - "description" : "The test vectors contains a signature where both r and s are small integers. Some libraries cannot verify such signatures.", - "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", - "cves" : [ + "SmallRandS": { + "bugType": "EDGE_CASE", + "description": "The test vectors contains a signature where both r and s are small integers. Some libraries cannot verify such signatures.", + "effect": "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", + "cves": [ "2020-13895" ] }, - "SpecialCaseHash" : { - "bugType" : "EDGE_CASE", - "description" : "The test vector contains a signature where the hash of the message is a special case, e.g., contains a long run of 0 or 1 bits." + "SpecialCaseHash": { + "bugType": "EDGE_CASE", + "description": "The test vector contains a signature where the hash of the message is a special case, e.g., contains a long run of 0 or 1 bits." }, - "ValidSignature" : { - "bugType" : "BASIC", - "description" : "The test vector contains a valid signature that was generated pseudorandomly. Such signatures should not fail to verify unless some of the parameters (e.g. curve or hash function) are not supported." + "ValidSignature": { + "bugType": "BASIC", + "description": "The test vector contains a valid signature that was generated pseudorandomly. Such signatures should not fail to verify unless some of the parameters (e.g. curve or hash function) are not supported." } }, - "testGroups" : [ + "testGroups": [ { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", - "wx" : "00b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6f", - "wy" : "00f0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", + "wx": "00b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6f", + "wy": "00f0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEuDj/ROW8F3vyEYnQdmCC/J2EMiaIf8l2\nA3EQC37iCm/wyddb+6ezGmvKGXRJbutW3jVwcZVdg8Sxutqgshgy6Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 1, - "comment" : "Signature malleability", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEuDj/ROW8F3vyEYnQdmCC/J2EMiaIf8l2\nA3EQC37iCm/wyddb+6ezGmvKGXRJbutW3jVwcZVdg8Sxutqgshgy6Q==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 1, + "comment": "Signature malleability", + "flags": [ "SignatureMalleabilityBitcoin" ], - "msg" : "313233343030", - "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022100900e75ad233fcc908509dbff5922647db37c21f4afd3203ae8dc4ae7794b0f87", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022100900e75ad233fcc908509dbff5922647db37c21f4afd3203ae8dc4ae7794b0f87", + "result": "invalid" }, { - "tcId" : 2, - "comment" : "valid", - "flags" : [ + "tcId": 2, + "comment": "valid", + "flags": [ "ValidSignature" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "valid" }, { - "tcId" : 3, - "comment" : "length of sequence [r, s] uses long form encoding", - "flags" : [ + "tcId": 3, + "comment": "length of sequence [r, s] uses long form encoding", + "flags": [ "BerEncodedSignature" ], - "msg" : "313233343030", - "sig" : "308145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "308145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 4, - "comment" : "length of sequence [r, s] contains a leading 0", - "flags" : [ + "tcId": 4, + "comment": "length of sequence [r, s] contains a leading 0", + "flags": [ "BerEncodedSignature" ], - "msg" : "313233343030", - "sig" : "30820045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30820045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 5, - "comment" : "length of sequence [r, s] uses 70 instead of 69", - "flags" : [ + "tcId": 5, + "comment": "length of sequence [r, s] uses 70 instead of 69", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 6, - "comment" : "length of sequence [r, s] uses 68 instead of 69", - "flags" : [ + "tcId": 6, + "comment": "length of sequence [r, s] uses 68 instead of 69", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 7, - "comment" : "uint32 overflow in length of sequence [r, s]", - "flags" : [ + "tcId": 7, + "comment": "uint32 overflow in length of sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30850100000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30850100000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 8, - "comment" : "uint64 overflow in length of sequence [r, s]", - "flags" : [ + "tcId": 8, + "comment": "uint64 overflow in length of sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3089010000000000000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3089010000000000000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 9, - "comment" : "length of sequence [r, s] = 2**31 - 1", - "flags" : [ + "tcId": 9, + "comment": "length of sequence [r, s] = 2**31 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30847fffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30847fffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 10, - "comment" : "length of sequence [r, s] = 2**31", - "flags" : [ + "tcId": 10, + "comment": "length of sequence [r, s] = 2**31", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "308480000000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "308480000000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 11, - "comment" : "length of sequence [r, s] = 2**32 - 1", - "flags" : [ + "tcId": 11, + "comment": "length of sequence [r, s] = 2**32 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3084ffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3084ffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 12, - "comment" : "length of sequence [r, s] = 2**40 - 1", - "flags" : [ + "tcId": 12, + "comment": "length of sequence [r, s] = 2**40 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3085ffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3085ffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 13, - "comment" : "length of sequence [r, s] = 2**64 - 1", - "flags" : [ + "tcId": 13, + "comment": "length of sequence [r, s] = 2**64 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3088ffffffffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3088ffffffffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 14, - "comment" : "incorrect length of sequence [r, s]", - "flags" : [ + "tcId": 14, + "comment": "incorrect length of sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30ff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30ff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 15, - "comment" : "replaced sequence [r, s] by an indefinite length tag without termination", - "flags" : [ + "tcId": 15, + "comment": "replaced sequence [r, s] by an indefinite length tag without termination", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 16, - "comment" : "removing sequence [r, s]", - "flags" : [ + "tcId": 16, + "comment": "removing sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "", - "result" : "invalid" + "msg": "313233343030", + "sig": "", + "result": "invalid" }, { - "tcId" : 17, - "comment" : "lonely sequence tag", - "flags" : [ + "tcId": 17, + "comment": "lonely sequence tag", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30", - "result" : "invalid" + "msg": "313233343030", + "sig": "30", + "result": "invalid" }, { - "tcId" : 18, - "comment" : "appending 0's to sequence [r, s]", - "flags" : [ + "tcId": 18, + "comment": "appending 0's to sequence [r, s]", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result": "invalid" }, { - "tcId" : 19, - "comment" : "prepending 0's to sequence [r, s]", - "flags" : [ + "tcId": 19, + "comment": "prepending 0's to sequence [r, s]", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "30470000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30470000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 20, - "comment" : "appending unused 0's to sequence [r, s]", - "flags" : [ + "tcId": 20, + "comment": "appending unused 0's to sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result": "invalid" }, { - "tcId" : 21, - "comment" : "appending null value to sequence [r, s]", - "flags" : [ + "tcId": 21, + "comment": "appending null value to sequence [r, s]", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", + "result": "invalid" }, { - "tcId" : 22, - "comment" : "prepending garbage to sequence [r, s]", - "flags" : [ + "tcId": 22, + "comment": "prepending garbage to sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304a4981773045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304a4981773045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 23, - "comment" : "prepending garbage to sequence [r, s]", - "flags" : [ + "tcId": 23, + "comment": "prepending garbage to sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304925003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304925003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 24, - "comment" : "appending garbage to sequence [r, s]", - "flags" : [ + "tcId": 24, + "comment": "appending garbage to sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", - "result" : "invalid" + "msg": "313233343030", + "sig": "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", + "result": "invalid" }, { - "tcId" : 25, - "comment" : "including undefined tags", - "flags" : [ + "tcId": 25, + "comment": "including undefined tags", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "304daa00bb00cd003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304daa00bb00cd003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 26, - "comment" : "including undefined tags", - "flags" : [ + "tcId": 26, + "comment": "including undefined tags", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304d2229aa00bb00cd00022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304d2229aa00bb00cd00022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 27, - "comment" : "including undefined tags", - "flags" : [ + "tcId": 27, + "comment": "including undefined tags", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652228aa00bb00cd0002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652228aa00bb00cd0002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 28, - "comment" : "truncated length of sequence [r, s]", - "flags" : [ + "tcId": 28, + "comment": "truncated length of sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3081", - "result" : "invalid" + "msg": "313233343030", + "sig": "3081", + "result": "invalid" }, { - "tcId" : 29, - "comment" : "including undefined tags to sequence [r, s]", - "flags" : [ + "tcId": 29, + "comment": "including undefined tags to sequence [r, s]", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "304baa02aabb3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304baa02aabb3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 30, - "comment" : "using composition with indefinite length for sequence [r, s]", - "flags" : [ + "tcId": 30, + "comment": "using composition with indefinite length for sequence [r, s]", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "30803045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" + "msg": "313233343030", + "sig": "30803045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result": "invalid" }, { - "tcId" : 31, - "comment" : "using composition with wrong tag for sequence [r, s]", - "flags" : [ + "tcId": 31, + "comment": "using composition with wrong tag for sequence [r, s]", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "30803145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" + "msg": "313233343030", + "sig": "30803145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result": "invalid" }, { - "tcId" : 32, - "comment" : "Replacing sequence [r, s] with NULL", - "flags" : [ + "tcId": 32, + "comment": "Replacing sequence [r, s] with NULL", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "0500", - "result" : "invalid" + "msg": "313233343030", + "sig": "0500", + "result": "invalid" }, { - "tcId" : 33, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ + "tcId": 33, + "comment": "changing tag value of sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "2e45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "2e45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 34, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ + "tcId": 34, + "comment": "changing tag value of sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "2f45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "2f45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 35, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ + "tcId": 35, + "comment": "changing tag value of sequence [r, s]", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 36, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ + "tcId": 36, + "comment": "changing tag value of sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3245022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3245022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 37, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ + "tcId": 37, + "comment": "changing tag value of sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "ff45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "ff45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 38, - "comment" : "dropping value of sequence [r, s]", - "flags" : [ + "tcId": 38, + "comment": "dropping value of sequence [r, s]", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3000", + "result": "invalid" }, { - "tcId" : 39, - "comment" : "using composition for sequence [r, s]", - "flags" : [ + "tcId": 39, + "comment": "using composition for sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304930010230442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304930010230442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 40, - "comment" : "truncated sequence [r, s]", - "flags" : [ + "tcId": 40, + "comment": "truncated sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", + "result": "invalid" }, { - "tcId" : 41, - "comment" : "truncated sequence [r, s]", - "flags" : [ + "tcId": 41, + "comment": "truncated sequence [r, s]", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 42, - "comment" : "sequence [r, s] of size 4166 to check for overflows", - "flags" : [ + "tcId": 42, + "comment": "sequence [r, s] of size 4166 to check for overflows", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30821046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid" + "msg": "313233343030", + "sig": "30821046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result": "invalid" }, { - "tcId" : 43, - "comment" : "indefinite length", - "flags" : [ + "tcId": 43, + "comment": "indefinite length", + "flags": [ "BerEncodedSignature" ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result": "invalid" }, { - "tcId" : 44, - "comment" : "indefinite length with truncated delimiter", - "flags" : [ + "tcId": 44, + "comment": "indefinite length with truncated delimiter", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba00", - "result" : "invalid" + "msg": "313233343030", + "sig": "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba00", + "result": "invalid" }, { - "tcId" : 45, - "comment" : "indefinite length with additional element", - "flags" : [ + "tcId": 45, + "comment": "indefinite length with additional element", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba05000000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba05000000", + "result": "invalid" }, { - "tcId" : 46, - "comment" : "indefinite length with truncated element", - "flags" : [ + "tcId": 46, + "comment": "indefinite length with truncated element", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba060811220000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba060811220000", + "result": "invalid" }, { - "tcId" : 47, - "comment" : "indefinite length with garbage", - "flags" : [ + "tcId": 47, + "comment": "indefinite length with garbage", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000fe02beef", - "result" : "invalid" + "msg": "313233343030", + "sig": "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000fe02beef", + "result": "invalid" }, { - "tcId" : 48, - "comment" : "indefinite length with nonempty EOC", - "flags" : [ + "tcId": 48, + "comment": "indefinite length with nonempty EOC", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0002beef", - "result" : "invalid" + "msg": "313233343030", + "sig": "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0002beef", + "result": "invalid" }, { - "tcId" : 49, - "comment" : "prepend empty sequence", - "flags" : [ + "tcId": 49, + "comment": "prepend empty sequence", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "30473000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30473000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 50, - "comment" : "append empty sequence", - "flags" : [ + "tcId": 50, + "comment": "append empty sequence", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba3000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba3000", + "result": "invalid" }, { - "tcId" : 51, - "comment" : "append zero", - "flags" : [ + "tcId": 51, + "comment": "append zero", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba020100", + "result": "invalid" }, { - "tcId" : 52, - "comment" : "append garbage with high tag number", - "flags" : [ + "tcId": 52, + "comment": "append garbage with high tag number", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31babf7f00", - "result" : "invalid" + "msg": "313233343030", + "sig": "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31babf7f00", + "result": "invalid" }, { - "tcId" : 53, - "comment" : "append null with explicit tag", - "flags" : [ + "tcId": 53, + "comment": "append null with explicit tag", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa0020500", - "result" : "invalid" + "msg": "313233343030", + "sig": "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa0020500", + "result": "invalid" }, { - "tcId" : 54, - "comment" : "append null with implicit tag", - "flags" : [ + "tcId": 54, + "comment": "append null with implicit tag", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa000", + "result": "invalid" }, { - "tcId" : 55, - "comment" : "sequence of sequence", - "flags" : [ + "tcId": 55, + "comment": "sequence of sequence", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 56, - "comment" : "truncated sequence: removed last 1 elements", - "flags" : [ + "tcId": 56, + "comment": "truncated sequence: removed last 1 elements", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3023022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365", - "result" : "invalid" + "msg": "313233343030", + "sig": "3023022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365", + "result": "invalid" }, { - "tcId" : 57, - "comment" : "repeating element in sequence", - "flags" : [ + "tcId": 57, + "comment": "repeating element in sequence", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3067022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3067022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 58, - "comment" : "flipped bit 0 in r", - "flags" : [ + "tcId": 58, + "comment": "flipped bit 0 in r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 59, - "comment" : "flipped bit 32 in r", - "flags" : [ + "tcId": 59, + "comment": "flipped bit 32 in r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccac983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccac983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 60, - "comment" : "flipped bit 48 in r", - "flags" : [ + "tcId": 60, + "comment": "flipped bit 48 in r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5133ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5133ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 61, - "comment" : "flipped bit 64 in r", - "flags" : [ + "tcId": 61, + "comment": "flipped bit 64 in r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc08b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc08b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 62, - "comment" : "length of r uses long form encoding", - "flags" : [ + "tcId": 62, + "comment": "length of r uses long form encoding", + "flags": [ "BerEncodedSignature" ], - "msg" : "313233343030", - "sig" : "304602812100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304602812100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 63, - "comment" : "length of r contains a leading 0", - "flags" : [ + "tcId": 63, + "comment": "length of r contains a leading 0", + "flags": [ "BerEncodedSignature" ], - "msg" : "313233343030", - "sig" : "30470282002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30470282002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 64, - "comment" : "length of r uses 34 instead of 33", - "flags" : [ + "tcId": 64, + "comment": "length of r uses 34 instead of 33", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 65, - "comment" : "length of r uses 32 instead of 33", - "flags" : [ + "tcId": 65, + "comment": "length of r uses 32 instead of 33", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 66, - "comment" : "uint32 overflow in length of r", - "flags" : [ + "tcId": 66, + "comment": "uint32 overflow in length of r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304a0285010000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304a0285010000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 67, - "comment" : "uint64 overflow in length of r", - "flags" : [ + "tcId": 67, + "comment": "uint64 overflow in length of r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304e028901000000000000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304e028901000000000000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 68, - "comment" : "length of r = 2**31 - 1", - "flags" : [ + "tcId": 68, + "comment": "length of r = 2**31 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304902847fffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304902847fffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 69, - "comment" : "length of r = 2**31", - "flags" : [ + "tcId": 69, + "comment": "length of r = 2**31", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304902848000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304902848000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 70, - "comment" : "length of r = 2**32 - 1", - "flags" : [ + "tcId": 70, + "comment": "length of r = 2**32 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30490284ffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30490284ffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 71, - "comment" : "length of r = 2**40 - 1", - "flags" : [ + "tcId": 71, + "comment": "length of r = 2**40 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304a0285ffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304a0285ffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 72, - "comment" : "length of r = 2**64 - 1", - "flags" : [ + "tcId": 72, + "comment": "length of r = 2**64 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304d0288ffffffffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304d0288ffffffffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 73, - "comment" : "incorrect length of r", - "flags" : [ + "tcId": 73, + "comment": "incorrect length of r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304502ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304502ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 74, - "comment" : "replaced r by an indefinite length tag without termination", - "flags" : [ + "tcId": 74, + "comment": "replaced r by an indefinite length tag without termination", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045028000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045028000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 75, - "comment" : "removing r", - "flags" : [ + "tcId": 75, + "comment": "removing r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "302202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "302202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 76, - "comment" : "lonely integer tag", - "flags" : [ + "tcId": 76, + "comment": "lonely integer tag", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30230202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30230202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 77, - "comment" : "lonely integer tag", - "flags" : [ + "tcId": 77, + "comment": "lonely integer tag", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3024022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502", - "result" : "invalid" + "msg": "313233343030", + "sig": "3024022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502", + "result": "invalid" }, { - "tcId" : 78, - "comment" : "appending 0's to r", - "flags" : [ + "tcId": 78, + "comment": "appending 0's to r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 79, - "comment" : "prepending 0's to r", - "flags" : [ + "tcId": 79, + "comment": "prepending 0's to r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30470223000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30470223000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 80, - "comment" : "appending unused 0's to r", - "flags" : [ + "tcId": 80, + "comment": "appending unused 0's to r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 81, - "comment" : "appending null value to r", - "flags" : [ + "tcId": 81, + "comment": "appending null value to r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 82, - "comment" : "prepending garbage to r", - "flags" : [ + "tcId": 82, + "comment": "prepending garbage to r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304a2226498177022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304a2226498177022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 83, - "comment" : "prepending garbage to r", - "flags" : [ + "tcId": 83, + "comment": "prepending garbage to r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304922252500022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304922252500022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 84, - "comment" : "appending garbage to r", - "flags" : [ + "tcId": 84, + "comment": "appending garbage to r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304d2223022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650004deadbeef02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304d2223022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650004deadbeef02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 85, - "comment" : "truncated length of r", - "flags" : [ + "tcId": 85, + "comment": "truncated length of r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3024028102206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3024028102206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 86, - "comment" : "including undefined tags to r", - "flags" : [ + "tcId": 86, + "comment": "including undefined tags to r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304b2227aa02aabb022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304b2227aa02aabb022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 87, - "comment" : "using composition with indefinite length for r", - "flags" : [ + "tcId": 87, + "comment": "using composition with indefinite length for r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30492280022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30492280022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 88, - "comment" : "using composition with wrong tag for r", - "flags" : [ + "tcId": 88, + "comment": "using composition with wrong tag for r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "30492280032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30492280032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 89, - "comment" : "Replacing r with NULL", - "flags" : [ + "tcId": 89, + "comment": "Replacing r with NULL", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3024050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3024050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 90, - "comment" : "changing tag value of r", - "flags" : [ + "tcId": 90, + "comment": "changing tag value of r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 91, - "comment" : "changing tag value of r", - "flags" : [ + "tcId": 91, + "comment": "changing tag value of r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045012100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045012100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 92, - "comment" : "changing tag value of r", - "flags" : [ + "tcId": 92, + "comment": "changing tag value of r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 93, - "comment" : "changing tag value of r", - "flags" : [ + "tcId": 93, + "comment": "changing tag value of r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045042100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045042100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 94, - "comment" : "changing tag value of r", - "flags" : [ + "tcId": 94, + "comment": "changing tag value of r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045ff2100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045ff2100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 95, - "comment" : "dropping value of r", - "flags" : [ + "tcId": 95, + "comment": "dropping value of r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3024020002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3024020002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 96, - "comment" : "using composition for r", - "flags" : [ + "tcId": 96, + "comment": "using composition for r", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304922250201000220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304922250201000220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 97, - "comment" : "modifying first byte of r", - "flags" : [ + "tcId": 97, + "comment": "modifying first byte of r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045022102813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022102813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 98, - "comment" : "modifying last byte of r", - "flags" : [ + "tcId": 98, + "comment": "modifying last byte of r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323e502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323e502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 99, - "comment" : "truncated r", - "flags" : [ + "tcId": 99, + "comment": "truncated r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3044022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832302206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832302206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 100, - "comment" : "truncated r", - "flags" : [ + "tcId": 100, + "comment": "truncated r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "30440220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30440220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 101, - "comment" : "r of size 4130 to check for overflows", - "flags" : [ + "tcId": 101, + "comment": "r of size 4130 to check for overflows", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "308210480282102200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "308210480282102200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 102, - "comment" : "leading ff in r", - "flags" : [ + "tcId": 102, + "comment": "leading ff in r", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "30460222ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30460222ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 103, - "comment" : "replaced r by infinity", - "flags" : [ + "tcId": 103, + "comment": "replaced r by infinity", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "302509018002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "302509018002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 104, - "comment" : "replacing r with zero", - "flags" : [ + "tcId": 104, + "comment": "replacing r with zero", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "302502010002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "302502010002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 105, - "comment" : "flipped bit 0 in s", - "flags" : [ + "tcId": 105, + "comment": "flipped bit 0 in s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31bb", - "result" : "invalid" + "msg": "313233343030", + "sig": "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31bb", + "result": "invalid" }, { - "tcId" : 106, - "comment" : "flipped bit 32 in s", - "flags" : [ + "tcId": 106, + "comment": "flipped bit 32 in s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a456eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a456eb31ba", + "result": "invalid" }, { - "tcId" : 107, - "comment" : "flipped bit 48 in s", - "flags" : [ + "tcId": 107, + "comment": "flipped bit 48 in s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f713a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f713a556eb31ba", + "result": "invalid" }, { - "tcId" : 108, - "comment" : "flipped bit 64 in s", - "flags" : [ + "tcId": 108, + "comment": "flipped bit 64 in s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758001d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758001d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 109, - "comment" : "length of s uses long form encoding", - "flags" : [ + "tcId": 109, + "comment": "length of s uses long form encoding", + "flags": [ "BerEncodedSignature" ], - "msg" : "313233343030", - "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 110, - "comment" : "length of s contains a leading 0", - "flags" : [ + "tcId": 110, + "comment": "length of s contains a leading 0", + "flags": [ "BerEncodedSignature" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028200206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028200206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 111, - "comment" : "length of s uses 33 instead of 32", - "flags" : [ + "tcId": 111, + "comment": "length of s uses 33 instead of 32", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 112, - "comment" : "length of s uses 31 instead of 32", - "flags" : [ + "tcId": 112, + "comment": "length of s uses 31 instead of 32", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 113, - "comment" : "uint32 overflow in length of s", - "flags" : [ + "tcId": 113, + "comment": "uint32 overflow in length of s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028501000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028501000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 114, - "comment" : "uint64 overflow in length of s", - "flags" : [ + "tcId": 114, + "comment": "uint64 overflow in length of s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304e022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502890100000000000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304e022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502890100000000000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 115, - "comment" : "length of s = 2**31 - 1", - "flags" : [ + "tcId": 115, + "comment": "length of s = 2**31 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502847fffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502847fffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 116, - "comment" : "length of s = 2**31", - "flags" : [ + "tcId": 116, + "comment": "length of s = 2**31", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284800000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284800000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 117, - "comment" : "length of s = 2**32 - 1", - "flags" : [ + "tcId": 117, + "comment": "length of s = 2**32 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284ffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284ffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 118, - "comment" : "length of s = 2**40 - 1", - "flags" : [ + "tcId": 118, + "comment": "length of s = 2**40 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650285ffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650285ffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 119, - "comment" : "length of s = 2**64 - 1", - "flags" : [ + "tcId": 119, + "comment": "length of s = 2**64 - 1", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650288ffffffffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650288ffffffffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 120, - "comment" : "incorrect length of s", - "flags" : [ + "tcId": 120, + "comment": "incorrect length of s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 121, - "comment" : "replaced s by an indefinite length tag without termination", - "flags" : [ + "tcId": 121, + "comment": "replaced s by an indefinite length tag without termination", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502806ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502806ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 122, - "comment" : "appending 0's to s", - "flags" : [ + "tcId": 122, + "comment": "appending 0's to s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result": "invalid" }, { - "tcId" : 123, - "comment" : "prepending 0's to s", - "flags" : [ + "tcId": 123, + "comment": "prepending 0's to s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022200006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022200006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 124, - "comment" : "appending null value to s", - "flags" : [ + "tcId": 124, + "comment": "appending null value to s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", - "result" : "invalid" + "msg": "313233343030", + "sig": "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", + "result": "invalid" }, { - "tcId" : 125, - "comment" : "prepending garbage to s", - "flags" : [ + "tcId": 125, + "comment": "prepending garbage to s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222549817702206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222549817702206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 126, - "comment" : "prepending garbage to s", - "flags" : [ + "tcId": 126, + "comment": "prepending garbage to s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652224250002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652224250002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 127, - "comment" : "appending garbage to s", - "flags" : [ + "tcId": 127, + "comment": "appending garbage to s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", - "result" : "invalid" + "msg": "313233343030", + "sig": "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", + "result": "invalid" }, { - "tcId" : 128, - "comment" : "truncated length of s", - "flags" : [ + "tcId": 128, + "comment": "truncated length of s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281", + "result": "invalid" }, { - "tcId" : 129, - "comment" : "including undefined tags to s", - "flags" : [ + "tcId": 129, + "comment": "including undefined tags to s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "304b022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652226aa02aabb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304b022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652226aa02aabb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 130, - "comment" : "using composition with indefinite length for s", - "flags" : [ + "tcId": 130, + "comment": "using composition with indefinite length for s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result": "invalid" }, { - "tcId" : 131, - "comment" : "using composition with wrong tag for s", - "flags" : [ + "tcId": 131, + "comment": "using composition with wrong tag for s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228003206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228003206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result": "invalid" }, { - "tcId" : 132, - "comment" : "Replacing s with NULL", - "flags" : [ + "tcId": 132, + "comment": "Replacing s with NULL", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650500", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650500", + "result": "invalid" }, { - "tcId" : 133, - "comment" : "changing tag value of s", - "flags" : [ + "tcId": 133, + "comment": "changing tag value of s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236500206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236500206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 134, - "comment" : "changing tag value of s", - "flags" : [ + "tcId": 134, + "comment": "changing tag value of s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236501206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236501206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 135, - "comment" : "changing tag value of s", - "flags" : [ + "tcId": 135, + "comment": "changing tag value of s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236503206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236503206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 136, - "comment" : "changing tag value of s", - "flags" : [ + "tcId": 136, + "comment": "changing tag value of s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236504206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236504206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 137, - "comment" : "changing tag value of s", - "flags" : [ + "tcId": 137, + "comment": "changing tag value of s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365ff206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365ff206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 138, - "comment" : "dropping value of s", - "flags" : [ + "tcId": 138, + "comment": "dropping value of s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650200", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650200", + "result": "invalid" }, { - "tcId" : 139, - "comment" : "using composition for s", - "flags" : [ + "tcId": 139, + "comment": "using composition for s", + "flags": [ "InvalidEncoding" ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222402016f021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222402016f021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 140, - "comment" : "modifying first byte of s", - "flags" : [ + "tcId": 140, + "comment": "modifying first byte of s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206df18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206df18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 141, - "comment" : "modifying last byte of s", - "flags" : [ + "tcId": 141, + "comment": "modifying last byte of s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb313a", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb313a", + "result": "invalid" }, { - "tcId" : 142, - "comment" : "truncated s", - "flags" : [ + "tcId": 142, + "comment": "truncated s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", + "result": "invalid" }, { - "tcId" : 143, - "comment" : "truncated s", - "flags" : [ + "tcId": 143, + "comment": "truncated s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 144, - "comment" : "s of size 4129 to check for overflows", - "flags" : [ + "tcId": 144, + "comment": "s of size 4129 to check for overflows", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "30821048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028210216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid" + "msg": "313233343030", + "sig": "30821048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028210216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result": "invalid" }, { - "tcId" : 145, - "comment" : "leading ff in s", - "flags" : [ + "tcId": 145, + "comment": "leading ff in s", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 146, - "comment" : "replaced s by infinity", - "flags" : [ + "tcId": 146, + "comment": "replaced s by infinity", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365090180", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365090180", + "result": "invalid" }, { - "tcId" : 147, - "comment" : "replacing s with zero", - "flags" : [ + "tcId": 147, + "comment": "replacing s with zero", + "flags": [ "ModifiedSignature" ], - "msg" : "313233343030", - "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365020100", + "result": "invalid" }, { - "tcId" : 148, - "comment" : "replaced r by r + n", - "flags" : [ + "tcId": 148, + "comment": "replaced r by r + n", + "flags": [ "RangeCheck" ], - "msg" : "313233343030", - "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478583b90deabca4b05c4574e49b5899b964a602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022101813ef79ccefa9a56f7ba805f0e478583b90deabca4b05c4574e49b5899b964a602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 149, - "comment" : "replaced r by r - n", - "flags" : [ + "tcId": 149, + "comment": "replaced r by r - n", + "flags": [ "RangeCheck" ], - "msg" : "313233343030", - "sig" : "30440220813ef79ccefa9a56f7ba805f0e47858643b030ef461f1bcdf53fde3ef94ce22402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30440220813ef79ccefa9a56f7ba805f0e47858643b030ef461f1bcdf53fde3ef94ce22402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 150, - "comment" : "replaced r by r + 256 * n", - "flags" : [ + "tcId": 150, + "comment": "replaced r by r + 256 * n", + "flags": [ "RangeCheck" ], - "msg" : "313233343030", - "sig" : "304602220100813ef79ccefa9a56f7ba805f0e47843fad3bf4853e07f7c98770c99bffc4646502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304602220100813ef79ccefa9a56f7ba805f0e47843fad3bf4853e07f7c98770c99bffc4646502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 151, - "comment" : "replaced r by -r", - "flags" : [ + "tcId": 151, + "comment": "replaced r by -r", + "flags": [ "ModifiedInteger" ], - "msg" : "313233343030", - "sig" : "30450221ff7ec10863310565a908457fa0f1b87a7b01a0f22a0a9843f64aedc334367cdc9b02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30450221ff7ec10863310565a908457fa0f1b87a7b01a0f22a0a9843f64aedc334367cdc9b02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 152, - "comment" : "replaced r by n - r", - "flags" : [ + "tcId": 152, + "comment": "replaced r by n - r", + "flags": [ "ModifiedInteger" ], - "msg" : "313233343030", - "sig" : "304402207ec10863310565a908457fa0f1b87a79bc4fcf10b9e0e4320ac021c106b31ddc02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304402207ec10863310565a908457fa0f1b87a79bc4fcf10b9e0e4320ac021c106b31ddc02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 153, - "comment" : "replaced r by -n - r", - "flags" : [ + "tcId": 153, + "comment": "replaced r by -n - r", + "flags": [ "ModifiedInteger" ], - "msg" : "313233343030", - "sig" : "30450221fe7ec10863310565a908457fa0f1b87a7c46f215435b4fa3ba8b1b64a766469b5a02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30450221fe7ec10863310565a908457fa0f1b87a7c46f215435b4fa3ba8b1b64a766469b5a02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 154, - "comment" : "replaced r by r + 2**256", - "flags" : [ + "tcId": 154, + "comment": "replaced r by r + 2**256", + "flags": [ "IntegerOverflow" ], - "msg" : "313233343030", - "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022101813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 155, - "comment" : "replaced r by r + 2**320", - "flags" : [ + "tcId": 155, + "comment": "replaced r by r + 2**320", + "flags": [ "IntegerOverflow" ], - "msg" : "313233343030", - "sig" : "304d0229010000000000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304d0229010000000000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 156, - "comment" : "replaced s by s + n", - "flags" : [ + "tcId": 156, + "comment": "replaced s by s + n", + "flags": [ "RangeCheck" ], - "msg" : "313233343030", - "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b7fc1e197d8aebe203c96c87232272172fb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30450221016ff18a52dcc0336f7af62400a6dd9b7fc1e197d8aebe203c96c87232272172fb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 157, - "comment" : "replaced s by s - n", - "flags" : [ + "tcId": 157, + "comment": "replaced s by s - n", + "flags": [ "RangeCheck" ], - "msg" : "313233343030", - "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b824c83de0b502cdfc51723b51886b4f07902206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30450221ff6ff18a52dcc0336f7af62400a6dd9b824c83de0b502cdfc51723b51886b4f07902206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 158, - "comment" : "replaced s by s + 256 * n", - "flags" : [ + "tcId": 158, + "comment": "replaced s by s + 256 * n", + "flags": [ "RangeCheck" ], - "msg" : "313233343030", - "sig" : "3046022201006ff18a52dcc0336f7af62400a6dd9a3bb60fa1a14815bbc0a954a0758d2c72ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022201006ff18a52dcc0336f7af62400a6dd9a3bb60fa1a14815bbc0a954a0758d2c72ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 159, - "comment" : "replaced s by -s", - "flags" : [ + "tcId": 159, + "comment": "replaced s by -s", + "flags": [ "ModifiedInteger" ], - "msg" : "313233343030", - "sig" : "30440220900e75ad233fcc908509dbff5922647ef8cd450e008a7fff2909ec5aa914ce4602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30440220900e75ad233fcc908509dbff5922647ef8cd450e008a7fff2909ec5aa914ce4602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 160, - "comment" : "replaced s by -n - s", - "flags" : [ + "tcId": 160, + "comment": "replaced s by -n - s", + "flags": [ "ModifiedInteger" ], - "msg" : "313233343030", - "sig" : "30450221fe900e75ad233fcc908509dbff592264803e1e68275141dfc369378dcdd8de8d0502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30450221fe900e75ad233fcc908509dbff592264803e1e68275141dfc369378dcdd8de8d0502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 161, - "comment" : "replaced s by s + 2**256", - "flags" : [ + "tcId": 161, + "comment": "replaced s by s + 2**256", + "flags": [ "IntegerOverflow" ], - "msg" : "313233343030", - "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30450221016ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 162, - "comment" : "replaced s by s - 2**256", - "flags" : [ + "tcId": 162, + "comment": "replaced s by s - 2**256", + "flags": [ "IntegerOverflow" ], - "msg" : "313233343030", - "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "30450221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 163, - "comment" : "replaced s by s + 2**320", - "flags" : [ + "tcId": 163, + "comment": "replaced s by s + 2**320", + "flags": [ "IntegerOverflow" ], - "msg" : "313233343030", - "sig" : "304d02290100000000000000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" + "msg": "313233343030", + "sig": "304d02290100000000000000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result": "invalid" }, { - "tcId" : 164, - "comment" : "Signature with special case values r=0 and s=0", - "flags" : [ + "tcId": 164, + "comment": "Signature with special case values r=0 and s=0", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3006020100020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020100020100", + "result": "invalid" }, { - "tcId" : 165, - "comment" : "Signature with special case values r=0 and s=1", - "flags" : [ + "tcId": 165, + "comment": "Signature with special case values r=0 and s=1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3006020100020101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020100020101", + "result": "invalid" }, { - "tcId" : 166, - "comment" : "Signature with special case values r=0 and s=-1", - "flags" : [ + "tcId": 166, + "comment": "Signature with special case values r=0 and s=-1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30060201000201ff", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201000201ff", + "result": "invalid" }, { - "tcId" : 167, - "comment" : "Signature with special case values r=0 and s=n", - "flags" : [ + "tcId": 167, + "comment": "Signature with special case values r=0 and s=n", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result": "invalid" }, { - "tcId" : 168, - "comment" : "Signature with special case values r=0 and s=n - 1", - "flags" : [ + "tcId": 168, + "comment": "Signature with special case values r=0 and s=n - 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result": "invalid" }, { - "tcId" : 169, - "comment" : "Signature with special case values r=0 and s=n + 1", - "flags" : [ + "tcId": 169, + "comment": "Signature with special case values r=0 and s=n + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result": "invalid" }, { - "tcId" : 170, - "comment" : "Signature with special case values r=0 and s=p", - "flags" : [ + "tcId": 170, + "comment": "Signature with special case values r=0 and s=p", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result": "invalid" }, { - "tcId" : 171, - "comment" : "Signature with special case values r=0 and s=p + 1", - "flags" : [ + "tcId": 171, + "comment": "Signature with special case values r=0 and s=p + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result": "invalid" }, { - "tcId" : 172, - "comment" : "Signature with special case values r=1 and s=0", - "flags" : [ + "tcId": 172, + "comment": "Signature with special case values r=1 and s=0", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3006020101020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020101020100", + "result": "invalid" }, { - "tcId" : 173, - "comment" : "Signature with special case values r=1 and s=1", - "flags" : [ + "tcId": 173, + "comment": "Signature with special case values r=1 and s=1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3006020101020101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020101020101", + "result": "invalid" }, { - "tcId" : 174, - "comment" : "Signature with special case values r=1 and s=-1", - "flags" : [ + "tcId": 174, + "comment": "Signature with special case values r=1 and s=-1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30060201010201ff", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201010201ff", + "result": "invalid" }, { - "tcId" : 175, - "comment" : "Signature with special case values r=1 and s=n", - "flags" : [ + "tcId": 175, + "comment": "Signature with special case values r=1 and s=n", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result": "invalid" }, { - "tcId" : 176, - "comment" : "Signature with special case values r=1 and s=n - 1", - "flags" : [ + "tcId": 176, + "comment": "Signature with special case values r=1 and s=n - 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result": "invalid" }, { - "tcId" : 177, - "comment" : "Signature with special case values r=1 and s=n + 1", - "flags" : [ + "tcId": 177, + "comment": "Signature with special case values r=1 and s=n + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result": "invalid" }, { - "tcId" : 178, - "comment" : "Signature with special case values r=1 and s=p", - "flags" : [ + "tcId": 178, + "comment": "Signature with special case values r=1 and s=p", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result": "invalid" }, { - "tcId" : 179, - "comment" : "Signature with special case values r=1 and s=p + 1", - "flags" : [ + "tcId": 179, + "comment": "Signature with special case values r=1 and s=p + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result": "invalid" }, { - "tcId" : 180, - "comment" : "Signature with special case values r=-1 and s=0", - "flags" : [ + "tcId": 180, + "comment": "Signature with special case values r=-1 and s=0", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30060201ff020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201ff020100", + "result": "invalid" }, { - "tcId" : 181, - "comment" : "Signature with special case values r=-1 and s=1", - "flags" : [ + "tcId": 181, + "comment": "Signature with special case values r=-1 and s=1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30060201ff020101", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201ff020101", + "result": "invalid" }, { - "tcId" : 182, - "comment" : "Signature with special case values r=-1 and s=-1", - "flags" : [ + "tcId": 182, + "comment": "Signature with special case values r=-1 and s=-1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30060201ff0201ff", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201ff0201ff", + "result": "invalid" }, { - "tcId" : 183, - "comment" : "Signature with special case values r=-1 and s=n", - "flags" : [ + "tcId": 183, + "comment": "Signature with special case values r=-1 and s=n", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" + "msg": "313233343030", + "sig": "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result": "invalid" }, { - "tcId" : 184, - "comment" : "Signature with special case values r=-1 and s=n - 1", - "flags" : [ + "tcId": 184, + "comment": "Signature with special case values r=-1 and s=n - 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" + "msg": "313233343030", + "sig": "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result": "invalid" }, { - "tcId" : 185, - "comment" : "Signature with special case values r=-1 and s=n + 1", - "flags" : [ + "tcId": 185, + "comment": "Signature with special case values r=-1 and s=n + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" + "msg": "313233343030", + "sig": "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result": "invalid" }, { - "tcId" : 186, - "comment" : "Signature with special case values r=-1 and s=p", - "flags" : [ + "tcId": 186, + "comment": "Signature with special case values r=-1 and s=p", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" + "msg": "313233343030", + "sig": "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result": "invalid" }, { - "tcId" : 187, - "comment" : "Signature with special case values r=-1 and s=p + 1", - "flags" : [ + "tcId": 187, + "comment": "Signature with special case values r=-1 and s=p + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" + "msg": "313233343030", + "sig": "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result": "invalid" }, { - "tcId" : 188, - "comment" : "Signature with special case values r=n and s=0", - "flags" : [ + "tcId": 188, + "comment": "Signature with special case values r=n and s=0", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020100", + "result": "invalid" }, { - "tcId" : 189, - "comment" : "Signature with special case values r=n and s=1", - "flags" : [ + "tcId": 189, + "comment": "Signature with special case values r=n and s=1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101", + "result": "invalid" }, { - "tcId" : 190, - "comment" : "Signature with special case values r=n and s=-1", - "flags" : [ + "tcId": 190, + "comment": "Signature with special case values r=n and s=-1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410201ff", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410201ff", + "result": "invalid" }, { - "tcId" : 191, - "comment" : "Signature with special case values r=n and s=n", - "flags" : [ + "tcId": 191, + "comment": "Signature with special case values r=n and s=n", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result": "invalid" }, { - "tcId" : 192, - "comment" : "Signature with special case values r=n and s=n - 1", - "flags" : [ + "tcId": 192, + "comment": "Signature with special case values r=n and s=n - 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result": "invalid" }, { - "tcId" : 193, - "comment" : "Signature with special case values r=n and s=n + 1", - "flags" : [ + "tcId": 193, + "comment": "Signature with special case values r=n and s=n + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result": "invalid" }, { - "tcId" : 194, - "comment" : "Signature with special case values r=n and s=p", - "flags" : [ + "tcId": 194, + "comment": "Signature with special case values r=n and s=p", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result": "invalid" }, { - "tcId" : 195, - "comment" : "Signature with special case values r=n and s=p + 1", - "flags" : [ + "tcId": 195, + "comment": "Signature with special case values r=n and s=p + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result": "invalid" }, { - "tcId" : 196, - "comment" : "Signature with special case values r=n - 1 and s=0", - "flags" : [ + "tcId": 196, + "comment": "Signature with special case values r=n - 1 and s=0", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020100", + "result": "invalid" }, { - "tcId" : 197, - "comment" : "Signature with special case values r=n - 1 and s=1", - "flags" : [ + "tcId": 197, + "comment": "Signature with special case values r=n - 1 and s=1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020101", + "result": "invalid" }, { - "tcId" : 198, - "comment" : "Signature with special case values r=n - 1 and s=-1", - "flags" : [ + "tcId": 198, + "comment": "Signature with special case values r=n - 1 and s=-1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641400201ff", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641400201ff", + "result": "invalid" }, { - "tcId" : 199, - "comment" : "Signature with special case values r=n - 1 and s=n", - "flags" : [ + "tcId": 199, + "comment": "Signature with special case values r=n - 1 and s=n", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result": "invalid" }, { - "tcId" : 200, - "comment" : "Signature with special case values r=n - 1 and s=n - 1", - "flags" : [ + "tcId": 200, + "comment": "Signature with special case values r=n - 1 and s=n - 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result": "invalid" }, { - "tcId" : 201, - "comment" : "Signature with special case values r=n - 1 and s=n + 1", - "flags" : [ + "tcId": 201, + "comment": "Signature with special case values r=n - 1 and s=n + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result": "invalid" }, { - "tcId" : 202, - "comment" : "Signature with special case values r=n - 1 and s=p", - "flags" : [ + "tcId": 202, + "comment": "Signature with special case values r=n - 1 and s=p", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result": "invalid" }, { - "tcId" : 203, - "comment" : "Signature with special case values r=n - 1 and s=p + 1", - "flags" : [ + "tcId": 203, + "comment": "Signature with special case values r=n - 1 and s=p + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result": "invalid" }, { - "tcId" : 204, - "comment" : "Signature with special case values r=n + 1 and s=0", - "flags" : [ + "tcId": 204, + "comment": "Signature with special case values r=n + 1 and s=0", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020100", + "result": "invalid" }, { - "tcId" : 205, - "comment" : "Signature with special case values r=n + 1 and s=1", - "flags" : [ + "tcId": 205, + "comment": "Signature with special case values r=n + 1 and s=1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020101", + "result": "invalid" }, { - "tcId" : 206, - "comment" : "Signature with special case values r=n + 1 and s=-1", - "flags" : [ + "tcId": 206, + "comment": "Signature with special case values r=n + 1 and s=-1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641420201ff", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641420201ff", + "result": "invalid" }, { - "tcId" : 207, - "comment" : "Signature with special case values r=n + 1 and s=n", - "flags" : [ + "tcId": 207, + "comment": "Signature with special case values r=n + 1 and s=n", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result": "invalid" }, { - "tcId" : 208, - "comment" : "Signature with special case values r=n + 1 and s=n - 1", - "flags" : [ + "tcId": 208, + "comment": "Signature with special case values r=n + 1 and s=n - 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result": "invalid" }, { - "tcId" : 209, - "comment" : "Signature with special case values r=n + 1 and s=n + 1", - "flags" : [ + "tcId": 209, + "comment": "Signature with special case values r=n + 1 and s=n + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result": "invalid" }, { - "tcId" : 210, - "comment" : "Signature with special case values r=n + 1 and s=p", - "flags" : [ + "tcId": 210, + "comment": "Signature with special case values r=n + 1 and s=p", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result": "invalid" }, { - "tcId" : 211, - "comment" : "Signature with special case values r=n + 1 and s=p + 1", - "flags" : [ + "tcId": 211, + "comment": "Signature with special case values r=n + 1 and s=p + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result": "invalid" }, { - "tcId" : 212, - "comment" : "Signature with special case values r=p and s=0", - "flags" : [ + "tcId": 212, + "comment": "Signature with special case values r=p and s=0", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020100", + "result": "invalid" }, { - "tcId" : 213, - "comment" : "Signature with special case values r=p and s=1", - "flags" : [ + "tcId": 213, + "comment": "Signature with special case values r=p and s=1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020101", + "result": "invalid" }, { - "tcId" : 214, - "comment" : "Signature with special case values r=p and s=-1", - "flags" : [ + "tcId": 214, + "comment": "Signature with special case values r=p and s=-1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0201ff", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0201ff", + "result": "invalid" }, { - "tcId" : 215, - "comment" : "Signature with special case values r=p and s=n", - "flags" : [ + "tcId": 215, + "comment": "Signature with special case values r=p and s=n", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result": "invalid" }, { - "tcId" : 216, - "comment" : "Signature with special case values r=p and s=n - 1", - "flags" : [ + "tcId": 216, + "comment": "Signature with special case values r=p and s=n - 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result": "invalid" }, { - "tcId" : 217, - "comment" : "Signature with special case values r=p and s=n + 1", - "flags" : [ + "tcId": 217, + "comment": "Signature with special case values r=p and s=n + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result": "invalid" }, { - "tcId" : 218, - "comment" : "Signature with special case values r=p and s=p", - "flags" : [ + "tcId": 218, + "comment": "Signature with special case values r=p and s=p", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result": "invalid" }, { - "tcId" : 219, - "comment" : "Signature with special case values r=p and s=p + 1", - "flags" : [ + "tcId": 219, + "comment": "Signature with special case values r=p and s=p + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result": "invalid" }, { - "tcId" : 220, - "comment" : "Signature with special case values r=p + 1 and s=0", - "flags" : [ + "tcId": 220, + "comment": "Signature with special case values r=p + 1 and s=0", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020100", + "result": "invalid" }, { - "tcId" : 221, - "comment" : "Signature with special case values r=p + 1 and s=1", - "flags" : [ + "tcId": 221, + "comment": "Signature with special case values r=p + 1 and s=1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020101", + "result": "invalid" }, { - "tcId" : 222, - "comment" : "Signature with special case values r=p + 1 and s=-1", - "flags" : [ + "tcId": 222, + "comment": "Signature with special case values r=p + 1 and s=-1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc300201ff", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc300201ff", + "result": "invalid" }, { - "tcId" : 223, - "comment" : "Signature with special case values r=p + 1 and s=n", - "flags" : [ + "tcId": 223, + "comment": "Signature with special case values r=p + 1 and s=n", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result": "invalid" }, { - "tcId" : 224, - "comment" : "Signature with special case values r=p + 1 and s=n - 1", - "flags" : [ + "tcId": 224, + "comment": "Signature with special case values r=p + 1 and s=n - 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result": "invalid" }, { - "tcId" : 225, - "comment" : "Signature with special case values r=p + 1 and s=n + 1", - "flags" : [ + "tcId": 225, + "comment": "Signature with special case values r=p + 1 and s=n + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result": "invalid" }, { - "tcId" : 226, - "comment" : "Signature with special case values r=p + 1 and s=p", - "flags" : [ + "tcId": 226, + "comment": "Signature with special case values r=p + 1 and s=p", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result": "invalid" }, { - "tcId" : 227, - "comment" : "Signature with special case values r=p + 1 and s=p + 1", - "flags" : [ + "tcId": 227, + "comment": "Signature with special case values r=p + 1 and s=p + 1", + "flags": [ "InvalidSignature" ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" + "msg": "313233343030", + "sig": "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result": "invalid" }, { - "tcId" : 228, - "comment" : "Signature encoding contains incorrect types: r=0, s=0.25", - "flags" : [ + "tcId": 228, + "comment": "Signature encoding contains incorrect types: r=0, s=0.25", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3008020100090380fe01", - "result" : "invalid" + "msg": "313233343030", + "sig": "3008020100090380fe01", + "result": "invalid" }, { - "tcId" : 229, - "comment" : "Signature encoding contains incorrect types: r=0, s=nan", - "flags" : [ + "tcId": 229, + "comment": "Signature encoding contains incorrect types: r=0, s=nan", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006020100090142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020100090142", + "result": "invalid" }, { - "tcId" : 230, - "comment" : "Signature encoding contains incorrect types: r=0, s=True", - "flags" : [ + "tcId": 230, + "comment": "Signature encoding contains incorrect types: r=0, s=True", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006020100010101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020100010101", + "result": "invalid" }, { - "tcId" : 231, - "comment" : "Signature encoding contains incorrect types: r=0, s=False", - "flags" : [ + "tcId": 231, + "comment": "Signature encoding contains incorrect types: r=0, s=False", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006020100010100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020100010100", + "result": "invalid" }, { - "tcId" : 232, - "comment" : "Signature encoding contains incorrect types: r=0, s=Null", - "flags" : [ + "tcId": 232, + "comment": "Signature encoding contains incorrect types: r=0, s=Null", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201000500", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201000500", + "result": "invalid" }, { - "tcId" : 233, - "comment" : "Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string", - "flags" : [ + "tcId": 233, + "comment": "Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201000c00", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201000c00", + "result": "invalid" }, { - "tcId" : 234, - "comment" : "Signature encoding contains incorrect types: r=0, s=\"0\"", - "flags" : [ + "tcId": 234, + "comment": "Signature encoding contains incorrect types: r=0, s=\"0\"", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30060201000c0130", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201000c0130", + "result": "invalid" }, { - "tcId" : 235, - "comment" : "Signature encoding contains incorrect types: r=0, s=empty list", - "flags" : [ + "tcId": 235, + "comment": "Signature encoding contains incorrect types: r=0, s=empty list", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201003000", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201003000", + "result": "invalid" }, { - "tcId" : 236, - "comment" : "Signature encoding contains incorrect types: r=0, s=list containing 0", - "flags" : [ + "tcId": 236, + "comment": "Signature encoding contains incorrect types: r=0, s=list containing 0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30080201003003020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30080201003003020100", + "result": "invalid" }, { - "tcId" : 237, - "comment" : "Signature encoding contains incorrect types: r=1, s=0.25", - "flags" : [ + "tcId": 237, + "comment": "Signature encoding contains incorrect types: r=1, s=0.25", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3008020101090380fe01", - "result" : "invalid" + "msg": "313233343030", + "sig": "3008020101090380fe01", + "result": "invalid" }, { - "tcId" : 238, - "comment" : "Signature encoding contains incorrect types: r=1, s=nan", - "flags" : [ + "tcId": 238, + "comment": "Signature encoding contains incorrect types: r=1, s=nan", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006020101090142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020101090142", + "result": "invalid" }, { - "tcId" : 239, - "comment" : "Signature encoding contains incorrect types: r=1, s=True", - "flags" : [ + "tcId": 239, + "comment": "Signature encoding contains incorrect types: r=1, s=True", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006020101010101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020101010101", + "result": "invalid" }, { - "tcId" : 240, - "comment" : "Signature encoding contains incorrect types: r=1, s=False", - "flags" : [ + "tcId": 240, + "comment": "Signature encoding contains incorrect types: r=1, s=False", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006020101010100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006020101010100", + "result": "invalid" }, { - "tcId" : 241, - "comment" : "Signature encoding contains incorrect types: r=1, s=Null", - "flags" : [ + "tcId": 241, + "comment": "Signature encoding contains incorrect types: r=1, s=Null", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201010500", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201010500", + "result": "invalid" }, { - "tcId" : 242, - "comment" : "Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string", - "flags" : [ + "tcId": 242, + "comment": "Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201010c00", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201010c00", + "result": "invalid" }, { - "tcId" : 243, - "comment" : "Signature encoding contains incorrect types: r=1, s=\"0\"", - "flags" : [ + "tcId": 243, + "comment": "Signature encoding contains incorrect types: r=1, s=\"0\"", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30060201010c0130", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201010c0130", + "result": "invalid" }, { - "tcId" : 244, - "comment" : "Signature encoding contains incorrect types: r=1, s=empty list", - "flags" : [ + "tcId": 244, + "comment": "Signature encoding contains incorrect types: r=1, s=empty list", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201013000", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201013000", + "result": "invalid" }, { - "tcId" : 245, - "comment" : "Signature encoding contains incorrect types: r=1, s=list containing 0", - "flags" : [ + "tcId": 245, + "comment": "Signature encoding contains incorrect types: r=1, s=list containing 0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30080201013003020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30080201013003020100", + "result": "invalid" }, { - "tcId" : 246, - "comment" : "Signature encoding contains incorrect types: r=-1, s=0.25", - "flags" : [ + "tcId": 246, + "comment": "Signature encoding contains incorrect types: r=-1, s=0.25", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30080201ff090380fe01", - "result" : "invalid" + "msg": "313233343030", + "sig": "30080201ff090380fe01", + "result": "invalid" }, { - "tcId" : 247, - "comment" : "Signature encoding contains incorrect types: r=-1, s=nan", - "flags" : [ + "tcId": 247, + "comment": "Signature encoding contains incorrect types: r=-1, s=nan", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30060201ff090142", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201ff090142", + "result": "invalid" }, { - "tcId" : 248, - "comment" : "Signature encoding contains incorrect types: r=-1, s=True", - "flags" : [ + "tcId": 248, + "comment": "Signature encoding contains incorrect types: r=-1, s=True", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30060201ff010101", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201ff010101", + "result": "invalid" }, { - "tcId" : 249, - "comment" : "Signature encoding contains incorrect types: r=-1, s=False", - "flags" : [ + "tcId": 249, + "comment": "Signature encoding contains incorrect types: r=-1, s=False", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30060201ff010100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201ff010100", + "result": "invalid" }, { - "tcId" : 250, - "comment" : "Signature encoding contains incorrect types: r=-1, s=Null", - "flags" : [ + "tcId": 250, + "comment": "Signature encoding contains incorrect types: r=-1, s=Null", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201ff0500", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201ff0500", + "result": "invalid" }, { - "tcId" : 251, - "comment" : "Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string", - "flags" : [ + "tcId": 251, + "comment": "Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201ff0c00", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201ff0c00", + "result": "invalid" }, { - "tcId" : 252, - "comment" : "Signature encoding contains incorrect types: r=-1, s=\"0\"", - "flags" : [ + "tcId": 252, + "comment": "Signature encoding contains incorrect types: r=-1, s=\"0\"", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30060201ff0c0130", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060201ff0c0130", + "result": "invalid" }, { - "tcId" : 253, - "comment" : "Signature encoding contains incorrect types: r=-1, s=empty list", - "flags" : [ + "tcId": 253, + "comment": "Signature encoding contains incorrect types: r=-1, s=empty list", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050201ff3000", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050201ff3000", + "result": "invalid" }, { - "tcId" : 254, - "comment" : "Signature encoding contains incorrect types: r=-1, s=list containing 0", - "flags" : [ + "tcId": 254, + "comment": "Signature encoding contains incorrect types: r=-1, s=list containing 0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30080201ff3003020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30080201ff3003020100", + "result": "invalid" }, { - "tcId" : 255, - "comment" : "Signature encoding contains incorrect types: r=n, s=0.25", - "flags" : [ + "tcId": 255, + "comment": "Signature encoding contains incorrect types: r=n, s=0.25", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090380fe01", - "result" : "invalid" + "msg": "313233343030", + "sig": "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090380fe01", + "result": "invalid" }, { - "tcId" : 256, - "comment" : "Signature encoding contains incorrect types: r=n, s=nan", - "flags" : [ + "tcId": 256, + "comment": "Signature encoding contains incorrect types: r=n, s=nan", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090142", + "result": "invalid" }, { - "tcId" : 257, - "comment" : "Signature encoding contains incorrect types: r=n, s=True", - "flags" : [ + "tcId": 257, + "comment": "Signature encoding contains incorrect types: r=n, s=True", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010101", + "result": "invalid" }, { - "tcId" : 258, - "comment" : "Signature encoding contains incorrect types: r=n, s=False", - "flags" : [ + "tcId": 258, + "comment": "Signature encoding contains incorrect types: r=n, s=False", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010100", + "result": "invalid" }, { - "tcId" : 259, - "comment" : "Signature encoding contains incorrect types: r=n, s=Null", - "flags" : [ + "tcId": 259, + "comment": "Signature encoding contains incorrect types: r=n, s=Null", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410500", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410500", + "result": "invalid" }, { - "tcId" : 260, - "comment" : "Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string", - "flags" : [ + "tcId": 260, + "comment": "Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c00", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c00", + "result": "invalid" }, { - "tcId" : 261, - "comment" : "Signature encoding contains incorrect types: r=n, s=\"0\"", - "flags" : [ + "tcId": 261, + "comment": "Signature encoding contains incorrect types: r=n, s=\"0\"", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c0130", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c0130", + "result": "invalid" }, { - "tcId" : 262, - "comment" : "Signature encoding contains incorrect types: r=n, s=empty list", - "flags" : [ + "tcId": 262, + "comment": "Signature encoding contains incorrect types: r=n, s=empty list", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413000", + "result": "invalid" }, { - "tcId" : 263, - "comment" : "Signature encoding contains incorrect types: r=n, s=list containing 0", - "flags" : [ + "tcId": 263, + "comment": "Signature encoding contains incorrect types: r=n, s=list containing 0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413003020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413003020100", + "result": "invalid" }, { - "tcId" : 264, - "comment" : "Signature encoding contains incorrect types: r=p, s=0.25", - "flags" : [ + "tcId": 264, + "comment": "Signature encoding contains incorrect types: r=p, s=0.25", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090380fe01", - "result" : "invalid" + "msg": "313233343030", + "sig": "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090380fe01", + "result": "invalid" }, { - "tcId" : 265, - "comment" : "Signature encoding contains incorrect types: r=p, s=nan", - "flags" : [ + "tcId": 265, + "comment": "Signature encoding contains incorrect types: r=p, s=nan", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090142", + "result": "invalid" }, { - "tcId" : 266, - "comment" : "Signature encoding contains incorrect types: r=p, s=True", - "flags" : [ + "tcId": 266, + "comment": "Signature encoding contains incorrect types: r=p, s=True", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010101", + "result": "invalid" }, { - "tcId" : 267, - "comment" : "Signature encoding contains incorrect types: r=p, s=False", - "flags" : [ + "tcId": 267, + "comment": "Signature encoding contains incorrect types: r=p, s=False", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010100", + "result": "invalid" }, { - "tcId" : 268, - "comment" : "Signature encoding contains incorrect types: r=p, s=Null", - "flags" : [ + "tcId": 268, + "comment": "Signature encoding contains incorrect types: r=p, s=Null", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0500", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0500", + "result": "invalid" }, { - "tcId" : 269, - "comment" : "Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string", - "flags" : [ + "tcId": 269, + "comment": "Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c00", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c00", + "result": "invalid" }, { - "tcId" : 270, - "comment" : "Signature encoding contains incorrect types: r=p, s=\"0\"", - "flags" : [ + "tcId": 270, + "comment": "Signature encoding contains incorrect types: r=p, s=\"0\"", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c0130", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c0130", + "result": "invalid" }, { - "tcId" : 271, - "comment" : "Signature encoding contains incorrect types: r=p, s=empty list", - "flags" : [ + "tcId": 271, + "comment": "Signature encoding contains incorrect types: r=p, s=empty list", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3000", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3000", + "result": "invalid" }, { - "tcId" : 272, - "comment" : "Signature encoding contains incorrect types: r=p, s=list containing 0", - "flags" : [ + "tcId": 272, + "comment": "Signature encoding contains incorrect types: r=p, s=list containing 0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3003020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3003020100", + "result": "invalid" }, { - "tcId" : 273, - "comment" : "Signature encoding contains incorrect types: r=0.25, s=0.25", - "flags" : [ + "tcId": 273, + "comment": "Signature encoding contains incorrect types: r=0.25, s=0.25", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "300a090380fe01090380fe01", - "result" : "invalid" + "msg": "313233343030", + "sig": "300a090380fe01090380fe01", + "result": "invalid" }, { - "tcId" : 274, - "comment" : "Signature encoding contains incorrect types: r=nan, s=nan", - "flags" : [ + "tcId": 274, + "comment": "Signature encoding contains incorrect types: r=nan, s=nan", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006090142090142", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006090142090142", + "result": "invalid" }, { - "tcId" : 275, - "comment" : "Signature encoding contains incorrect types: r=True, s=True", - "flags" : [ + "tcId": 275, + "comment": "Signature encoding contains incorrect types: r=True, s=True", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006010101010101", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006010101010101", + "result": "invalid" }, { - "tcId" : 276, - "comment" : "Signature encoding contains incorrect types: r=False, s=False", - "flags" : [ + "tcId": 276, + "comment": "Signature encoding contains incorrect types: r=False, s=False", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006010100010100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006010100010100", + "result": "invalid" }, { - "tcId" : 277, - "comment" : "Signature encoding contains incorrect types: r=Null, s=Null", - "flags" : [ + "tcId": 277, + "comment": "Signature encoding contains incorrect types: r=Null, s=Null", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "300405000500", - "result" : "invalid" + "msg": "313233343030", + "sig": "300405000500", + "result": "invalid" }, { - "tcId" : 278, - "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string", - "flags" : [ + "tcId": 278, + "comment": "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30040c000c00", - "result" : "invalid" + "msg": "313233343030", + "sig": "30040c000c00", + "result": "invalid" }, { - "tcId" : 279, - "comment" : "Signature encoding contains incorrect types: r=\"0\", s=\"0\"", - "flags" : [ + "tcId": 279, + "comment": "Signature encoding contains incorrect types: r=\"0\", s=\"0\"", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30060c01300c0130", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060c01300c0130", + "result": "invalid" }, { - "tcId" : 280, - "comment" : "Signature encoding contains incorrect types: r=empty list, s=empty list", - "flags" : [ + "tcId": 280, + "comment": "Signature encoding contains incorrect types: r=empty list, s=empty list", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "300430003000", - "result" : "invalid" + "msg": "313233343030", + "sig": "300430003000", + "result": "invalid" }, { - "tcId" : 281, - "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=list containing 0", - "flags" : [ + "tcId": 281, + "comment": "Signature encoding contains incorrect types: r=list containing 0, s=list containing 0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "300a30030201003003020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "300a30030201003003020100", + "result": "invalid" }, { - "tcId" : 282, - "comment" : "Signature encoding contains incorrect types: r=0.25, s=0", - "flags" : [ + "tcId": 282, + "comment": "Signature encoding contains incorrect types: r=0.25, s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3008090380fe01020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3008090380fe01020100", + "result": "invalid" }, { - "tcId" : 283, - "comment" : "Signature encoding contains incorrect types: r=nan, s=0", - "flags" : [ + "tcId": 283, + "comment": "Signature encoding contains incorrect types: r=nan, s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006090142020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006090142020100", + "result": "invalid" }, { - "tcId" : 284, - "comment" : "Signature encoding contains incorrect types: r=True, s=0", - "flags" : [ + "tcId": 284, + "comment": "Signature encoding contains incorrect types: r=True, s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006010101020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006010101020100", + "result": "invalid" }, { - "tcId" : 285, - "comment" : "Signature encoding contains incorrect types: r=False, s=0", - "flags" : [ + "tcId": 285, + "comment": "Signature encoding contains incorrect types: r=False, s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "3006010100020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3006010100020100", + "result": "invalid" }, { - "tcId" : 286, - "comment" : "Signature encoding contains incorrect types: r=Null, s=0", - "flags" : [ + "tcId": 286, + "comment": "Signature encoding contains incorrect types: r=Null, s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050500020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050500020100", + "result": "invalid" }, { - "tcId" : 287, - "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0", - "flags" : [ + "tcId": 287, + "comment": "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30050c00020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30050c00020100", + "result": "invalid" }, { - "tcId" : 288, - "comment" : "Signature encoding contains incorrect types: r=\"0\", s=0", - "flags" : [ + "tcId": 288, + "comment": "Signature encoding contains incorrect types: r=\"0\", s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30060c0130020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30060c0130020100", + "result": "invalid" }, { - "tcId" : 289, - "comment" : "Signature encoding contains incorrect types: r=empty list, s=0", - "flags" : [ + "tcId": 289, + "comment": "Signature encoding contains incorrect types: r=empty list, s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30053000020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30053000020100", + "result": "invalid" }, { - "tcId" : 290, - "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=0", - "flags" : [ + "tcId": 290, + "comment": "Signature encoding contains incorrect types: r=list containing 0, s=0", + "flags": [ "InvalidTypesInSignature" ], - "msg" : "313233343030", - "sig" : "30083003020100020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "30083003020100020100", + "result": "invalid" }, { - "tcId" : 291, - "comment" : "Edge case for Shamir multiplication", - "flags" : [ + "tcId": 291, + "comment": "Edge case for Shamir multiplication", + "flags": [ "EdgeCaseShamirMultiplication" ], - "msg" : "3235353835", - "sig" : "3045022100dd1b7d09a7bd8218961034a39a87fecf5314f00c4d25eb58a07ac85e85eab516022035138c401ef8d3493d65c9002fe62b43aee568731b744548358996d9cc427e06", - "result" : "valid" + "msg": "3235353835", + "sig": "3045022100dd1b7d09a7bd8218961034a39a87fecf5314f00c4d25eb58a07ac85e85eab516022035138c401ef8d3493d65c9002fe62b43aee568731b744548358996d9cc427e06", + "result": "valid" }, { - "tcId" : 292, - "comment" : "special case hash", - "flags" : [ + "tcId": 292, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "343236343739373234", - "sig" : "304502210095c29267d972a043d955224546222bba343fc1d4db0fec262a33ac61305696ae02206edfe96713aed56f8a28a6653f57e0b829712e5eddc67f34682b24f0676b2640", - "result" : "valid" + "msg": "343236343739373234", + "sig": "304502210095c29267d972a043d955224546222bba343fc1d4db0fec262a33ac61305696ae02206edfe96713aed56f8a28a6653f57e0b829712e5eddc67f34682b24f0676b2640", + "result": "valid" }, { - "tcId" : 293, - "comment" : "special case hash", - "flags" : [ + "tcId": 293, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "37313338363834383931", - "sig" : "3044022028f94a894e92024699e345fe66971e3edcd050023386135ab3939d550898fb25022032963e5bd41fa5911ed8f37deb86dae0a762bb6121c894615083c5d95ea01db3", - "result" : "valid" + "msg": "37313338363834383931", + "sig": "3044022028f94a894e92024699e345fe66971e3edcd050023386135ab3939d550898fb25022032963e5bd41fa5911ed8f37deb86dae0a762bb6121c894615083c5d95ea01db3", + "result": "valid" }, { - "tcId" : 294, - "comment" : "special case hash", - "flags" : [ + "tcId": 294, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "3130333539333331363638", - "sig" : "3045022100be26b18f9549f89f411a9b52536b15aa270b84548d0e859a1952a27af1a77ac6022070c1d4fa9cd03cc8eaa8d506edb97eed7b8358b453c88aefbb880a3f0e8d472f", - "result" : "valid" + "msg": "3130333539333331363638", + "sig": "3045022100be26b18f9549f89f411a9b52536b15aa270b84548d0e859a1952a27af1a77ac6022070c1d4fa9cd03cc8eaa8d506edb97eed7b8358b453c88aefbb880a3f0e8d472f", + "result": "valid" }, { - "tcId" : 295, - "comment" : "special case hash", - "flags" : [ + "tcId": 295, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33393439343031323135", - "sig" : "3045022100b1a4b1478e65cc3eafdf225d1298b43f2da19e4bcff7eacc0a2e98cd4b74b1140220179aa31e304cc142cf5073171751b28f3f5e0fa88c994e7c55f1bc07b8d56c16", - "result" : "valid" + "msg": "33393439343031323135", + "sig": "3045022100b1a4b1478e65cc3eafdf225d1298b43f2da19e4bcff7eacc0a2e98cd4b74b1140220179aa31e304cc142cf5073171751b28f3f5e0fa88c994e7c55f1bc07b8d56c16", + "result": "valid" }, { - "tcId" : 296, - "comment" : "special case hash", - "flags" : [ + "tcId": 296, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31333434323933303739", - "sig" : "30440220325332021261f1bd18f2712aa1e2252da23796da8a4b1ff6ea18cafec7e171f2022040b4f5e287ee61fc3c804186982360891eaa35c75f05a43ecd48b35d984a6648", - "result" : "valid" + "msg": "31333434323933303739", + "sig": "30440220325332021261f1bd18f2712aa1e2252da23796da8a4b1ff6ea18cafec7e171f2022040b4f5e287ee61fc3c804186982360891eaa35c75f05a43ecd48b35d984a6648", + "result": "valid" }, { - "tcId" : 297, - "comment" : "special case hash", - "flags" : [ + "tcId": 297, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33373036323131373132", - "sig" : "3045022100a23ad18d8fc66d81af0903890cbd453a554cb04cdc1a8ca7f7f78e5367ed88a0022023e3eb2ce1c04ea748c389bd97374aa9413b9268851c04dcd9f88e78813fee56", - "result" : "valid" + "msg": "33373036323131373132", + "sig": "3045022100a23ad18d8fc66d81af0903890cbd453a554cb04cdc1a8ca7f7f78e5367ed88a0022023e3eb2ce1c04ea748c389bd97374aa9413b9268851c04dcd9f88e78813fee56", + "result": "valid" }, { - "tcId" : 298, - "comment" : "special case hash", - "flags" : [ + "tcId": 298, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "333433363838373132", - "sig" : "304402202bdea41cda63a2d14bf47353bd20880a690901de7cd6e3cc6d8ed5ba0cdb109102203cea66bccfc9f9bf8c7ca4e1c1457cc9145e13e936d90b3d9c7786b8b26cf4c7", - "result" : "valid" + "msg": "333433363838373132", + "sig": "304402202bdea41cda63a2d14bf47353bd20880a690901de7cd6e3cc6d8ed5ba0cdb109102203cea66bccfc9f9bf8c7ca4e1c1457cc9145e13e936d90b3d9c7786b8b26cf4c7", + "result": "valid" }, { - "tcId" : 299, - "comment" : "special case hash", - "flags" : [ + "tcId": 299, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31333531353330333730", - "sig" : "3045022100d7cd76ec01c1b1079eba9e2aa2a397243c4758c98a1ba0b7404a340b9b00ced602203575001e19d922e6de8b3d6c84ea43b5c3338106cf29990134e7669a826f78e6", - "result" : "valid" + "msg": "31333531353330333730", + "sig": "3045022100d7cd76ec01c1b1079eba9e2aa2a397243c4758c98a1ba0b7404a340b9b00ced602203575001e19d922e6de8b3d6c84ea43b5c3338106cf29990134e7669a826f78e6", + "result": "valid" }, { - "tcId" : 300, - "comment" : "special case hash", - "flags" : [ + "tcId": 300, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "36353533323033313236", - "sig" : "3045022100a872c744d936db21a10c361dd5c9063355f84902219652f6fc56dc95a7139d960220400df7575d9756210e9ccc77162c6b593c7746cfb48ac263c42750b421ef4bb9", - "result" : "valid" + "msg": "36353533323033313236", + "sig": "3045022100a872c744d936db21a10c361dd5c9063355f84902219652f6fc56dc95a7139d960220400df7575d9756210e9ccc77162c6b593c7746cfb48ac263c42750b421ef4bb9", + "result": "valid" }, { - "tcId" : 301, - "comment" : "special case hash", - "flags" : [ + "tcId": 301, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31353634333436363033", - "sig" : "30450221009fa9afe07752da10b36d3afcd0fe44bfc40244d75203599cf8f5047fa3453854022050e0a7c013bfbf51819736972d44b4b56bc2a2b2c180df6ec672df171410d77a", - "result" : "valid" + "msg": "31353634333436363033", + "sig": "30450221009fa9afe07752da10b36d3afcd0fe44bfc40244d75203599cf8f5047fa3453854022050e0a7c013bfbf51819736972d44b4b56bc2a2b2c180df6ec672df171410d77a", + "result": "valid" }, { - "tcId" : 302, - "comment" : "special case hash", - "flags" : [ + "tcId": 302, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "34343239353339313137", - "sig" : "3045022100885640384d0d910efb177b46be6c3dc5cac81f0b88c3190bb6b5f99c2641f2050220738ed9bff116306d9caa0f8fc608be243e0b567779d8dab03e8e19d553f1dc8e", - "result" : "valid" + "msg": "34343239353339313137", + "sig": "3045022100885640384d0d910efb177b46be6c3dc5cac81f0b88c3190bb6b5f99c2641f2050220738ed9bff116306d9caa0f8fc608be243e0b567779d8dab03e8e19d553f1dc8e", + "result": "valid" }, { - "tcId" : 303, - "comment" : "special case hash", - "flags" : [ + "tcId": 303, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "3130393533323631333531", - "sig" : "304402202d051f91c5a9d440c5676985710483bc4f1a6c611b10c95a2ff0363d90c2a45802206ddf94e6fba5be586833d0c53cf216ad3948f37953c26c1cf4968e9a9e8243dc", - "result" : "valid" + "msg": "3130393533323631333531", + "sig": "304402202d051f91c5a9d440c5676985710483bc4f1a6c611b10c95a2ff0363d90c2a45802206ddf94e6fba5be586833d0c53cf216ad3948f37953c26c1cf4968e9a9e8243dc", + "result": "valid" }, { - "tcId" : 304, - "comment" : "special case hash", - "flags" : [ + "tcId": 304, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "35393837333530303431", - "sig" : "3045022100f3ac2523967482f53d508522712d583f4379cd824101ff635ea0935117baa54f022027f10812227397e02cea96fb0e680761636dab2b080d1fc5d11685cbe8500cfe", - "result" : "valid" + "msg": "35393837333530303431", + "sig": "3045022100f3ac2523967482f53d508522712d583f4379cd824101ff635ea0935117baa54f022027f10812227397e02cea96fb0e680761636dab2b080d1fc5d11685cbe8500cfe", + "result": "valid" }, { - "tcId" : 305, - "comment" : "special case hash", - "flags" : [ + "tcId": 305, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33343633303036383738", - "sig" : "304502210096447cf68c3ab7266ed7447de3ac52fed7cc08cbdfea391c18a9b8ab370bc91302200f5e7874d3ac0e918f01c885a1639177c923f8660d1ceba1ca1f301bc675cdbc", - "result" : "valid" + "msg": "33343633303036383738", + "sig": "304502210096447cf68c3ab7266ed7447de3ac52fed7cc08cbdfea391c18a9b8ab370bc91302200f5e7874d3ac0e918f01c885a1639177c923f8660d1ceba1ca1f301bc675cdbc", + "result": "valid" }, { - "tcId" : 306, - "comment" : "special case hash", - "flags" : [ + "tcId": 306, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "39383137333230323837", - "sig" : "30440220530a0832b691da0b5619a0b11de6877f3c0971baaa68ed122758c29caaf46b7202206c89e44f5eb33060ea4b46318c39138eaedec72de42ba576579a6a4690e339f3", - "result" : "valid" + "msg": "39383137333230323837", + "sig": "30440220530a0832b691da0b5619a0b11de6877f3c0971baaa68ed122758c29caaf46b7202206c89e44f5eb33060ea4b46318c39138eaedec72de42ba576579a6a4690e339f3", + "result": "valid" }, { - "tcId" : 307, - "comment" : "special case hash", - "flags" : [ + "tcId": 307, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33323232303431303436", - "sig" : "30450221009c54c25500bde0b92d72d6ec483dc2482f3654294ca74de796b681255ed58a770220677453c6b56f527631c9f67b3f3eb621fd88582b4aff156d2f1567d6211a2a33", - "result" : "valid" + "msg": "33323232303431303436", + "sig": "30450221009c54c25500bde0b92d72d6ec483dc2482f3654294ca74de796b681255ed58a770220677453c6b56f527631c9f67b3f3eb621fd88582b4aff156d2f1567d6211a2a33", + "result": "valid" }, { - "tcId" : 308, - "comment" : "special case hash", - "flags" : [ + "tcId": 308, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "36363636333037313034", - "sig" : "3045022100e7909d41439e2f6af29136c7348ca2641a2b070d5b64f91ea9da7070c7a2618b022042d782f132fa1d36c2c88ba27c3d678d80184a5d1eccac7501f0b47e3d205008", - "result" : "valid" + "msg": "36363636333037313034", + "sig": "3045022100e7909d41439e2f6af29136c7348ca2641a2b070d5b64f91ea9da7070c7a2618b022042d782f132fa1d36c2c88ba27c3d678d80184a5d1eccac7501f0b47e3d205008", + "result": "valid" }, { - "tcId" : 309, - "comment" : "special case hash", - "flags" : [ + "tcId": 309, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31303335393531383938", - "sig" : "304402205924873209593135a4c3da7bb381227f8a4b6aa9f34fe5bb7f8fbc131a039ffe02201f1bb11b441c8feaa40f44213d9a405ed792d59fb49d5bcdd9a4285ae5693022", - "result" : "valid" + "msg": "31303335393531383938", + "sig": "304402205924873209593135a4c3da7bb381227f8a4b6aa9f34fe5bb7f8fbc131a039ffe02201f1bb11b441c8feaa40f44213d9a405ed792d59fb49d5bcdd9a4285ae5693022", + "result": "valid" }, { - "tcId" : 310, - "comment" : "special case hash", - "flags" : [ + "tcId": 310, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31383436353937313935", - "sig" : "3045022100eeb692c9b262969b231c38b5a7f60649e0c875cd64df88f33aa571fa3d29ab0e0220218b3a1eb06379c2c18cf51b06430786d1c64cd2d24c9b232b23e5bac7989acd", - "result" : "valid" + "msg": "31383436353937313935", + "sig": "3045022100eeb692c9b262969b231c38b5a7f60649e0c875cd64df88f33aa571fa3d29ab0e0220218b3a1eb06379c2c18cf51b06430786d1c64cd2d24c9b232b23e5bac7989acd", + "result": "valid" }, { - "tcId" : 311, - "comment" : "special case hash", - "flags" : [ + "tcId": 311, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33313336303436313839", - "sig" : "3045022100a40034177f36091c2b653684a0e3eb5d4bff18e4d09f664c2800e7cafda1daf802203a3ec29853704e52031c58927a800a968353adc3d973beba9172cbbeab4dd149", - "result" : "valid" + "msg": "33313336303436313839", + "sig": "3045022100a40034177f36091c2b653684a0e3eb5d4bff18e4d09f664c2800e7cafda1daf802203a3ec29853704e52031c58927a800a968353adc3d973beba9172cbbeab4dd149", + "result": "valid" }, { - "tcId" : 312, - "comment" : "special case hash", - "flags" : [ + "tcId": 312, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "32363633373834323534", - "sig" : "3045022100b5d795cc75cea5c434fa4185180cd6bd21223f3d5a86da6670d71d95680dadbf022054e4d8810a001ecbb9f7ca1c2ebfdb9d009e9031a431aca3c20ab4e0d1374ec1", - "result" : "valid" + "msg": "32363633373834323534", + "sig": "3045022100b5d795cc75cea5c434fa4185180cd6bd21223f3d5a86da6670d71d95680dadbf022054e4d8810a001ecbb9f7ca1c2ebfdb9d009e9031a431aca3c20ab4e0d1374ec1", + "result": "valid" }, { - "tcId" : 313, - "comment" : "special case hash", - "flags" : [ + "tcId": 313, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31363532313030353234", - "sig" : "3044022007dc2478d43c1232a4595608c64426c35510051a631ae6a5a6eb1161e57e42e102204a59ea0fdb72d12165cea3bf1ca86ba97517bd188db3dbd21a5a157850021984", - "result" : "valid" + "msg": "31363532313030353234", + "sig": "3044022007dc2478d43c1232a4595608c64426c35510051a631ae6a5a6eb1161e57e42e102204a59ea0fdb72d12165cea3bf1ca86ba97517bd188db3dbd21a5a157850021984", + "result": "valid" }, { - "tcId" : 314, - "comment" : "special case hash", - "flags" : [ + "tcId": 314, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "35373438303831363936", - "sig" : "3045022100ddd20c4a05596ca868b558839fce9f6511ddd83d1ccb53f82e5269d559a0155202205b91734729d93093ff22123c4a25819d7feb66a250663fc780cb66fc7b6e6d17", - "result" : "valid" + "msg": "35373438303831363936", + "sig": "3045022100ddd20c4a05596ca868b558839fce9f6511ddd83d1ccb53f82e5269d559a0155202205b91734729d93093ff22123c4a25819d7feb66a250663fc780cb66fc7b6e6d17", + "result": "valid" }, { - "tcId" : 315, - "comment" : "special case hash", - "flags" : [ + "tcId": 315, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "36333433393133343638", - "sig" : "30450221009cde6e0ede0a003f02fda0a01b59facfe5dec063318f279ce2de7a9b1062f7b702202886a5b8c679bdf8224c66f908fd6205492cb70b0068d46ae4f33a4149b12a52", - "result" : "valid" + "msg": "36333433393133343638", + "sig": "30450221009cde6e0ede0a003f02fda0a01b59facfe5dec063318f279ce2de7a9b1062f7b702202886a5b8c679bdf8224c66f908fd6205492cb70b0068d46ae4f33a4149b12a52", + "result": "valid" }, { - "tcId" : 316, - "comment" : "special case hash", - "flags" : [ + "tcId": 316, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31353431313033353938", - "sig" : "3045022100c5771016d0dd6357143c89f684cd740423502554c0c59aa8c99584f1ff38f609022054b405f4477546686e464c5463b4fd4190572e58d0f7e7357f6e61947d20715c", - "result" : "valid" + "msg": "31353431313033353938", + "sig": "3045022100c5771016d0dd6357143c89f684cd740423502554c0c59aa8c99584f1ff38f609022054b405f4477546686e464c5463b4fd4190572e58d0f7e7357f6e61947d20715c", + "result": "valid" }, { - "tcId" : 317, - "comment" : "special case hash", - "flags" : [ + "tcId": 317, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "3130343738353830313238", - "sig" : "3045022100a24ebc0ec224bd67ae397cbe6fa37b3125adbd34891abe2d7c7356921916dfe6022034f6eb6374731bbbafc4924fb8b0bdcdda49456d724cdae6178d87014cb53d8c", - "result" : "valid" + "msg": "3130343738353830313238", + "sig": "3045022100a24ebc0ec224bd67ae397cbe6fa37b3125adbd34891abe2d7c7356921916dfe6022034f6eb6374731bbbafc4924fb8b0bdcdda49456d724cdae6178d87014cb53d8c", + "result": "valid" }, { - "tcId" : 318, - "comment" : "special case hash", - "flags" : [ + "tcId": 318, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "3130353336323835353638", - "sig" : "304402202557d64a7aee2e0931c012e4fea1cd3a2c334edae68cdeb7158caf21b68e5a2402207f06cdbb6a90023a973882ed97b080fe6b05af3ec93db6f1a4399a69edf7670d", - "result" : "valid" + "msg": "3130353336323835353638", + "sig": "304402202557d64a7aee2e0931c012e4fea1cd3a2c334edae68cdeb7158caf21b68e5a2402207f06cdbb6a90023a973882ed97b080fe6b05af3ec93db6f1a4399a69edf7670d", + "result": "valid" }, { - "tcId" : 319, - "comment" : "special case hash", - "flags" : [ + "tcId": 319, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "393533393034313035", - "sig" : "3045022100c4f2eccbb6a24350c8466450b9d61b207ee359e037b3dcedb42a3f2e6dd6aeb502203263c6b59a2f55cdd1c6e14894d5e5963b28bc3e2469ac9ba1197991ca7ff9c7", - "result" : "valid" + "msg": "393533393034313035", + "sig": "3045022100c4f2eccbb6a24350c8466450b9d61b207ee359e037b3dcedb42a3f2e6dd6aeb502203263c6b59a2f55cdd1c6e14894d5e5963b28bc3e2469ac9ba1197991ca7ff9c7", + "result": "valid" }, { - "tcId" : 320, - "comment" : "special case hash", - "flags" : [ + "tcId": 320, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "393738383438303339", - "sig" : "3045022100eff04781c9cbcd162d0a25a6e2ebcca43506c523385cb515d49ea38a1b12fcad022015acd73194c91a95478534f23015b672ebed213e45424dd2c8e26ac8b3eb34a5", - "result" : "valid" + "msg": "393738383438303339", + "sig": "3045022100eff04781c9cbcd162d0a25a6e2ebcca43506c523385cb515d49ea38a1b12fcad022015acd73194c91a95478534f23015b672ebed213e45424dd2c8e26ac8b3eb34a5", + "result": "valid" }, { - "tcId" : 321, - "comment" : "special case hash", - "flags" : [ + "tcId": 321, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33363130363732343432", - "sig" : "3045022100f58b4e3110a64bf1b5db97639ee0e5a9c8dfa49dc59b679891f520fdf0584c8702202cd8fe51888aee9db3e075440fd4db73b5c732fb87b510e97093d66415f62af7", - "result" : "valid" + "msg": "33363130363732343432", + "sig": "3045022100f58b4e3110a64bf1b5db97639ee0e5a9c8dfa49dc59b679891f520fdf0584c8702202cd8fe51888aee9db3e075440fd4db73b5c732fb87b510e97093d66415f62af7", + "result": "valid" }, { - "tcId" : 322, - "comment" : "special case hash", - "flags" : [ + "tcId": 322, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31303534323430373035", - "sig" : "3045022100f8abecaa4f0c502de4bf5903d48417f786bf92e8ad72fec0bd7fcb7800c0bbe302204c7f9e231076a30b7ae36b0cebe69ccef1cd194f7cce93a5588fd6814f437c0e", - "result" : "valid" + "msg": "31303534323430373035", + "sig": "3045022100f8abecaa4f0c502de4bf5903d48417f786bf92e8ad72fec0bd7fcb7800c0bbe302204c7f9e231076a30b7ae36b0cebe69ccef1cd194f7cce93a5588fd6814f437c0e", + "result": "valid" }, { - "tcId" : 323, - "comment" : "special case hash", - "flags" : [ + "tcId": 323, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "35313734343438313937", - "sig" : "304402205d5b38bd37ad498b2227a633268a8cca879a5c7c94a4e416bd0a614d09e606d2022012b8d664ea9991062ecbb834e58400e25c46007af84f6007d7f1685443269afe", - "result" : "valid" + "msg": "35313734343438313937", + "sig": "304402205d5b38bd37ad498b2227a633268a8cca879a5c7c94a4e416bd0a614d09e606d2022012b8d664ea9991062ecbb834e58400e25c46007af84f6007d7f1685443269afe", + "result": "valid" }, { - "tcId" : 324, - "comment" : "special case hash", - "flags" : [ + "tcId": 324, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31393637353631323531", - "sig" : "304402200c1cd9fe4034f086a2b52d65b9d3834d72aebe7f33dfe8f976da82648177d8e3022013105782e3d0cfe85c2778dec1a848b27ac0ae071aa6da341a9553a946b41e59", - "result" : "valid" + "msg": "31393637353631323531", + "sig": "304402200c1cd9fe4034f086a2b52d65b9d3834d72aebe7f33dfe8f976da82648177d8e3022013105782e3d0cfe85c2778dec1a848b27ac0ae071aa6da341a9553a946b41e59", + "result": "valid" }, { - "tcId" : 325, - "comment" : "special case hash", - "flags" : [ + "tcId": 325, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33343437323533333433", - "sig" : "3045022100ae7935fb96ff246b7b5d5662870d1ba587b03d6e1360baf47988b5c02ccc1a5b02205f00c323272083782d4a59f2dfd65e49de0693627016900ef7e61428056664b3", - "result" : "valid" + "msg": "33343437323533333433", + "sig": "3045022100ae7935fb96ff246b7b5d5662870d1ba587b03d6e1360baf47988b5c02ccc1a5b02205f00c323272083782d4a59f2dfd65e49de0693627016900ef7e61428056664b3", + "result": "valid" }, { - "tcId" : 326, - "comment" : "special case hash", - "flags" : [ + "tcId": 326, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "333638323634333138", - "sig" : "3044022000a134b5c6ccbcefd4c882b945baeb4933444172795fa6796aae1490675470980220566e46105d24d890151e3eea3ebf88f5b92b3f5ec93a217765a6dcbd94f2c55b", - "result" : "valid" + "msg": "333638323634333138", + "sig": "3044022000a134b5c6ccbcefd4c882b945baeb4933444172795fa6796aae1490675470980220566e46105d24d890151e3eea3ebf88f5b92b3f5ec93a217765a6dcbd94f2c55b", + "result": "valid" }, { - "tcId" : 327, - "comment" : "special case hash", - "flags" : [ + "tcId": 327, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33323631313938363038", - "sig" : "304402202e4721363ad3992c139e5a1c26395d2c2d777824aa24fde075e0d7381171309d0220740f7c494418e1300dd4512f782a58800bff6a7abdfdd20fbbd4f05515ca1a4f", - "result" : "valid" + "msg": "33323631313938363038", + "sig": "304402202e4721363ad3992c139e5a1c26395d2c2d777824aa24fde075e0d7381171309d0220740f7c494418e1300dd4512f782a58800bff6a7abdfdd20fbbd4f05515ca1a4f", + "result": "valid" }, { - "tcId" : 328, - "comment" : "special case hash", - "flags" : [ + "tcId": 328, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "39363738373831303934", - "sig" : "304402206852e9d3cd9fe373c2d504877967d365ab1456707b6817a042864694e1960ccf0220064b27ea142b30887b84c86adccb2fa39a6911ad21fc7e819f593be52bc4f3bd", - "result" : "valid" + "msg": "39363738373831303934", + "sig": "304402206852e9d3cd9fe373c2d504877967d365ab1456707b6817a042864694e1960ccf0220064b27ea142b30887b84c86adccb2fa39a6911ad21fc7e819f593be52bc4f3bd", + "result": "valid" }, { - "tcId" : 329, - "comment" : "special case hash", - "flags" : [ + "tcId": 329, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "34393538383233383233", - "sig" : "30440220188a8c5648dc79eace158cf886c62b5468f05fd95f03a7635c5b4c31f09af4c5022036361a0b571a00c6cd5e686ccbfcfa703c4f97e48938346d0c103fdc76dc5867", - "result" : "valid" + "msg": "34393538383233383233", + "sig": "30440220188a8c5648dc79eace158cf886c62b5468f05fd95f03a7635c5b4c31f09af4c5022036361a0b571a00c6cd5e686ccbfcfa703c4f97e48938346d0c103fdc76dc5867", + "result": "valid" }, { - "tcId" : 330, - "comment" : "special case hash", - "flags" : [ + "tcId": 330, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "383234363337383337", - "sig" : "3045022100a74f1fb9a8263f62fc4416a5b7d584f4206f3996bb91f6fc8e73b9e92bad0e1302206815032e8c7d76c3ab06a86f33249ce9940148cb36d1f417c2e992e801afa3fa", - "result" : "valid" + "msg": "383234363337383337", + "sig": "3045022100a74f1fb9a8263f62fc4416a5b7d584f4206f3996bb91f6fc8e73b9e92bad0e1302206815032e8c7d76c3ab06a86f33249ce9940148cb36d1f417c2e992e801afa3fa", + "result": "valid" }, { - "tcId" : 331, - "comment" : "special case hash", - "flags" : [ + "tcId": 331, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "3131303230383333373736", - "sig" : "3044022007244865b72ff37e62e3146f0dc14682badd7197799135f0b00ade7671742bfe02200d80c2238edb4e4a7a86a8c57ca9af1711f406f7f5da0299aa04e2932d960754", - "result" : "valid" + "msg": "3131303230383333373736", + "sig": "3044022007244865b72ff37e62e3146f0dc14682badd7197799135f0b00ade7671742bfe02200d80c2238edb4e4a7a86a8c57ca9af1711f406f7f5da0299aa04e2932d960754", + "result": "valid" }, { - "tcId" : 332, - "comment" : "special case hash", - "flags" : [ + "tcId": 332, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "313333383731363438", - "sig" : "3045022100da7fdd05b5badabd619d805c4ee7d9a84f84ddd5cf9c5bf4d4338140d689ef08022028f1cf4fa1c3c5862cfa149c0013cf5fe6cf5076cae000511063e7de25bb38e5", - "result" : "valid" + "msg": "313333383731363438", + "sig": "3045022100da7fdd05b5badabd619d805c4ee7d9a84f84ddd5cf9c5bf4d4338140d689ef08022028f1cf4fa1c3c5862cfa149c0013cf5fe6cf5076cae000511063e7de25bb38e5", + "result": "valid" }, { - "tcId" : 333, - "comment" : "special case hash", - "flags" : [ + "tcId": 333, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "333232313434313632", - "sig" : "3045022100d3027c656f6d4fdfd8ede22093e3c303b0133c340d615e7756f6253aea927238022009aef060c8e4cef972974011558df144fed25ca69ae8d0b2eaf1a8feefbec417", - "result" : "valid" + "msg": "333232313434313632", + "sig": "3045022100d3027c656f6d4fdfd8ede22093e3c303b0133c340d615e7756f6253aea927238022009aef060c8e4cef972974011558df144fed25ca69ae8d0b2eaf1a8feefbec417", + "result": "valid" }, { - "tcId" : 334, - "comment" : "special case hash", - "flags" : [ + "tcId": 334, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "3130363836363535353436", - "sig" : "304402200bf6c0188dc9571cd0e21eecac5fbb19d2434988e9cc10244593ef3a98099f6902204864a562661f9221ec88e3dd0bc2f6e27ac128c30cc1a80f79ec670a22b042ee", - "result" : "valid" + "msg": "3130363836363535353436", + "sig": "304402200bf6c0188dc9571cd0e21eecac5fbb19d2434988e9cc10244593ef3a98099f6902204864a562661f9221ec88e3dd0bc2f6e27ac128c30cc1a80f79ec670a22b042ee", + "result": "valid" }, { - "tcId" : 335, - "comment" : "special case hash", - "flags" : [ + "tcId": 335, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "3632313535323436", - "sig" : "3045022100ae459640d5d1179be47a47fa538e16d94ddea5585e7a244804a51742c686443a02206c8e30e530a634fae80b3ceb062978b39edbe19777e0a24553b68886181fd897", - "result" : "valid" + "msg": "3632313535323436", + "sig": "3045022100ae459640d5d1179be47a47fa538e16d94ddea5585e7a244804a51742c686443a02206c8e30e530a634fae80b3ceb062978b39edbe19777e0a24553b68886181fd897", + "result": "valid" }, { - "tcId" : 336, - "comment" : "special case hash", - "flags" : [ + "tcId": 336, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "37303330383138373734", - "sig" : "304402201cf3517ba3bf2ab8b9ead4ebb6e866cb88a1deacb6a785d3b63b483ca02ac4950220249a798b73606f55f5f1c70de67cb1a0cff95d7dc50b3a617df861bad3c6b1c9", - "result" : "valid" + "msg": "37303330383138373734", + "sig": "304402201cf3517ba3bf2ab8b9ead4ebb6e866cb88a1deacb6a785d3b63b483ca02ac4950220249a798b73606f55f5f1c70de67cb1a0cff95d7dc50b3a617df861bad3c6b1c9", + "result": "valid" }, { - "tcId" : 337, - "comment" : "special case hash", - "flags" : [ + "tcId": 337, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "35393234353233373434", - "sig" : "3045022100e69b5238265ea35d77e4dd172288d8cea19810a10292617d5976519dc5757cb802204b03c5bc47e826bdb27328abd38d3056d77476b2130f3df6ec4891af08ba1e29", - "result" : "valid" + "msg": "35393234353233373434", + "sig": "3045022100e69b5238265ea35d77e4dd172288d8cea19810a10292617d5976519dc5757cb802204b03c5bc47e826bdb27328abd38d3056d77476b2130f3df6ec4891af08ba1e29", + "result": "valid" }, { - "tcId" : 338, - "comment" : "special case hash", - "flags" : [ + "tcId": 338, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31343935353836363231", - "sig" : "304402205f9d7d7c870d085fc1d49fff69e4a275812800d2cf8973e7325866cb40fa2b6f02206d1f5491d9f717a597a15fd540406486d76a44697b3f0d9d6dcef6669f8a0a56", - "result" : "valid" + "msg": "31343935353836363231", + "sig": "304402205f9d7d7c870d085fc1d49fff69e4a275812800d2cf8973e7325866cb40fa2b6f02206d1f5491d9f717a597a15fd540406486d76a44697b3f0d9d6dcef6669f8a0a56", + "result": "valid" }, { - "tcId" : 339, - "comment" : "special case hash", - "flags" : [ + "tcId": 339, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "34303035333134343036", - "sig" : "304402200a7d5b1959f71df9f817146ee49bd5c89b431e7993e2fdecab6858957da685ae02200f8aad2d254690bdc13f34a4fec44a02fd745a422df05ccbb54635a8b86b9609", - "result" : "valid" + "msg": "34303035333134343036", + "sig": "304402200a7d5b1959f71df9f817146ee49bd5c89b431e7993e2fdecab6858957da685ae02200f8aad2d254690bdc13f34a4fec44a02fd745a422df05ccbb54635a8b86b9609", + "result": "valid" }, { - "tcId" : 340, - "comment" : "special case hash", - "flags" : [ + "tcId": 340, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "33303936343537353132", - "sig" : "3044022079e88bf576b74bc07ca142395fda28f03d3d5e640b0b4ff0752c6d94cd553408022032cea05bd2d706c8f6036a507e2ab7766004f0904e2e5c5862749c0073245d6a", - "result" : "valid" + "msg": "33303936343537353132", + "sig": "3044022079e88bf576b74bc07ca142395fda28f03d3d5e640b0b4ff0752c6d94cd553408022032cea05bd2d706c8f6036a507e2ab7766004f0904e2e5c5862749c0073245d6a", + "result": "valid" }, { - "tcId" : 341, - "comment" : "special case hash", - "flags" : [ + "tcId": 341, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "32373834303235363230", - "sig" : "30450221009d54e037a00212b377bc8874798b8da080564bbdf7e07591b861285809d01488022018b4e557667a82bd95965f0706f81a29243fbdd86968a7ebeb43069db3b18c7f", - "result" : "valid" + "msg": "32373834303235363230", + "sig": "30450221009d54e037a00212b377bc8874798b8da080564bbdf7e07591b861285809d01488022018b4e557667a82bd95965f0706f81a29243fbdd86968a7ebeb43069db3b18c7f", + "result": "valid" }, { - "tcId" : 342, - "comment" : "special case hash", - "flags" : [ + "tcId": 342, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "32363138373837343138", - "sig" : "304402202664f1ffa982fedbcc7cab1b8bc6e2cb420218d2a6077ad08e591ba9feab33bd022049f5c7cb515e83872a3d41b4cdb85f242ad9d61a5bfc01debfbb52c6c84ba728", - "result" : "valid" + "msg": "32363138373837343138", + "sig": "304402202664f1ffa982fedbcc7cab1b8bc6e2cb420218d2a6077ad08e591ba9feab33bd022049f5c7cb515e83872a3d41b4cdb85f242ad9d61a5bfc01debfbb52c6c84ba728", + "result": "valid" }, { - "tcId" : 343, - "comment" : "special case hash", - "flags" : [ + "tcId": 343, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "31363432363235323632", - "sig" : "304402205827518344844fd6a7de73cbb0a6befdea7b13d2dee4475317f0f18ffc81524b02204f5ccb4e0b488b5a5d760aacddb2d791970fe43da61eb30e2e90208a817e46db", - "result" : "valid" + "msg": "31363432363235323632", + "sig": "304402205827518344844fd6a7de73cbb0a6befdea7b13d2dee4475317f0f18ffc81524b02204f5ccb4e0b488b5a5d760aacddb2d791970fe43da61eb30e2e90208a817e46db", + "result": "valid" }, { - "tcId" : 344, - "comment" : "special case hash", - "flags" : [ + "tcId": 344, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "36383234313839343336", - "sig" : "304502210097ab19bd139cac319325869218b1bce111875d63fb12098a04b0cd59b6fdd3a30220431d9cea3a243847303cebda56476431d034339f31d785ee8852db4f040d4921", - "result" : "valid" + "msg": "36383234313839343336", + "sig": "304502210097ab19bd139cac319325869218b1bce111875d63fb12098a04b0cd59b6fdd3a30220431d9cea3a243847303cebda56476431d034339f31d785ee8852db4f040d4921", + "result": "valid" }, { - "tcId" : 345, - "comment" : "special case hash", - "flags" : [ + "tcId": 345, + "comment": "special case hash", + "flags": [ "SpecialCaseHash" ], - "msg" : "343834323435343235", - "sig" : "3044022052c683144e44119ae2013749d4964ef67509278f6d38ba869adcfa69970e123d02203479910167408f45bda420a626ec9c4ec711c1274be092198b4187c018b562ca", - "result" : "valid" + "msg": "343834323435343235", + "sig": "3044022052c683144e44119ae2013749d4964ef67509278f6d38ba869adcfa69970e123d02203479910167408f45bda420a626ec9c4ec711c1274be092198b4187c018b562ca", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", - "wx" : "07310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc362", - "wy" : "26a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", + "wx": "07310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc362", + "wy": "26a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEBzEPkKnq4UmghAL1QZSg97SsQnv42b1s\ndoEHHcR9w2ImptN6xG1h/WAMC/G/+HaJ7RF92msOWTGK4BChl6JsoA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 346, - "comment" : "k*G has a large x-coordinate", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEBzEPkKnq4UmghAL1QZSg97SsQnv42b1s\ndoEHHcR9w2ImptN6xG1h/WAMC/G/+HaJ7RF92msOWTGK4BChl6JsoA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 346, + "comment": "k*G has a large x-coordinate", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "30160211014551231950b75fc4402da1722fc9baeb020103", - "result" : "valid" + "msg": "313233343030", + "sig": "30160211014551231950b75fc4402da1722fc9baeb020103", + "result": "valid" }, { - "tcId" : 347, - "comment" : "r too large", - "flags" : [ + "tcId": 347, + "comment": "r too large", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c020103", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c020103", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", - "wx" : "00bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22", - "wy" : "705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", + "wx": "00bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22", + "wy": "705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvJfnWF7srUjhZoO8QJFwjhqTDGg/xHAB\n1LODWU8sTiJwWYnPadrq3U5OS4FR7YiN/sIPsBco2J1Ws/OPKunIxQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 348, - "comment" : "r,s are large", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvJfnWF7srUjhZoO8QJFwjhqTDGg/xHAB\n1LODWU8sTiJwWYnPadrq3U5OS4FR7YiN/sIPsBco2J1Ws/OPKunIxQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 348, + "comment": "r,s are large", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f020103", - "result" : "valid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f020103", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", - "wx" : "44ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252", - "wy" : "00b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", + "wx": "44ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252", + "wy": "00b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERK0zmvvCHpq/e2AqXKU16jeBNbbRDYEx\nC92Ck9HfMlK2P/fQd0dw+P4dFyL6g6zQL0NOT8EQoMyPbd3TfVbEYw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 349, - "comment" : "r and s^-1 have a large Hamming weight", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERK0zmvvCHpq/e2AqXKU16jeBNbbRDYEx\nC92Ck9HfMlK2P/fQd0dw+P4dFyL6g6zQL0NOT8EQoMyPbd3TfVbEYw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 349, + "comment": "r and s^-1 have a large Hamming weight", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e9a7582886089c62fb840cf3b83061cd1cff3ae4341808bb5bdee6191174177", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e9a7582886089c62fb840cf3b83061cd1cff3ae4341808bb5bdee6191174177", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", - "wx" : "1260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c", - "wy" : "5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", + "wx": "1260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c", + "wy": "5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEmDCEiyeJE4a9RUb7eDDriO1TXxZaIHT\n7rrSHzfdh4xcmgwamt52c3qIEb1qf5KHyXjuOWqonBHkcinSzLVS8A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 350, - "comment" : "r and s^-1 have a large Hamming weight", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEmDCEiyeJE4a9RUb7eDDriO1TXxZaIHT\n7rrSHzfdh4xcmgwamt52c3qIEb1qf5KHyXjuOWqonBHkcinSzLVS8A==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 350, + "comment": "r and s^-1 have a large Hamming weight", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022024238e70b431b1a64efdf9032669939d4b77f249503fc6905feb7540dea3e6d2", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022024238e70b431b1a64efdf9032669939d4b77f249503fc6905feb7540dea3e6d2", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", - "wx" : "1877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce", - "wy" : "00821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", + "wx": "1877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce", + "wy": "00821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGHcEW+JdNKHQYA+dXADQZFoqVDebbO76\n0ua/XCozUs6CGlMswXUe4dNtQcPWq06bFD5E7EbXNHjqanmlwOVBWQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 351, - "comment" : "small r and s", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGHcEW+JdNKHQYA+dXADQZFoqVDebbO76\n0ua/XCozUs6CGlMswXUe4dNtQcPWq06bFD5E7EbXNHjqanmlwOVBWQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 351, + "comment": "small r and s", + "flags": [ "SmallRandS", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3006020101020101", - "result" : "valid" + "msg": "313233343030", + "sig": "3006020101020101", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", - "wx" : "455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50", - "wy" : "00aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", + "wx": "455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50", + "wy": "00aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERVQ5/MPS3uzt3q7OYOe9FzBPNuu2Aq31\noi4Ljx20alCuw4+yuvIh6ajRiHx79iIt0YNGNOdyYzFa9tI2CdBPdw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 352, - "comment" : "small r and s", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERVQ5/MPS3uzt3q7OYOe9FzBPNuu2Aq31\noi4Ljx20alCuw4+yuvIh6ajRiHx79iIt0YNGNOdyYzFa9tI2CdBPdw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 352, + "comment": "small r and s", + "flags": [ "SmallRandS", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3006020101020102", - "result" : "valid" + "msg": "313233343030", + "sig": "3006020101020102", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", - "wx" : "2e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece718", - "wy" : "0449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", + "wx": "2e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece718", + "wy": "0449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELh9GawJMDDrOJDfeCRJ/7QS3BvlLGaIb\nscKs81zs5xgESa41I9clNOlklyz9OzivC93ZYZ5a8iPk0aQPNM+fHQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 353, - "comment" : "small r and s", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELh9GawJMDDrOJDfeCRJ/7QS3BvlLGaIb\nscKs81zs5xgESa41I9clNOlklyz9OzivC93ZYZ5a8iPk0aQPNM+fHQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 353, + "comment": "small r and s", + "flags": [ "SmallRandS", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3006020101020103", - "result" : "valid" + "msg": "313233343030", + "sig": "3006020101020103", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", - "wx" : "008e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a23373", - "wy" : "26ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", + "wx": "008e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a23373", + "wy": "26ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjnq9u9GN50UjdMGHmhw7AdEyYefUVxw7\nR6HHbFWiM3Mm7Yl81Rek9TSduAl4D20vK59imdi1qJB38RGacY/Xsw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 354, - "comment" : "small r and s", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjnq9u9GN50UjdMGHmhw7AdEyYefUVxw7\nR6HHbFWiM3Mm7Yl81Rek9TSduAl4D20vK59imdi1qJB38RGacY/Xsw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 354, + "comment": "small r and s", + "flags": [ "SmallRandS", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3006020102020101", - "result" : "valid" + "msg": "313233343030", + "sig": "3006020102020101", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", - "wx" : "7b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af19", - "wy" : "42117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", + "wx": "7b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af19", + "wy": "42117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEezM9Q0DT1xjdPmr/fee7+Lcr/WFshCAF\nYFKEI3a5rxlCEXxa/qx1XW83b8Yymn12BRuHEjpKXQvEpTk4DwPeew==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 355, - "comment" : "small r and s", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEezM9Q0DT1xjdPmr/fee7+Lcr/WFshCAF\nYFKEI3a5rxlCEXxa/qx1XW83b8Yymn12BRuHEjpKXQvEpTk4DwPeew==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 355, + "comment": "small r and s", + "flags": [ "SmallRandS", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3006020102020102", - "result" : "valid" + "msg": "313233343030", + "sig": "3006020102020102", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", - "wx" : "00d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e5", - "wy" : "03a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", + "wx": "00d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e5", + "wy": "03a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0wykoN22YWyFHTDO1oLED4PGJ1ih8nWZ\niNZ2OojxwOUDqA1UFWUNQSOXhOji+xI16f6ZHREuu4EYbL8Not46/w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 356, - "comment" : "small r and s", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0wykoN22YWyFHTDO1oLED4PGJ1ih8nWZ\niNZ2OojxwOUDqA1UFWUNQSOXhOji+xI16f6ZHREuu4EYbL8Not46/w==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 356, + "comment": "small r and s", + "flags": [ "SmallRandS", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3006020102020103", - "result" : "valid" + "msg": "313233343030", + "sig": "3006020102020103", + "result": "valid" }, { - "tcId" : 357, - "comment" : "r is larger than n", - "flags" : [ + "tcId": 357, + "comment": "r is larger than n", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364143020103", - "result" : "invalid" + "msg": "313233343030", + "sig": "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364143020103", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", - "wx" : "48969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24", - "wy" : "00b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", + "wx": "48969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24", + "wy": "00b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAESJabOZkSl7MyplLT7m4B6QmzmQTnH6I1\nSngwx3ULryS0AS0bgw0ZnMsfyXKzK/3tVfCc1i0lfl6ETiflehWU7A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 358, - "comment" : "s is larger than n", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAESJabOZkSl7MyplLT7m4B6QmzmQTnH6I1\nSngwx3ULryS0AS0bgw0ZnMsfyXKzK/3tVfCc1i0lfl6ETiflehWU7A==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 358, + "comment": "s is larger than n", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "30080201020203ed2979", - "result" : "invalid" + "msg": "313233343030", + "sig": "30080201020203ed2979", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", - "wx" : "02ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee77", - "wy" : "7eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", + "wx": "02ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee77", + "wy": "7eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAu9NbWz9WpTx13hCJuPipsCkNsVYOWGf\nOPtEcrX57nd+tKzU7r2lzXKHX/0qLyYinC3GtGUAkZpDLIZznzroZg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 359, - "comment" : "small r and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAu9NbWz9WpTx13hCJuPipsCkNsVYOWGf\nOPtEcrX57nd+tKzU7r2lzXKHX/0qLyYinC3GtGUAkZpDLIZznzroZg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 359, + "comment": "small r and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "30260202010102203a74e9d3a74e9d3a74e9d3a74e9d3a749f8ab3732a0a89604a09bce5b2916da4", - "result" : "valid" + "msg": "313233343030", + "sig": "30260202010102203a74e9d3a74e9d3a74e9d3a74e9d3a749f8ab3732a0a89604a09bce5b2916da4", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", - "wx" : "464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584", - "wy" : "00b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", + "wx": "464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584", + "wy": "00b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERk9P9xVynK5Qcso72AHTGVtnrsZemwGq\n0gopQ9y8tYSxr9KdMaOaEdVwqhWXQ5s7LRlxvy8avxVDLQIHsQ0dCA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 360, - "comment" : "smallish r and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERk9P9xVynK5Qcso72AHTGVtnrsZemwGq\n0gopQ9y8tYSxr9KdMaOaEdVwqhWXQ5s7LRlxvy8avxVDLQIHsQ0dCA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 360, + "comment": "smallish r and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "302b02072d9b4d347952cc02200343aefc2f25d98b882e86eb9e30d55a6eb508b516510b34024ae4b6362330b3", - "result" : "valid" + "msg": "313233343030", + "sig": "302b02072d9b4d347952cc02200343aefc2f25d98b882e86eb9e30d55a6eb508b516510b34024ae4b6362330b3", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", - "wx" : "157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4c", - "wy" : "00deadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", + "wx": "157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4c", + "wy": "00deadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFX+P3fNz619Jz88Q2LhTz5HLzX1mXDUi\nun3XON23mkzerfGlxEjqPJ9BkaiZmr/MdXrG1kVn7wcsR/7GE0Q7jw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 361, - "comment" : "100-bit r and small s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFX+P3fNz619Jz88Q2LhTz5HLzX1mXDUi\nun3XON23mkzerfGlxEjqPJ9BkaiZmr/MdXrG1kVn7wcsR/7GE0Q7jw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 361, + "comment": "100-bit r and small s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3031020d1033e67e37b32b445580bf4efc02206f906f906f906f906f906f906f906f8fe1cab5eefdb214061dce3b22789f1d6f", - "result" : "valid" + "msg": "313233343030", + "sig": "3031020d1033e67e37b32b445580bf4efc02206f906f906f906f906f906f906f906f8fe1cab5eefdb214061dce3b22789f1d6f", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", - "wx" : "0934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0", - "wy" : "00d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", + "wx": "0934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0", + "wy": "00d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECTSlN0ZsB0MOLEj+uZC7Gft4zsyc7kJO\npNEwKRqiN/DU+S0jtGKAS1toxSVYwByZltv3J/zKu+7bliGkAFNa+g==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 362, - "comment" : "small r and 100 bit s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECTSlN0ZsB0MOLEj+uZC7Gft4zsyc7kJO\npNEwKRqiN/DU+S0jtGKAS1toxSVYwByZltv3J/zKu+7bliGkAFNa+g==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 362, + "comment": "small r and 100 bit s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3026020201010220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", - "result" : "valid" + "msg": "313233343030", + "sig": "3026020201010220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", - "wx" : "00d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c65", - "wy" : "4a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", + "wx": "00d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c65", + "wy": "4a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1u8gvmbIk/dBqb+Q2bdGddHCoxKWOXrL\nPvF0/QswDGVKDJVHjKADmRYtfw8tyJ79wrKKMPur4oWFcpWksMTiZQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 363, - "comment" : "100-bit r and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1u8gvmbIk/dBqb+Q2bdGddHCoxKWOXrL\nPvF0/QswDGVKDJVHjKADmRYtfw8tyJ79wrKKMPur4oWFcpWksMTiZQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 363, + "comment": "100-bit r and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3031020d062522bbd3ecbe7c39e93e7c260220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", - "result" : "valid" + "msg": "313233343030", + "sig": "3031020d062522bbd3ecbe7c39e93e7c260220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", - "wx" : "00b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee06", - "wy" : "29c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", + "wx": "00b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee06", + "wy": "29c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtykdFATgwMB9q5NyGJ9L1Y0s6qjRXt5U\nTZUUVFup7gYpyaY9XjCHacww7CdqQQ5kZKJ+6v2eWZ2xDwU6T+SoKQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 364, - "comment" : "r and s^-1 are close to n", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtykdFATgwMB9q5NyGJ9L1Y0s6qjRXt5U\nTZUUVFup7gYpyaY9XjCHacww7CdqQQ5kZKJ+6v2eWZ2xDwU6T+SoKQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 364, + "comment": "r and s^-1 are close to n", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3045022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03640c1022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03640c1022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", - "wx" : "6e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8", - "wy" : "186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", + "wx": "6e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8", + "wy": "186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbigwMwXWQsy5I7ci6oayoLyONzXssm6E\nmxnJ92sv27gYboDWTYyrFk9SOPUxhGG/idTZbuZUTIFsdWaUd3Tg9g==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 365, - "comment" : "r and s are 64-bit integer", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbigwMwXWQsy5I7ci6oayoLyONzXssm6E\nmxnJ92sv27gYboDWTYyrFk9SOPUxhGG/idTZbuZUTIFsdWaUd3Tg9g==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 365, + "comment": "r and s are 64-bit integer", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "30160209009c44febf31c3594d020900839ed28247c2b06b", - "result" : "valid" + "msg": "313233343030", + "sig": "30160209009c44febf31c3594d020900839ed28247c2b06b", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", - "wx" : "375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9", - "wy" : "00a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", + "wx": "375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9", + "wy": "00a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEN1vak/avkvtfj0sbXwU047r6s0y3rZ+5\n0Lci5KXDAqmgC584elo5YJeqIWL8W7z0pSYzcvaByU2lHpeZEgmQ/Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 366, - "comment" : "r and s are 100-bit integer", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEN1vak/avkvtfj0sbXwU047r6s0y3rZ+5\n0Lci5KXDAqmgC584elo5YJeqIWL8W7z0pSYzcvaByU2lHpeZEgmQ/Q==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 366, + "comment": "r and s are 100-bit integer", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "301e020d09df8b682430beef6f5fd7c7cf020d0fd0a62e13778f4222a0d61c8a", - "result" : "valid" + "msg": "313233343030", + "sig": "301e020d09df8b682430beef6f5fd7c7cf020d0fd0a62e13778f4222a0d61c8a", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", - "wx" : "00d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197", - "wy" : "00da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", + "wx": "00d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197", + "wy": "00da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE11toIWur4DriV+lLTjvxxS9E498mbRUk\n/4xepp2nMZfaS/+e0cU/RJF6Z9e5eFmOid81nj1ZE+rqJPOuJZq8RA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 367, - "comment" : "r and s are 128-bit integer", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE11toIWur4DriV+lLTjvxxS9E498mbRUk\n/4xepp2nMZfaS/+e0cU/RJF6Z9e5eFmOid81nj1ZE+rqJPOuJZq8RA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 367, + "comment": "r and s are 128-bit integer", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "30260211008a598e563a89f526c32ebec8de26367a02110084f633e2042630e99dd0f1e16f7a04bf", - "result" : "valid" + "msg": "313233343030", + "sig": "30260211008a598e563a89f526c32ebec8de26367a02110084f633e2042630e99dd0f1e16f7a04bf", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", - "wx" : "78bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653", - "wy" : "118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", + "wx": "78bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653", + "wy": "118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeLzaFArtI9QwyyPD3A0B9CPbE07pSjqM\ntIPy3qwqxlMRgRT28zBF1OntkQcIUAe/vd+PWP56GiRF1mqZAEVHbg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 368, - "comment" : "r and s are 160-bit integer", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeLzaFArtI9QwyyPD3A0B9CPbE07pSjqM\ntIPy3qwqxlMRgRT28zBF1OntkQcIUAe/vd+PWP56GiRF1mqZAEVHbg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 368, + "comment": "r and s are 160-bit integer", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "302e021500aa6eeb5823f7fa31b466bb473797f0d0314c0bdf021500e2977c479e6d25703cebbc6bd561938cc9d1bfb9", - "result" : "valid" + "msg": "313233343030", + "sig": "302e021500aa6eeb5823f7fa31b466bb473797f0d0314c0bdf021500e2977c479e6d25703cebbc6bd561938cc9d1bfb9", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", - "wx" : "00bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c", - "wy" : "1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", + "wx": "00bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c", + "wy": "1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEu3n2GFf3Q7+htucRHOQJQ3claWnk4VFZ\nEj2VSKzDvmwfnZ+IYNz/0+s23Wwx/y5yJsIAnEyU2NfStWhr96vWdw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 369, - "comment" : "s == 1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEu3n2GFf3Q7+htucRHOQJQ3claWnk4VFZ\nEj2VSKzDvmwfnZ+IYNz/0+s23Wwx/y5yJsIAnEyU2NfStWhr96vWdw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 369, + "comment": "s == 1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020101", - "result" : "valid" + "msg": "313233343030", + "sig": "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020101", + "result": "valid" }, { - "tcId" : 370, - "comment" : "s == 0", - "flags" : [ + "tcId": 370, + "comment": "s == 0", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020100", - "result" : "invalid" + "msg": "313233343030", + "sig": "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020100", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", - "wx" : "0093591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36", - "wy" : "073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", + "wx": "0093591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36", + "wy": "073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEk1kYJ9nmcTtOn66mLHKyjf76aODAUWC1\n1qroj9LjbDYHP1VFrVr0EK8mr/9oZUz3LUXkk0iTESAyRzR6iQ9FGA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 371, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEk1kYJ9nmcTtOn66mLHKyjf76aODAUWC1\n1qroj9LjbDYHP1VFrVr0EK8mr/9oZUz3LUXkk0iTESAyRzR6iQ9FGA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 371, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220419d981c515af8cc82545aac0c85e9e308fbb2eab6acd7ed497e0b4145a18fd9", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220419d981c515af8cc82545aac0c85e9e308fbb2eab6acd7ed497e0b4145a18fd9", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", - "wx" : "31ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0da", - "wy" : "00da01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", + "wx": "31ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0da", + "wy": "00da01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMe0wga7+AB62QCBp7izMGGKTe4WZUUTb\nqVA5Q1h78NraAbjMTfNPWrOxo1lhUgiUbl7jX5jud1uMzs2GzMFlDw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 372, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMe0wga7+AB62QCBp7izMGGKTe4WZUUTb\nqVA5Q1h78NraAbjMTfNPWrOxo1lhUgiUbl7jX5jud1uMzs2GzMFlDw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 372, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102201b21717ad71d23bbac60a9ad0baf75b063c9fdf52a00ebf99d022172910993c9", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102201b21717ad71d23bbac60a9ad0baf75b063c9fdf52a00ebf99d022172910993c9", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", - "wx" : "7dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea8", - "wy" : "54c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", + "wx": "7dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea8", + "wy": "54c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEff9m+phQn/Pi5RBF9DkFI9zNpDo7wohe\nWMJICQmQ7qhUx2wrmt62u1cYI+B/18ZchjnPnZBSYAZMjnZ1zm2YtA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 373, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEff9m+phQn/Pi5RBF9DkFI9zNpDo7wohe\nWMJICQmQ7qhUx2wrmt62u1cYI+B/18ZchjnPnZBSYAZMjnZ1zm2YtA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 373, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202f588f66018f3dd14db3e28e77996487e32486b521ed8e5a20f06591951777e9", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202f588f66018f3dd14db3e28e77996487e32486b521ed8e5a20f06591951777e9", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", - "wx" : "4280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a", - "wy" : "2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", + "wx": "4280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a", + "wy": "2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEQoBQmqtk7fwLSiln5MvOhJy1ROSncxPI\n5uzlefvXQgouif5cwZJ9VU5qO7FAM+p8kizXXLosdBX9q1LyCxhg8Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 374, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEQoBQmqtk7fwLSiln5MvOhJy1ROSncxPI\n5uzlefvXQgouif5cwZJ9VU5qO7FAM+p8kizXXLosdBX9q1LyCxhg8Q==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 374, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220091a08870ff4daf9123b30c20e8c4fc8505758dcf4074fcaff2170c9bfcf74f4", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220091a08870ff4daf9123b30c20e8c4fc8505758dcf4074fcaff2170c9bfcf74f4", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", - "wx" : "4f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb", - "wy" : "2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", + "wx": "4f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb", + "wy": "2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAET43xRRlOPE/D7qJtQ851tALWsXRy3cuy\nVLinmwvz2csqog2ChEyyZjROccp48q0np1oJ5bwPpX5O/Z1GWgiI2w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 375, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAET43xRRlOPE/D7qJtQ851tALWsXRy3cuy\nVLinmwvz2csqog2ChEyyZjROccp48q0np1oJ5bwPpX5O/Z1GWgiI2w==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 375, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207c370dc0ce8c59a8b273cba44a7c1191fc3186dc03cab96b0567312df0d0b250", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207c370dc0ce8c59a8b273cba44a7c1191fc3186dc03cab96b0567312df0d0b250", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", - "wx" : "009598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14", - "wy" : "122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", + "wx": "009598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14", + "wy": "122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElZilfdZ+w+FrWHoziqOhCjo5E7QaOvMu\nPtP/ATWMaxQSKBnt+AdLvFIffUzc6C/velFnBq/7odk9neqcyuGiBw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 376, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElZilfdZ+w+FrWHoziqOhCjo5E7QaOvMu\nPtP/ATWMaxQSKBnt+AdLvFIffUzc6C/velFnBq/7odk9neqcyuGiBw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 376, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022070b59a7d1ee77a2f9e0491c2a7cfcd0ed04df4a35192f6132dcc668c79a6160e", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022070b59a7d1ee77a2f9e0491c2a7cfcd0ed04df4a35192f6132dcc668c79a6160e", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", - "wx" : "009171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e", - "wy" : "634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", + "wx": "009171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e", + "wy": "634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkXH+w8oggGvAhPEvB2CRG2CZC9gOWypx\nygOgSLIPg35jT9F4Y3YbKVjSvk4Un409ervcGL4D9FGrbBf6Ch+DMA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 377, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkXH+w8oggGvAhPEvB2CRG2CZC9gOWypx\nygOgSLIPg35jT9F4Y3YbKVjSvk4Un409ervcGL4D9FGrbBf6Ch+DMA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 377, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202736d76e412246e097148e2bf62915614eb7c428913a58eb5e9cd4674a9423de", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202736d76e412246e097148e2bf62915614eb7c428913a58eb5e9cd4674a9423de", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", - "wx" : "777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9", - "wy" : "00ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", + "wx": "777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9", + "wy": "00ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEd3yJMLbh0nEQD+aM6T8WP6N2EsX/9n9K\nYvw7r689F6ntc9hvYKUbXtkTU6OwVO3AqpLJ68vQt10Yj9yIJ5HWjQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 378, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEd3yJMLbh0nEQD+aM6T8WP6N2EsX/9n9K\nYvw7r689F6ntc9hvYKUbXtkTU6OwVO3AqpLJ68vQt10Yj9yIJ5HWjQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 378, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204a1e12831fbe93627b02d6e7f24bccdd6ef4b2d0f46739eaf3b1eaf0ca117770", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204a1e12831fbe93627b02d6e7f24bccdd6ef4b2d0f46739eaf3b1eaf0ca117770", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", - "wx" : "00eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf470", - "wy" : "0603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", + "wx": "00eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf470", + "wy": "0603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE6rwkj2JuCmPh64HEPUYaOaHbqIHrbuIV\nKwfDLXG89HAGA8qoudM9sTr0TG777IoZjtYSSsnrF+qv0oJKVF7AAA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 379, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE6rwkj2JuCmPh64HEPUYaOaHbqIHrbuIV\nKwfDLXG89HAGA8qoudM9sTr0TG777IoZjtYSSsnrF+qv0oJKVF7AAA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 379, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022006c778d4dfff7dee06ed88bc4e0ed34fc553aad67caf796f2a1c6487c1b2e877", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022006c778d4dfff7dee06ed88bc4e0ed34fc553aad67caf796f2a1c6487c1b2e877", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", - "wx" : "009f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001", - "wy" : "00f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", + "wx": "009f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001", + "wy": "00f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEn3oTraFYpV+d3xpF8ETwc9m4ADDv3Pyf\nn1hBj7zq8AH4raAXUJD4DUcifWcTtnQPmgCR2IqDfQoc13tYqPKNcw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 380, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEn3oTraFYpV+d3xpF8ETwc9m4ADDv3Pyf\nn1hBj7zq8AH4raAXUJD4DUcifWcTtnQPmgCR2IqDfQoc13tYqPKNcw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 380, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204de459ef9159afa057feb3ec40fef01c45b809f4ab296ea48c206d4249a2b451", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204de459ef9159afa057feb3ec40fef01c45b809f4ab296ea48c206d4249a2b451", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", - "wx" : "11c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4db", - "wy" : "00bbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", + "wx": "11c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4db", + "wy": "00bbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEcTz5GHNAZtcBuoM6kxAkMPMPjxdnzxt\nZbQ2gm2ptNu763p35Mv9ogcJfENCNwX3LIBHbaPaxApIOwqw8urRyw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 381, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEcTz5GHNAZtcBuoM6kxAkMPMPjxdnzxt\nZbQ2gm2ptNu763p35Mv9ogcJfENCNwX3LIBHbaPaxApIOwqw8urRyw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 381, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220745d294978007302033502e1acc48b63ae6500be43adbea1b258d6b423dbb416", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220745d294978007302033502e1acc48b63ae6500be43adbea1b258d6b423dbb416", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", - "wx" : "00e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4", - "wy" : "161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", + "wx": "00e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4", + "wy": "161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE4uGGgtUxI6oBpsXQCwxiPWcbRi6oC93W\nUif9UQWYiqQWGQez/SUESpSepByOLqhFncbxZUhWuLYbMVQ7sbRb2w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 382, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE4uGGgtUxI6oBpsXQCwxiPWcbRi6oC93W\nUif9UQWYiqQWGQez/SUESpSepByOLqhFncbxZUhWuLYbMVQ7sbRb2w==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 382, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207b2a785e3896f59b2d69da57648e80ad3c133a750a2847fd2098ccd902042b6c", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207b2a785e3896f59b2d69da57648e80ad3c133a750a2847fd2098ccd902042b6c", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", - "wx" : "0090f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197da", - "wy" : "00fadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", + "wx": "0090f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197da", + "wy": "00fadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkPjUynPeCKZWSq8AUke28P/peFBNzlJg\nX0a3w+Vhl9r62+Uo63DZ7n6g5wcC21T3IVFMe4YErCyyFPHey344PQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 383, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkPjUynPeCKZWSq8AUke28P/peFBNzlJg\nX0a3w+Vhl9r62+Uo63DZ7n6g5wcC21T3IVFMe4YErCyyFPHey344PQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 383, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022071ae94a72ca896875e7aa4a4c3d29afdb4b35b6996273e63c47ac519256c5eb1", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022071ae94a72ca896875e7aa4a4c3d29afdb4b35b6996273e63c47ac519256c5eb1", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", - "wx" : "00824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e", - "wy" : "3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", + "wx": "00824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e", + "wy": "3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEgkwZXHPP/fA40QG84Wh7XDthRvOVyIWX\nb3dTsjdrlI483vpvw0fRPk3LxjoLA6FlGAzSvhQxoM90zh6iUILSvA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 384, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEgkwZXHPP/fA40QG84Wh7XDthRvOVyIWX\nb3dTsjdrlI483vpvw0fRPk3LxjoLA6FlGAzSvhQxoM90zh6iUILSvA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 384, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102200fa527fa7343c0bc9ec35a6278bfbff4d83301b154fc4bd14aee7eb93445b5f9", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102200fa527fa7343c0bc9ec35a6278bfbff4d83301b154fc4bd14aee7eb93445b5f9", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", - "wx" : "2788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f", - "wy" : "30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", + "wx": "2788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f", + "wy": "30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ4ilLweOs/ICxPpz4NM4b6899r6FYANj\nb1mZItT1Jo8wtPIHyRm7315nqL5CZagXR1Szq6jxbldbd/9NWn62Tw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 385, - "comment" : "edge case modular inverse", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ4ilLweOs/ICxPpz4NM4b6899r6FYANj\nb1mZItT1Jo8wtPIHyRm7315nqL5CZagXR1Szq6jxbldbd/9NWn62Tw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 385, + "comment": "edge case modular inverse", + "flags": [ "ModularInverse", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102206539c0adadd0525ff42622164ce9314348bd0863b4c80e936b23ca0414264671", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102206539c0adadd0525ff42622164ce9314348bd0863b4c80e936b23ca0414264671", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", - "wx" : "00d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b4150874", - "wy" : "01b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", + "wx": "00d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b4150874", + "wy": "01b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1TO3iaSviQ+nqCofrljEBPmmKlC0mtr6\ns0nFE7QVCHQBtBcbgD52s0qYYeEPe8KJoGb9Ab0p+EyYehCl+xjC1A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 386, - "comment" : "point at infinity during verify", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1TO3iaSviQ+nqCofrljEBPmmKlC0mtr6\ns0nFE7QVCHQBtBcbgD52s0qYYeEPe8KJoGb9Ab0p+EyYehCl+xjC1A==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 386, + "comment": "point at infinity during verify", + "flags": [ "PointDuplication", "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", - "result" : "invalid" + "msg": "313233343030", + "sig": "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", - "wx" : "3a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4", - "wy" : "221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", + "wx": "3a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4", + "wy": "221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOjFQeYyK9p0ebpgfOkVAK6HXMvS+gzDF\nFk9J4Q7FVbQiG9hCvF5Nl+/zcWX2DjmYpCTXKkUM+V6kd8eCh9A0Og==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 387, - "comment" : "edge case for signature malleability", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOjFQeYyK9p0ebpgfOkVAK6HXMvS+gzDF\nFk9J4Q7FVbQiG9hCvF5Nl+/zcWX2DjmYpCTXKkUM+V6kd8eCh9A0Og==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 387, + "comment": "edge case for signature malleability", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", - "wx" : "3b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e80", - "wy" : "0de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", + "wx": "3b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e80", + "wy": "0de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOzffX7NHxpoPF9hcDHyoNzaIOoJeExQ9\nD8/IEB6FHoAN48CQtsohulQ1FzMMBLEvlIxrrfFKY6v/3074x1NwJg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 388, - "comment" : "edge case for signature malleability", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOzffX7NHxpoPF9hcDHyoNzaIOoJeExQ9\nD8/IEB6FHoAN48CQtsohulQ1FzMMBLEvlIxrrfFKY6v/3074x1NwJg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 388, + "comment": "edge case for signature malleability", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1", - "result" : "invalid" + "msg": "313233343030", + "sig": "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", - "wx" : "00feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82c", - "wy" : "00e87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", + "wx": "00feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82c", + "wy": "00e87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/rUWOw7OMP8+A8fVXEOA+i+oHuLANUlC\n/28IyZ0M2CzofeBe4b2gidPk4kj6D3IRAqz//fUOZUvigUM5md+Jfg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 389, - "comment" : "u1 == 1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/rUWOw7OMP8+A8fVXEOA+i+oHuLANUlC\n/28IyZ0M2CzofeBe4b2gidPk4kj6D3IRAqz//fUOZUvigUM5md+Jfg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 389, + "comment": "u1 == 1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", - "wx" : "238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd4149228976", - "wy" : "40683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", + "wx": "238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd4149228976", + "wy": "40683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEI4ztABzyK4hT4C7cicvspQULp+BCp6d/\nk4LNQUkiiXZAaD0wlGQ4QPKViQqkwYqjm0HXfdD7O7JwDk+ewoT/wg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 390, - "comment" : "u1 == n - 1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEI4ztABzyK4hT4C7cicvspQULp+BCp6d/\nk4LNQUkiiXZAaD0wlGQ4QPKViQqkwYqjm0HXfdD7O7JwDk+ewoT/wg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 390, + "comment": "u1 == n - 1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", - "wx" : "00961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35e", - "wy" : "00d2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", + "wx": "00961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35e", + "wy": "00d2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElhz2SBfAbA5Rs8JzbJIv3hi9jEkG/Nf1\n72bEZ4UI817SxdGBaM++cPLxI710GSMruS3WkRPilBBhiJSBxaAnvw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 391, - "comment" : "u2 == 1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElhz2SBfAbA5Rs8JzbJIv3hi9jEkG/Nf1\n72bEZ4UI817SxdGBaM++cPLxI710GSMruS3WkRPilBBhiJSBxaAnvw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 391, + "comment": "u2 == 1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", - "wx" : "13681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b10288", - "wy" : "16528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", + "wx": "13681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b10288", + "wy": "16528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEE2gerhaM1Op88uKkXQUnQtEKn2TnloZ9\nvcuCn+CxAogWUodg0Xc3bAnfed45VXwynMF1NRes/+j6LsKYAmuDhA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 392, - "comment" : "u2 == n - 1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEE2gerhaM1Op88uKkXQUnQtEKn2TnloZ9\nvcuCn+CxAogWUodg0Xc3bAnfed45VXwynMF1NRes/+j6LsKYAmuDhA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 392, + "comment": "u2 == n - 1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", - "wx" : "5aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c2", - "wy" : "0091c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", + "wx": "5aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c2", + "wy": "0091c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWqer/ba0CG1UMyXl15xulc5C+GbSu4SQ\nljOgS7GqMcKRyACIeUkF4dozM22HTi+RzPRcxZGFvt5d1vP3rKrhiw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 393, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWqer/ba0CG1UMyXl15xulc5C+GbSu4SQ\nljOgS7GqMcKRyACIeUkF4dozM22HTi+RzPRcxZGFvt5d1vP3rKrhiw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 393, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", - "wx" : "277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e4", - "wy" : "64108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", + "wx": "277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e4", + "wy": "64108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEACd3kbMFpFsrOVkLLwXTOSpsgYLO9OtU\nASDg9cIGw+RkEIIz+wuMOsiS15744Pv5LtEzrdtFVCcBMlhNxS7vQQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 394, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEACd3kbMFpFsrOVkLLwXTOSpsgYLO9OtU\nASDg9cIGw+RkEIIz+wuMOsiS15744Pv5LtEzrdtFVCcBMlhNxS7vQQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 394, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02201c940f313f92647be257eccd7ed08b0baef3f0478f25871b53635302c5f6314a", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02201c940f313f92647be257eccd7ed08b0baef3f0478f25871b53635302c5f6314a", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", - "wx" : "6efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1a", - "wy" : "00c75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", + "wx": "6efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1a", + "wy": "00c75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbvoJK2jelGDwvMkZAFpfboDhnemJaL48\n0sdwqZSb+xrHXm5Qh9ZVDV+b6x555QKTB7wlUjXi1dyZJBrDq4hsSQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 395, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbvoJK2jelGDwvMkZAFpfboDhnemJaL48\n0sdwqZSb+xrHXm5Qh9ZVDV+b6x555QKTB7wlUjXi1dyZJBrDq4hsSQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 395, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022015d94a85077b493f91cb7101ec63e1b01be58b594e855f45050a8c14062d689b", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022015d94a85077b493f91cb7101ec63e1b01be58b594e855f45050a8c14062d689b", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", - "wx" : "72d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058", - "wy" : "00e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", + "wx": "72d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058", + "wy": "00e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEctShnE+dLPWEjqQERbcNRpa18C1jLAxl\nTMfX7rDG0FjoxM2ZQ+RZF0x6wB+nQhmOR+bBmmvbDE9sI3gxwbP5Qg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 396, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEctShnE+dLPWEjqQERbcNRpa18C1jLAxl\nTMfX7rDG0FjoxM2ZQ+RZF0x6wB+nQhmOR+bBmmvbDE9sI3gxwbP5Qg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 396, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b1d27a7694c146244a5ad0bd0636d9d9ef3b9fb58385418d9c982105077d1b7", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b1d27a7694c146244a5ad0bd0636d9d9ef3b9fb58385418d9c982105077d1b7", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", - "wx" : "2a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e7402", - "wy" : "58f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", + "wx": "2a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e7402", + "wy": "58f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKo6i9Q3M7QwhdXW9+nzUfRxvEABB7A41\nUSeUwb5+dAJY+MFxIu0wP9pxQ+tYvt5wKVtlMmYBOwsOvT8FMTf27A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 397, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKo6i9Q3M7QwhdXW9+nzUfRxvEABB7A41\nUSeUwb5+dAJY+MFxIu0wP9pxQ+tYvt5wKVtlMmYBOwsOvT8FMTf27A==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 397, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202d85896b3eb9dbb5a52f42f9c9261ed3fc46644ec65f06ade3fd78f257e43432", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202d85896b3eb9dbb5a52f42f9c9261ed3fc46644ec65f06ade3fd78f257e43432", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", - "wx" : "0088de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b8", - "wy" : "0c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", + "wx": "0088de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b8", + "wy": "0c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiN5onOmvHpS+aiCJyKixJT/9u2yOnIYk\nm6IgABpK07gMSZjlSEL0E7ntsYJay7YzXoHk0YSysByL69yF0fKJRg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 398, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiN5onOmvHpS+aiCJyKixJT/9u2yOnIYk\nm6IgABpK07gMSZjlSEL0E7ntsYJay7YzXoHk0YSysByL69yF0fKJRg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 398, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b0b12d67d73b76b4a5e85f3924c3da7f88cc89d8cbe0d5bc7faf1e4afc86864", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b0b12d67d73b76b4a5e85f3924c3da7f88cc89d8cbe0d5bc7faf1e4afc86864", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", - "wx" : "00fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7", - "wy" : "00b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", + "wx": "00fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7", + "wy": "00b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/qLTH3D5DV+z4A4YasQqs8FhXO5xTgtO\nETGz1NgiW/ewN6GN8qwVND8w90Bn3fKegX1fd/jc4FcU2lnAlPDNqQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 399, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/qLTH3D5DV+z4A4YasQqs8FhXO5xTgtO\nETGz1NgiW/ewN6GN8qwVND8w90Bn3fKegX1fd/jc4FcU2lnAlPDNqQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 399, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220694c146244a5ad0bd0636d9e12bc9e09e60e68b90d0b5e6c5dddd0cb694d8799", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220694c146244a5ad0bd0636d9e12bc9e09e60e68b90d0b5e6c5dddd0cb694d8799", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", - "wx" : "7258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db", - "wy" : "17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", + "wx": "7258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db", + "wy": "17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcliRHj1CM0kWZHnb4Lg0Gvf70D0KfhDt\nzLNrbO6lo9sXrCuJknkRKPo7ltwvvUyjv6eC7ygy/GZWlD2xjnNGsA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 400, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcliRHj1CM0kWZHnb4Lg0Gvf70D0KfhDt\nzLNrbO6lo9sXrCuJknkRKPo7ltwvvUyjv6eC7ygy/GZWlD2xjnNGsA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 400, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203d7f487c07bfc5f30846938a3dcef696444707cf9677254a92b06c63ab867d22", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203d7f487c07bfc5f30846938a3dcef696444707cf9677254a92b06c63ab867d22", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", - "wx" : "4f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914", - "wy" : "00c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", + "wx": "4f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914", + "wy": "00c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAETyhGHepkR01rs00Umcl9N7npVjPfHO7q\nrNRQFsmLORTIgYgQuMwG3bQOihJhxSj6pYlFXVpt+Tt3vF4OSTx0cA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 401, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAETyhGHepkR01rs00Umcl9N7npVjPfHO7q\nrNRQFsmLORTIgYgQuMwG3bQOihJhxSj6pYlFXVpt+Tt3vF4OSTx0cA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 401, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206c7648fc0fbf8a06adb8b839f97b4ff7a800f11b1e37c593b261394599792ba4", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206c7648fc0fbf8a06adb8b839f97b4ff7a800f11b1e37c593b261394599792ba4", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", - "wx" : "74f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66", - "wy" : "00eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", + "wx": "74f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66", + "wy": "00eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEdPKoFPtdjsqRppteYHEnMrOTfeMoKb6X\nTte2jFwvXWbv8PB8VvmHplf0IZYgX1iMDx2W/YpjpfI4tI9Hh4j+Ow==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 402, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEdPKoFPtdjsqRppteYHEnMrOTfeMoKb6X\nTte2jFwvXWbv8PB8VvmHplf0IZYgX1iMDx2W/YpjpfI4tI9Hh4j+Ow==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 402, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220641c9c5d790dc09cdd3dfabb62cdf453e69747a7e3d7aa1a714189ef53171a99", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220641c9c5d790dc09cdd3dfabb62cdf453e69747a7e3d7aa1a714189ef53171a99", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", - "wx" : "195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6a", - "wy" : "00b2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", + "wx": "195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6a", + "wy": "00b2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGVtRp8xKIbgnSnCpDed5gUw8jKNYMoII\nwJop8za4LWqyQWt8kv/9wpw7EoLdKnek0E3390UgRzk9hJmJxc7prQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 403, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGVtRp8xKIbgnSnCpDed5gUw8jKNYMoII\nwJop8za4LWqyQWt8kv/9wpw7EoLdKnek0E3390UgRzk9hJmJxc7prQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 403, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022029798c5c45bdf58b4a7b2fdc2c46ab4af1218c7eeb9f0f27a88f1267674de3b0", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022029798c5c45bdf58b4a7b2fdc2c46ab4af1218c7eeb9f0f27a88f1267674de3b0", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", - "wx" : "622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa", - "wy" : "736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", + "wx": "622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa", + "wy": "736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYi/HRzIDS+wt3zvBbTSz0fejJ90qjBm6\ntLtP46JLWKpzay8vrnb0367MkJYzOwEyjVHrP9qckifpDQtEmYPE8A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 404, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYi/HRzIDS+wt3zvBbTSz0fejJ90qjBm6\ntLtP46JLWKpzay8vrnb0367MkJYzOwEyjVHrP9qckifpDQtEmYPE8A==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 404, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02200b70f22ca2bb3cefadca1a5711fa3a59f4695385eb5aedf3495d0b6d00f8fd85", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02200b70f22ca2bb3cefadca1a5711fa3a59f4695385eb5aedf3495d0b6d00f8fd85", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", - "wx" : "1f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c7", - "wy" : "0827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", + "wx": "1f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c7", + "wy": "0827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH3+FyvLXVQ56+bZQI+u03ONFAxFpIwnb\nJplpuDS2EccIJ/RbeAIOy7r0hP3Vv6rmhw8RhMIVgbr274K9e1MPkw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 405, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH3+FyvLXVQ56+bZQI+u03ONFAxFpIwnb\nJplpuDS2EccIJ/RbeAIOy7r0hP3Vv6rmhw8RhMIVgbr274K9e1MPkw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 405, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", - "wx" : "49c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377a", - "wy" : "00efc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", + "wx": "49c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377a", + "wy": "00efc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEScGX3ICtHaR6Q0K5OJPo4fsLuU/DOoPn\ng8ALJMeBN3rvwg2pK6x2KVH3JHS+zHNNTMIrqBuJXigv2sTfevDzfQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 406, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEScGX3ICtHaR6Q0K5OJPo4fsLuU/DOoPn\ng8ALJMeBN3rvwg2pK6x2KVH3JHS+zHNNTMIrqBuJXigv2sTfevDzfQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 406, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202252d685e831b6cf095e4f0535eeaf0ddd3bfa91c210c9d9dc17224702eaf88f", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202252d685e831b6cf095e4f0535eeaf0ddd3bfa91c210c9d9dc17224702eaf88f", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", - "wx" : "00d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe", - "wy" : "7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", + "wx": "00d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe", + "wy": "7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2MtoUXthalZACqOGhjXlS29plZii9hZ3\nV2VJgLr2rL5+yM9EnISaoDRhow762kFFPFfG5vvJO7xvpJrabcBVXA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 407, - "comment" : "edge case for u1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2MtoUXthalZACqOGhjXlS29plZii9hZ3\nV2VJgLr2rL5+yM9EnISaoDRhow762kFFPFfG5vvJO7xvpJrabcBVXA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 407, + "comment": "edge case for u1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022075135abd7c425b60371a477f09ce0f274f64a8c6b061a07b5d63e93c65046c53", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022075135abd7c425b60371a477f09ce0f274f64a8c6b061a07b5d63e93c65046c53", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", - "wx" : "030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3", - "wy" : "00b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", + "wx": "030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3", + "wy": "00b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAwcT+2Pyqm/iyt8bIO/CWcd0Rdr6h9rD\nmLhAZco0ffOyJ4GN4aObWJywcdg+UxfMzcIzjlHjEv4x2Nw0pIAXUA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 408, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAwcT+2Pyqm/iyt8bIO/CWcd0Rdr6h9rD\nmLhAZco0ffOyJ4GN4aObWJywcdg+UxfMzcIzjlHjEv4x2Nw0pIAXUA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 408, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", - "wx" : "00babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7", - "wy" : "252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", + "wx": "00babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7", + "wy": "252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEurs2d7CVWALY6SmkE1VkDq8eoTU/incT\nMcSUbjSAr6clLxlsh+09KlnTsbVZE3/tABP+zvwZ+1qSaCubylG5UA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 409, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEurs2d7CVWALY6SmkE1VkDq8eoTU/incT\nMcSUbjSAr6clLxlsh+09KlnTsbVZE3/tABP+zvwZ+1qSaCubylG5UA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 409, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e888377ac6c71ac9dec3fdb9b56c9feaf0cfaca9f827fc5eb65fc3eac811210", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e888377ac6c71ac9dec3fdb9b56c9feaf0cfaca9f827fc5eb65fc3eac811210", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", - "wx" : "1aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60", - "wy" : "00bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", + "wx": "1aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60", + "wy": "00bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGqsgGHk0cREaig6bFD/eAvyVkgeW06Y9\n4ym0JDlvumC75BMHBRdHkkQbMY06ox3+hXeCHptEbsVz0nLgNsTr6Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 410, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGqsgGHk0cREaig6bFD/eAvyVkgeW06Y9\n4ym0JDlvumC75BMHBRdHkkQbMY06ox3+hXeCHptEbsVz0nLgNsTr6Q==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 410, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022030bbb794db588363b40679f6c182a50d3ce9679acdd3ffbe36d7813dacbdc818", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022030bbb794db588363b40679f6c182a50d3ce9679acdd3ffbe36d7813dacbdc818", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", - "wx" : "008cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff", - "wy" : "47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", + "wx": "008cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff", + "wy": "47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjLC5CUmcg+qAbNiFsd1GegEZ8GqIoCdu\nsM/aJ0U1qP9HtUKIM7w/LIv52QQRWM8zcYpplhzQFym8ABHR5YardQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 411, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjLC5CUmcg+qAbNiFsd1GegEZ8GqIoCdu\nsM/aJ0U1qP9HtUKIM7w/LIv52QQRWM8zcYpplhzQFym8ABHR5YardQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 411, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202c37fd995622c4fb7fffffffffffffffc7cee745110cb45ab558ed7c90c15a2f", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202c37fd995622c4fb7fffffffffffffffc7cee745110cb45ab558ed7c90c15a2f", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", - "wx" : "008f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d", - "wy" : "3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", + "wx": "008f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d", + "wy": "3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjwPPGkInK7FTJyMJP3Lm/urIXhcA6fvp\npqLdZC10v107iacYna2M91/CL28ViqJ/nCygDaynhb4zWPK9o4YsoA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 412, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjwPPGkInK7FTJyMJP3Lm/urIXhcA6fvp\npqLdZC10v107iacYna2M91/CL28ViqJ/nCygDaynhb4zWPK9o4YsoA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 412, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02207fd995622c4fb7ffffffffffffffffff5d883ffab5b32652ccdcaa290fccb97d", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02207fd995622c4fb7ffffffffffffffffff5d883ffab5b32652ccdcaa290fccb97d", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", - "wx" : "44de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8ace", - "wy" : "00a2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", + "wx": "44de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8ace", + "wy": "00a2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERN47nHpXqMnoIJUnU0IefZh7s9efcfAT\ngFyJfgGPis6iRgdYyPmNP9zhIalDZZ43LDJv/y5fwq5/o/edquE8Eg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 413, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERN47nHpXqMnoIJUnU0IefZh7s9efcfAT\ngFyJfgGPis6iRgdYyPmNP9zhIalDZZ43LDJv/y5fwq5/o/edquE8Eg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 413, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304302207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc021f4cd53ba7608fffffffffffffffffffff9e5cf143e2539626190a3ab09cce47", - "result" : "valid" + "msg": "313233343030", + "sig": "304302207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc021f4cd53ba7608fffffffffffffffffffff9e5cf143e2539626190a3ab09cce47", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", - "wx" : "6fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a", - "wy" : "0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", + "wx": "6fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a", + "wy": "0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEb7iytI4zAxJorWpRdITciDnqkPZmnqDH\nrDIz4qwxOUoKyLvn9zwv9N+ZeHJ6wd/C/VhkfSDzH5kQUxa2RnHyBA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 414, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEb7iytI4zAxJorWpRdITciDnqkPZmnqDH\nrDIz4qwxOUoKyLvn9zwv9N+ZeHJ6wd/C/VhkfSDzH5kQUxa2RnHyBA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 414, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205622c4fb7fffffffffffffffffffffff928a8f1c7ac7bec1808b9f61c01ec327", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205622c4fb7fffffffffffffffffffffff928a8f1c7ac7bec1808b9f61c01ec327", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", - "wx" : "00bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6", - "wy" : "00f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", + "wx": "00bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6", + "wy": "00f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvqcRIqBIaT6QX/YCs8+d0Yr2m5/J2EMd\nKx3Sa5Qsleb0PHuLletiCCwS2529p/445Fy+SkiGkH+4G9sMXqkkbA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 415, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvqcRIqBIaT6QX/YCs8+d0Yr2m5/J2EMd\nKx3Sa5Qsleb0PHuLletiCCwS2529p/445Fy+SkiGkH+4G9sMXqkkbA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 415, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022044104104104104104104104104104103b87853fd3b7d3f8e175125b4382f25ed", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022044104104104104104104104104104103b87853fd3b7d3f8e175125b4382f25ed", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", - "wx" : "00da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156", - "wy" : "00e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", + "wx": "00da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156", + "wy": "00e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2pGMcxugaiDLlO8zt3jpgaQEowXxlB/j\nNma0WwM1MVbiuyaU9XW0UYO+eOXJtSEL879Ij9TIKUUW2JVyyk9TkQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 416, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2pGMcxugaiDLlO8zt3jpgaQEowXxlB/j\nNma0WwM1MVbiuyaU9XW0UYO+eOXJtSEL879Ij9TIKUUW2JVyyk9TkQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 416, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202739ce739ce739ce739ce739ce739ce705560298d1f2f08dc419ac273a5b54d9", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202739ce739ce739ce739ce739ce739ce705560298d1f2f08dc419ac273a5b54d9", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", - "wx" : "3007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d", - "wy" : "5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", + "wx": "3007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d", + "wy": "5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMAfpLDk32t55ZN+jWw7/Ax9+sCrtCgMU\nQREGzetw/j1adUb8BVKZeyDj1vQT514stm4RYyJpcRS3m6xzS/xNxQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 417, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMAfpLDk32t55ZN+jWw7/Ax9+sCrtCgMU\nQREGzetw/j1adUb8BVKZeyDj1vQT514stm4RYyJpcRS3m6xzS/xNxQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 417, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02204888888888888888888888888888888831c83ae82ebe0898776b4c69d11f88de", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02204888888888888888888888888888888831c83ae82ebe0898776b4c69d11f88de", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", - "wx" : "60e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9b", - "wy" : "00d2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", + "wx": "60e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9b", + "wy": "00d2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYOc071Yk08vw3dN1ARvWY9bWrrxkTrWZ\n/fmNvc0YzpvS2Qs6wx8TmvgyzM9sy7ssbqEfqXNw3JkG2kdNfYp1Zw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 418, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYOc071Yk08vw3dN1ARvWY9bWrrxkTrWZ\n/fmNvc0YzpvS2Qs6wx8TmvgyzM9sy7ssbqEfqXNw3JkG2kdNfYp1Zw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 418, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206492492492492492492492492492492406dd3a19b8d5fb875235963c593bd2d3", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206492492492492492492492492492492406dd3a19b8d5fb875235963c593bd2d3", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", - "wx" : "0085a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba337", - "wy" : "69744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", + "wx": "0085a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba337", + "wy": "69744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEhakA6XhY9pPAt9+iYeOA2tbqBG0fZd3u\n7dX32K8LozdpdE0VrdT2wLw7DaKuyTs0y4xl+TQN33TnsACe7szOPA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 419, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEhakA6XhY9pPAt9+iYeOA2tbqBG0fZd3u\n7dX32K8LozdpdE0VrdT2wLw7DaKuyTs0y4xl+TQN33TnsACe7szOPA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 419, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b15", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b15", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", - "wx" : "38066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046", - "wy" : "00a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", + "wx": "38066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046", + "wy": "00a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOAZvddiO/EyT3jb0ngN7I0zBix3lYIdQ\npiyrA0VAEEaj6EvtjPy4Ge9NVQRE8s5LZRdmtp4uKQH4iDb/kANP7Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 420, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOAZvddiO/EyT3jb0ngN7I0zBix3lYIdQ\npiyrA0VAEEaj6EvtjPy4Ge9NVQRE8s5LZRdmtp4uKQH4iDb/kANP7Q==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 420, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", - "wx" : "0098f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabf", - "wy" : "00a33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", + "wx": "0098f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabf", + "wy": "00a33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmPaBd9yVwbTL+lJFSIylI6fVYpRw0DXW\nIaRDxy85qr+jPSlUb6HGSPLH1cz3DPHOSrebXbGsBZ2+zQaNvf8biQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 421, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmPaBd9yVwbTL+lJFSIylI6fVYpRw0DXW\nIaRDxy85qr+jPSlUb6HGSPLH1cz3DPHOSrebXbGsBZ2+zQaNvf8biQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 421, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", - "wx" : "5c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277", - "wy" : "00e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", + "wx": "5c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277", + "wy": "00e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEXCu/ojybmtB/A4qom0kwvyZ9lAHkJV3p\n6NoKUHjsgnfj6IKjHV5qN54Hk5g8ze05uVxDU6sv8B6lNpukewwxkQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 422, - "comment" : "edge case for u2", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEXCu/ojybmtB/A4qom0kwvyZ9lAHkJV3p\n6NoKUHjsgnfj6IKjHV5qN54Hk5g8ze05uVxDU6sv8B6lNpukewwxkQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 422, + "comment": "edge case for u2", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220185ddbca6dac41b1da033cfb60c152869e74b3cd66e9ffdf1b6bc09ed65ee40c", - "result" : "valid" + "msg": "313233343030", + "sig": "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220185ddbca6dac41b1da033cfb60c152869e74b3cd66e9ffdf1b6bc09ed65ee40c", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", - "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", - "wy" : "3547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", + "wx": "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", + "wy": "3547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4U1R4CCmESO215wGt6EzV+xrJVnul6Ptoprkz7EtcyEzA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 423, - "comment" : "point duplication during verification", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4U1R4CCmESO215wGt6EzV+xrJVnul6Ptoprkz7EtcyEzA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 423, + "comment": "point duplication during verification", + "flags": [ "PointDuplication" ], - "msg" : "313233343030", - "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", - "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", - "wy" : "00cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", + "wx": "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", + "wy": "00cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4XKuH99Z7txJKGP5SF7MqBOU2qYRaFwSXWUbME6SjN3Yw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 424, - "comment" : "duplication bug", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4XKuH99Z7txJKGP5SF7MqBOU2qYRaFwSXWUbME6SjN3Yw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 424, + "comment": "duplication bug", + "flags": [ "PointDuplication" ], - "msg" : "313233343030", - "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", - "wx" : "008aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e", - "wy" : "1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", + "wx": "008aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e", + "wy": "1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiqLGT6nGQ3Vjq/vL0AsgSNSMGMFSoqb0\nkDbedkfr6C4c5kOHmVxooGD6O8A5mwXMBu7H1Zj3UEGkkX5pK39R/w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 425, - "comment" : "comparison with point at infinity ", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiqLGT6nGQ3Vjq/vL0AsgSNSMGMFSoqb0\nkDbedkfr6C4c5kOHmVxooGD6O8A5mwXMBu7H1Zj3UEGkkX5pK39R/w==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 425, + "comment": "comparison with point at infinity ", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0022033333333333333333333333333333332f222f8faefdb533f265d461c29a47373", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0022033333333333333333333333333333332f222f8faefdb533f265d461c29a47373", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", - "wx" : "391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71f", - "wy" : "00dd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", + "wx": "391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71f", + "wy": "00dd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEORQn/37ngBPBSux9lqigYiCSmKeDg16U\n/WVJ1QL/9x/dZiTsNDrZ/PTZhyGB5Z+EL5ukzMrgmmwJcvtqxrTGvQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 426, - "comment" : "extreme value for k and edgecase s", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEORQn/37ngBPBSux9lqigYiCSmKeDg16U\n/WVJ1QL/9x/dZiTsNDrZ/PTZhyGB5Z+EL5ukzMrgmmwJcvtqxrTGvQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 426, + "comment": "extreme value for k and edgecase s", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", - "wx" : "00e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138e", - "wy" : "00c1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", + "wx": "00e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138e", + "wy": "00c1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE52K4ohm08YAhnMepBZJF5JYb0ZHAOJl4\nnHo0uJ6ME47BUz7wQZu3N24L/ekxnRCgaWh5HZ6g7tnBzmNFrtl1ng==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 427, - "comment" : "extreme value for k and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE52K4ohm08YAhnMepBZJF5JYb0ZHAOJl4\nnHo0uJ6ME47BUz7wQZu3N24L/ekxnRCgaWh5HZ6g7tnBzmNFrtl1ng==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 427, + "comment": "extreme value for k and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", - "wx" : "009aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952", - "wy" : "00fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", + "wx": "009aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952", + "wy": "00fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmu2w0oHbFk4TAADFaX+uDzBe+Ei+b/+0\nOsWT+7lQ6VL6b2MzWb3NgrVrC5+WWwN3idRrmoFBt5GyrvpxP5bBdQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 428, - "comment" : "extreme value for k and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmu2w0oHbFk4TAADFaX+uDzBe+Ei+b/+0\nOsWT+7lQ6VL6b2MzWb3NgrVrC5+WWwN3idRrmoFBt5GyrvpxP5bBdQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 428, + "comment": "extreme value for k and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", - "wx" : "008ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee", - "wy" : "1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", + "wx": "008ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee", + "wy": "1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEitRF22KBYmDk5of9GITki5/AY20DFUfW\nMxXnkuGb+u4d5k+Z1fHNi27Jyw94emVK6GmTuj2xAI70PP8GhMsivQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 429, - "comment" : "extreme value for k and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEitRF22KBYmDk5of9GITki5/AY20DFUfW\nMxXnkuGb+u4d5k+Z1fHNi27Jyw94emVK6GmTuj2xAI70PP8GhMsivQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 429, + "comment": "extreme value for k and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", - "wx" : "1f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32", - "wy" : "00e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", + "wx": "1f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32", + "wy": "00e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH1eZyVvokGOyTybkDLkowahop2+wCUYH\n6AQ9tAnJHDLnVyToE6QZHjqDkAfwji6Jc4iwbUoA3m3mDlNtkfq1Zg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 430, - "comment" : "extreme value for k and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH1eZyVvokGOyTybkDLkowahop2+wCUYH\n6AQ9tAnJHDLnVyToE6QZHjqDkAfwji6Jc4iwbUoA3m3mDlNtkfq1Zg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 430, + "comment": "extreme value for k and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", - "wx" : "00a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc", - "wy" : "28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", + "wx": "00a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc", + "wy": "28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEozMaThtCI+wsAn7dSCySihTtNY2T8dQh\nfTmr9p/LXMwo1oTSqqvNY4N3XKpiOd4m1MaTe7YD7LQZYIL0z/1QnQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 431, - "comment" : "extreme value for k", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEozMaThtCI+wsAn7dSCySihTtNY2T8dQh\nfTmr9p/LXMwo1oTSqqvNY4N3XKpiOd4m1MaTe7YD7LQZYIL0z/1QnQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 431, + "comment": "extreme value for k", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee502200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee502200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", - "wx" : "3f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb24818", - "wy" : "5ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", + "wx": "3f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb24818", + "wy": "5ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPzlSGZd0x885s4tmyxBCpiYNhoCAOEXk\n1DOtujuySBhepJW2jLx+1Bc+5jyQQtxQJiXH634h+wLKmpEU4KOhjQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 432, - "comment" : "extreme value for k and edgecase s", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPzlSGZd0x885s4tmyxBCpiYNhoCAOEXk\n1DOtujuySBhepJW2jLx+1Bc+5jyQQtxQJiXH634h+wLKmpEU4KOhjQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 432, + "comment": "extreme value for k and edgecase s", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", - "wx" : "00cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e", - "wy" : "054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", + "wx": "00cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e", + "wy": "054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzfuMD0IuFE4TfCQSyGwXH1/j+j9bu1RO\nkHYojzzteG4FT9ByG3fBHHm+rLPJQhGwoZvaCGUu/q+SUTo7ChY2mA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 433, - "comment" : "extreme value for k and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzfuMD0IuFE4TfCQSyGwXH1/j+j9bu1RO\nkHYojzzteG4FT9ByG3fBHHm+rLPJQhGwoZvaCGUu/q+SUTo7ChY2mA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 433, + "comment": "extreme value for k and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", - "wx" : "73598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3", - "wy" : "00cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", + "wx": "73598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3", + "wy": "00cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEc1mKahxoJ4+mv9DOQGTmgjW8HA9rIKko\nEIvjNnMPh+PLrmElGbUDLsyFrtgRJxqV/nk51dNGAUC6MY9NFKujHQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 434, - "comment" : "extreme value for k and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEc1mKahxoJ4+mv9DOQGTmgjW8HA9rIKko\nEIvjNnMPh+PLrmElGbUDLsyFrtgRJxqV/nk51dNGAUC6MY9NFKujHQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 434, + "comment": "extreme value for k and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", - "wx" : "58debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a1", - "wy" : "6773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", + "wx": "58debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a1", + "wy": "6773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWN69mn7iydWRMkeKVECuTV1+1Dcwg2n5\nLqhsghg/EKFnc+dvXtv02g5PG9/6wPVyV+HfpGWEKTEwmiQkX9pqXQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 435, - "comment" : "extreme value for k and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWN69mn7iydWRMkeKVECuTV1+1Dcwg2n5\nLqhsghg/EKFnc+dvXtv02g5PG9/6wPVyV+HfpGWEKTEwmiQkX9pqXQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 435, + "comment": "extreme value for k and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", - "wx" : "008b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b", - "wy" : "00950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", + "wx": "008b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b", + "wy": "00950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEi5BN5HlnNAxfjDVypyCSTvdXhjf+qxlJ\nrLJBpaasP1uVCQRJb5gksdY/MxO64huJ+uia/fyBG17OA/1aowGGTw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 436, - "comment" : "extreme value for k and s^-1", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEi5BN5HlnNAxfjDVypyCSTvdXhjf+qxlJ\nrLJBpaasP1uVCQRJb5gksdY/MxO64huJ+uia/fyBG17OA/1aowGGTw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 436, + "comment": "extreme value for k and s^-1", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", - "wx" : "00f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a", - "wy" : "346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", + "wx": "00f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a", + "wy": "346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9IkrbVJcdx4DXyolJwjzeE5II4YEtPlN\nxW6qHlRtlBo0axqgvOaLHFDltS9Qn7VSLlwl4Ci8j4Y0Au23vK2LGw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 437, - "comment" : "extreme value for k", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9IkrbVJcdx4DXyolJwjzeE5II4YEtPlN\nxW6qHlRtlBo0axqgvOaLHFDltS9Qn7VSLlwl4Ci8j4Y0Au23vK2LGw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 437, + "comment": "extreme value for k", + "flags": [ "ArithmeticError" ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179802200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", - "result" : "valid" + "msg": "313233343030", + "sig": "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179802200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - "wy" : "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "wx": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "wy": "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 438, - "comment" : "public key shares x-coordinate with generator", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuA==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 438, + "comment": "public key shares x-coordinate with generator", + "flags": [ "PointDuplication" ], - "msg" : "313233343030", - "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result": "invalid" }, { - "tcId" : 439, - "comment" : "public key shares x-coordinate with generator", - "flags" : [ + "tcId": 439, + "comment": "public key shares x-coordinate with generator", + "flags": [ "PointDuplication" ], - "msg" : "313233343030", - "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", - "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - "wy" : "00b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", + "wx": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "wy": "00b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5i3xSWI2Vw7mqJbBAPx7vdXAuhLt1l6q+ZjuC9vBO8ndw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 440, - "comment" : "public key shares x-coordinate with generator", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5i3xSWI2Vw7mqJbBAPx7vdXAuhLt1l6q+ZjuC9vBO8ndw==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 440, + "comment": "public key shares x-coordinate with generator", + "flags": [ "PointDuplication" ], - "msg" : "313233343030", - "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", - "result" : "invalid" + "msg": "313233343030", + "sig": "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result": "invalid" }, { - "tcId" : 441, - "comment" : "public key shares x-coordinate with generator", - "flags" : [ + "tcId": 441, + "comment": "public key shares x-coordinate with generator", + "flags": [ "PointDuplication" ], - "msg" : "313233343030", - "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", - "result" : "invalid" + "msg": "313233343030", + "sig": "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result": "invalid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", - "wx" : "782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963", - "wy" : "00af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", + "wx": "782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963", + "wy": "00af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeCyO0X47Kng7VGTzOwllKnHGeOBexR6E\n4rz8Zjo96WOvmstCgLjH98QvTvmrpiRewewXEv04oPqWQY2M1qphUg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 442, - "comment" : "pseudorandom signature", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeCyO0X47Kng7VGTzOwllKnHGeOBexR6E\n4rz8Zjo96WOvmstCgLjH98QvTvmrpiRewewXEv04oPqWQY2M1qphUg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 442, + "comment": "pseudorandom signature", + "flags": [ "ValidSignature" ], - "msg" : "", - "sig" : "3045022100f80ae4f96cdbc9d853f83d47aae225bf407d51c56b7776cd67d0dc195d99a9dc02204cfc1d941e08cb9aceadde0f4ccead76b30d332fc442115d50e673e28686b70b", - "result" : "valid" + "msg": "", + "sig": "3045022100f80ae4f96cdbc9d853f83d47aae225bf407d51c56b7776cd67d0dc195d99a9dc02204cfc1d941e08cb9aceadde0f4ccead76b30d332fc442115d50e673e28686b70b", + "result": "valid" }, { - "tcId" : 443, - "comment" : "pseudorandom signature", - "flags" : [ + "tcId": 443, + "comment": "pseudorandom signature", + "flags": [ "ValidSignature" ], - "msg" : "4d7367", - "sig" : "30440220109cd8ae0374358984a8249c0a843628f2835ffad1df1a9a69aa2fe72355545c02205390ff250ac4274e1cb25cd6ca6491f6b91281e32f5b264d87977aed4a94e77b", - "result" : "valid" + "msg": "4d7367", + "sig": "30440220109cd8ae0374358984a8249c0a843628f2835ffad1df1a9a69aa2fe72355545c02205390ff250ac4274e1cb25cd6ca6491f6b91281e32f5b264d87977aed4a94e77b", + "result": "valid" }, { - "tcId" : 444, - "comment" : "pseudorandom signature", - "flags" : [ + "tcId": 444, + "comment": "pseudorandom signature", + "flags": [ "ValidSignature" ], - "msg" : "313233343030", - "sig" : "3045022100d035ee1f17fdb0b2681b163e33c359932659990af77dca632012b30b27a057b302201939d9f3b2858bc13e3474cb50e6a82be44faa71940f876c1cba4c3e989202b6", - "result" : "valid" + "msg": "313233343030", + "sig": "3045022100d035ee1f17fdb0b2681b163e33c359932659990af77dca632012b30b27a057b302201939d9f3b2858bc13e3474cb50e6a82be44faa71940f876c1cba4c3e989202b6", + "result": "valid" }, { - "tcId" : 445, - "comment" : "pseudorandom signature", - "flags" : [ + "tcId": 445, + "comment": "pseudorandom signature", + "flags": [ "ValidSignature" ], - "msg" : "0000000000000000000000000000000000000000", - "sig" : "304402204f053f563ad34b74fd8c9934ce59e79c2eb8e6eca0fef5b323ca67d5ac7ed23802204d4b05daa0719e773d8617dce5631c5fd6f59c9bdc748e4b55c970040af01be5", - "result" : "valid" + "msg": "0000000000000000000000000000000000000000", + "sig": "304402204f053f563ad34b74fd8c9934ce59e79c2eb8e6eca0fef5b323ca67d5ac7ed23802204d4b05daa0719e773d8617dce5631c5fd6f59c9bdc748e4b55c970040af01be5", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", - "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", - "wy" : "01060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", + "wx": "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", + "wy": "01060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv8AAAABBgSS1aVnPg8l2NUPt+WMSdhtRtQhaVXgqj1A4Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 446, - "comment" : "y-coordinate of the public key is small", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv8AAAABBgSS1aVnPg8l2NUPt+WMSdhtRtQhaVXgqj1A4Q==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 446, + "comment": "y-coordinate of the public key is small", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "304402206d6a4f556ccce154e7fb9f19e76c3deca13d59cc2aeb4ecad968aab2ded45965022053b9fa74803ede0fc4441bf683d56c564d3e274e09ccf47390badd1471c05fb7", - "result" : "valid" + "msg": "4d657373616765", + "sig": "304402206d6a4f556ccce154e7fb9f19e76c3deca13d59cc2aeb4ecad968aab2ded45965022053b9fa74803ede0fc4441bf683d56c564d3e274e09ccf47390badd1471c05fb7", + "result": "valid" }, { - "tcId" : 447, - "comment" : "y-coordinate of the public key is small", - "flags" : [ + "tcId": 447, + "comment": "y-coordinate of the public key is small", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3044022100aad503de9b9fd66b948e9acf596f0a0e65e700b28b26ec56e6e45e846489b3c4021f0ddc3a2f89abb817bb85c062ce02f823c63fc26b269e0bc9b84d81a5aa123d", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3044022100aad503de9b9fd66b948e9acf596f0a0e65e700b28b26ec56e6e45e846489b3c4021f0ddc3a2f89abb817bb85c062ce02f823c63fc26b269e0bc9b84d81a5aa123d", + "result": "valid" }, { - "tcId" : 448, - "comment" : "y-coordinate of the public key is small", - "flags" : [ + "tcId": 448, + "comment": "y-coordinate of the public key is small", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "30450221009182cebd3bb8ab572e167174397209ef4b1d439af3b200cdf003620089e43225022054477c982ea019d2e1000497fc25fcee1bccae55f2ac27530ae53b29c4b356a4", - "result" : "valid" + "msg": "4d657373616765", + "sig": "30450221009182cebd3bb8ab572e167174397209ef4b1d439af3b200cdf003620089e43225022054477c982ea019d2e1000497fc25fcee1bccae55f2ac27530ae53b29c4b356a4", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", - "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", - "wy" : "00fffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", + "wx": "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", + "wy": "00fffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv/////++fttKlqYwfDaJyrwSBpztieSuSvelqoeVcK7Tg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 449, - "comment" : "y-coordinate of the public key is large", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv/////++fttKlqYwfDaJyrwSBpztieSuSvelqoeVcK7Tg==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 449, + "comment": "y-coordinate of the public key is large", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "304402203854a3998aebdf2dbc28adac4181462ccac7873907ab7f212c42db0e69b56ed802203ed3f6b8a388d02f3e4df9f2ae9c1bd2c3916a686460dffcd42909cd7f82058e", - "result" : "valid" + "msg": "4d657373616765", + "sig": "304402203854a3998aebdf2dbc28adac4181462ccac7873907ab7f212c42db0e69b56ed802203ed3f6b8a388d02f3e4df9f2ae9c1bd2c3916a686460dffcd42909cd7f82058e", + "result": "valid" }, { - "tcId" : 450, - "comment" : "y-coordinate of the public key is large", - "flags" : [ + "tcId": 450, + "comment": "y-coordinate of the public key is large", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3045022100e94dbdc38795fe5c904d8f16d969d3b587f0a25d2de90b6d8c5c53ff887e360702207a947369c164972521bb8af406813b2d9f94d2aeaa53d4c215aaa0a2578a2c5d", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3045022100e94dbdc38795fe5c904d8f16d969d3b587f0a25d2de90b6d8c5c53ff887e360702207a947369c164972521bb8af406813b2d9f94d2aeaa53d4c215aaa0a2578a2c5d", + "result": "valid" }, { - "tcId" : 451, - "comment" : "y-coordinate of the public key is large", - "flags" : [ + "tcId": 451, + "comment": "y-coordinate of the public key is large", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3044022049fc102a08ca47b60e0858cd0284d22cddd7233f94aaffbb2db1dd2cf08425e102205b16fca5a12cdb39701697ad8e39ffd6bdec0024298afaa2326aea09200b14d6", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3044022049fc102a08ca47b60e0858cd0284d22cddd7233f94aaffbb2db1dd2cf08425e102205b16fca5a12cdb39701697ad8e39ffd6bdec0024298afaa2326aea09200b14d6", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", - "wx" : "013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0", - "wy" : "00f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", + "wx": "013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0", + "wy": "00f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAAAAAT/SIkjWTZX3PCm0irSGMYUL5QP9\nAPhGi18PcOD27nqkO8LG/SWx2CaSQcvdnbsNrJbcliMfQwcF+DhxfQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 452, - "comment" : "x-coordinate of the public key is small", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAAAAAT/SIkjWTZX3PCm0irSGMYUL5QP9\nAPhGi18PcOD27nqkO8LG/SWx2CaSQcvdnbsNrJbcliMfQwcF+DhxfQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 452, + "comment": "x-coordinate of the public key is small", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3044022041efa7d3f05a0010675fcb918a45c693da4b348df21a59d6f9cd73e0d831d67a02204454ada693e5e26b7bd693236d340f80545c834577b6f73d378c7bcc534244da", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3044022041efa7d3f05a0010675fcb918a45c693da4b348df21a59d6f9cd73e0d831d67a02204454ada693e5e26b7bd693236d340f80545c834577b6f73d378c7bcc534244da", + "result": "valid" }, { - "tcId" : 453, - "comment" : "x-coordinate of the public key is small", - "flags" : [ + "tcId": 453, + "comment": "x-coordinate of the public key is small", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3045022100b615698c358b35920dd883eca625a6c5f7563970cdfc378f8fe0cee17092144c022025f47b326b5be1fb610b885153ea84d41eb4716be66a994e8779989df1c863d4", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3045022100b615698c358b35920dd883eca625a6c5f7563970cdfc378f8fe0cee17092144c022025f47b326b5be1fb610b885153ea84d41eb4716be66a994e8779989df1c863d4", + "result": "valid" }, { - "tcId" : 454, - "comment" : "x-coordinate of the public key is small", - "flags" : [ + "tcId": 454, + "comment": "x-coordinate of the public key is small", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "304502210087cf8c0eb82d44f69c60a2ff5457d3aaa322e7ec61ae5aecfd678ae1c1932b0e02203add3b115815047d6eb340a3e008989eaa0f8708d1794814729094d08d2460d3", - "result" : "valid" + "msg": "4d657373616765", + "sig": "304502210087cf8c0eb82d44f69c60a2ff5457d3aaa322e7ec61ae5aecfd678ae1c1932b0e02203add3b115815047d6eb340a3e008989eaa0f8708d1794814729094d08d2460d3", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", - "wx" : "25afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dffffffff", - "wy" : "00fa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "0425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", + "wx": "25afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dffffffff", + "wy": "00fa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJa/WiayrrtZ8Hylt5ZQG+MVQ9XFGoLTs\nLJeHbf/////6RqduUgMi37xJHsTwzBl0IPxOpYg9j23VPDVLxPZ8NQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 455, - "comment" : "x-coordinate of the public key has many trailing 1's", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a0342000425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJa/WiayrrtZ8Hylt5ZQG+MVQ9XFGoLTs\nLJeHbf/////6RqduUgMi37xJHsTwzBl0IPxOpYg9j23VPDVLxPZ8NQ==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 455, + "comment": "x-coordinate of the public key has many trailing 1's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3044022062f48ef71ace27bf5a01834de1f7e3f948b9dce1ca1e911d5e13d3b104471d8202205ea8f33f0c778972c4582080deda9b341857dd64514f0849a05f6964c2e34022", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3044022062f48ef71ace27bf5a01834de1f7e3f948b9dce1ca1e911d5e13d3b104471d8202205ea8f33f0c778972c4582080deda9b341857dd64514f0849a05f6964c2e34022", + "result": "valid" }, { - "tcId" : 456, - "comment" : "x-coordinate of the public key has many trailing 1's", - "flags" : [ + "tcId": 456, + "comment": "x-coordinate of the public key has many trailing 1's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3045022100f6b0e2f6fe020cf7c0c20137434344ed7add6c4be51861e2d14cbda472a6ffb402206416c8dd3e5c5282b306e8dc8ff34ab64cc99549232d678d714402eb6ca7aa0f", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3045022100f6b0e2f6fe020cf7c0c20137434344ed7add6c4be51861e2d14cbda472a6ffb402206416c8dd3e5c5282b306e8dc8ff34ab64cc99549232d678d714402eb6ca7aa0f", + "result": "valid" }, { - "tcId" : 457, - "comment" : "x-coordinate of the public key has many trailing 1's", - "flags" : [ + "tcId": 457, + "comment": "x-coordinate of the public key has many trailing 1's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3045022100db09d8460f05eff23bc7e436b67da563fa4b4edb58ac24ce201fa8a358125057022046da116754602940c8999c8d665f786c50f5772c0a3cdbda075e77eabc64df16", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3045022100db09d8460f05eff23bc7e436b67da563fa4b4edb58ac24ce201fa8a358125057022046da116754602940c8999c8d665f786c50f5772c0a3cdbda075e77eabc64df16", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", - "wx" : "00d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb9", - "wy" : "3f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "04d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", + "wx": "00d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb9", + "wy": "3f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0S5sZrZ3NMPITSYBz1013Al+J2N/CspK\nT9t0tqrdO7k/W9/4i9VzbfiY5pkAbtdQ8RzwfFhmzXrXDHEh/////w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 458, - "comment" : "y-coordinate of the public key has many trailing 1's", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a03420004d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0S5sZrZ3NMPITSYBz1013Al+J2N/CspK\nT9t0tqrdO7k/W9/4i9VzbfiY5pkAbtdQ8RzwfFhmzXrXDHEh/////w==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 458, + "comment": "y-coordinate of the public key has many trailing 1's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "30440220592c41e16517f12fcabd98267674f974b588e9f35d35406c1a7bb2ed1d19b7b802203e65a06bd9f83caaeb7b00f2368d7e0dece6b12221269a9b5b765198f840a3a1", - "result" : "valid" + "msg": "4d657373616765", + "sig": "30440220592c41e16517f12fcabd98267674f974b588e9f35d35406c1a7bb2ed1d19b7b802203e65a06bd9f83caaeb7b00f2368d7e0dece6b12221269a9b5b765198f840a3a1", + "result": "valid" }, { - "tcId" : 459, - "comment" : "y-coordinate of the public key has many trailing 1's", - "flags" : [ + "tcId": 459, + "comment": "y-coordinate of the public key has many trailing 1's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3045022100be0d70887d5e40821a61b68047de4ea03debfdf51cdf4d4b195558b959a032b202207d994b2d8f1dbbeb13534eb3f6e5dccd85f5c4133c27d9e64271b1826ce1f67d", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3045022100be0d70887d5e40821a61b68047de4ea03debfdf51cdf4d4b195558b959a032b202207d994b2d8f1dbbeb13534eb3f6e5dccd85f5c4133c27d9e64271b1826ce1f67d", + "result": "valid" }, { - "tcId" : 460, - "comment" : "y-coordinate of the public key has many trailing 1's", - "flags" : [ + "tcId": 460, + "comment": "y-coordinate of the public key has many trailing 1's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3045022100fae92dfcb2ee392d270af3a5739faa26d4f97bfd39ed3cbee4d29e26af3b206a02206c9ba37f9faa6a1fd3f65f23b4e853d4692a7274240a12db7ba3884830630d16", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3045022100fae92dfcb2ee392d270af3a5739faa26d4f97bfd39ed3cbee4d29e26af3b206a02206c9ba37f9faa6a1fd3f65f23b4e853d4692a7274240a12db7ba3884830630d16", + "result": "valid" } ] }, { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", - "wx" : "6d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000", - "wy" : "00e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb" + "type": "EcdsaBitcoinVerify", + "publicKey": { + "type": "EcPublicKey", + "curve": "secp256k1", + "keySize": 256, + "uncompressed": "046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", + "wx": "6d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000", + "wy": "00e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb" }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbUp/YNR3Sk8KqLve25U8fup5CUB+MWR1\nVmS8KAAAAADmWdNOTfONnoyeqt+6NmEsdpGVvobHeqw/NueLU4aA+w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 461, - "comment" : "x-coordinate of the public key has many trailing 0's", - "flags" : [ + "publicKeyDer": "3056301006072a8648ce3d020106052b8104000a034200046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbUp/YNR3Sk8KqLve25U8fup5CUB+MWR1\nVmS8KAAAAADmWdNOTfONnoyeqt+6NmEsdpGVvobHeqw/NueLU4aA+w==\n-----END PUBLIC KEY-----\n", + "sha": "SHA-256", + "tests": [ + { + "tcId": 461, + "comment": "x-coordinate of the public key has many trailing 0's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "30440220176a2557566ffa518b11226694eb9802ed2098bfe278e5570fe1d5d7af18a94302201291df6a0ed5fc0d15098e70bcf13a009284dfd0689d3bb4be6ceeb9be1487c4", - "result" : "valid" + "msg": "4d657373616765", + "sig": "30440220176a2557566ffa518b11226694eb9802ed2098bfe278e5570fe1d5d7af18a94302201291df6a0ed5fc0d15098e70bcf13a009284dfd0689d3bb4be6ceeb9be1487c4", + "result": "valid" }, { - "tcId" : 462, - "comment" : "x-coordinate of the public key has many trailing 0's", - "flags" : [ + "tcId": 462, + "comment": "x-coordinate of the public key has many trailing 0's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3044022060be20c3dbc162dd34d26780621c104bbe5dace630171b2daef0d826409ee5c20220427f7e4d889d549170bda6a9409fb1cb8b0e763d13eea7bd97f64cf41dc6e497", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3044022060be20c3dbc162dd34d26780621c104bbe5dace630171b2daef0d826409ee5c20220427f7e4d889d549170bda6a9409fb1cb8b0e763d13eea7bd97f64cf41dc6e497", + "result": "valid" }, { - "tcId" : 463, - "comment" : "x-coordinate of the public key has many trailing 0's", - "flags" : [ + "tcId": 463, + "comment": "x-coordinate of the public key has many trailing 0's", + "flags": [ "EdgeCasePublicKey" ], - "msg" : "4d657373616765", - "sig" : "3045022100edf03cf63f658883289a1a593d1007895b9f236d27c9c1f1313089aaed6b16ae02201a4dd6fc0814dc523d1fefa81c64fbf5e618e651e7096fccadbb94cd48e5e0cd", - "result" : "valid" + "msg": "4d657373616765", + "sig": "3045022100edf03cf63f658883289a1a593d1007895b9f236d27c9c1f1313089aaed6b16ae02201a4dd6fc0814dc523d1fefa81c64fbf5e618e651e7096fccadbb94cd48e5e0cd", + "result": "valid" } ] } diff --git a/external/snappy/conandata.yml b/external/snappy/conandata.yml deleted file mode 100644 index 1488c7a2baf..00000000000 --- a/external/snappy/conandata.yml +++ /dev/null @@ -1,40 +0,0 @@ -sources: - "1.1.10": - url: "https://github.com/google/snappy/archive/1.1.10.tar.gz" - sha256: "49d831bffcc5f3d01482340fe5af59852ca2fe76c3e05df0e67203ebbe0f1d90" - "1.1.9": - url: "https://github.com/google/snappy/archive/1.1.9.tar.gz" - sha256: "75c1fbb3d618dd3a0483bff0e26d0a92b495bbe5059c8b4f1c962b478b6e06e7" - "1.1.8": - url: "https://github.com/google/snappy/archive/1.1.8.tar.gz" - sha256: "16b677f07832a612b0836178db7f374e414f94657c138e6993cbfc5dcc58651f" - "1.1.7": - url: "https://github.com/google/snappy/archive/1.1.7.tar.gz" - sha256: "3dfa02e873ff51a11ee02b9ca391807f0c8ea0529a4924afa645fbf97163f9d4" -patches: - "1.1.10": - - patch_file: "patches/1.1.10-0001-fix-inlining-failure.patch" - patch_description: "disable inlining for compilation error" - patch_type: "portability" - - patch_file: "patches/1.1.9-0002-no-Werror.patch" - patch_description: "disable 'warning as error' options" - patch_type: "portability" - - patch_file: "patches/1.1.10-0003-fix-clobber-list-older-llvm.patch" - patch_description: "disable inline asm on apple-clang" - patch_type: "portability" - - patch_file: "patches/1.1.9-0004-rtti-by-default.patch" - patch_description: "remove 'disable rtti'" - patch_type: "conan" - "1.1.9": - - patch_file: "patches/1.1.9-0001-fix-inlining-failure.patch" - patch_description: "disable inlining for compilation error" - patch_type: "portability" - - patch_file: "patches/1.1.9-0002-no-Werror.patch" - patch_description: "disable 'warning as error' options" - patch_type: "portability" - - patch_file: "patches/1.1.9-0003-fix-clobber-list-older-llvm.patch" - patch_description: "disable inline asm on apple-clang" - patch_type: "portability" - - patch_file: "patches/1.1.9-0004-rtti-by-default.patch" - patch_description: "remove 'disable rtti'" - patch_type: "conan" diff --git a/external/snappy/conanfile.py b/external/snappy/conanfile.py deleted file mode 100644 index 23558639f46..00000000000 --- a/external/snappy/conanfile.py +++ /dev/null @@ -1,89 +0,0 @@ -from conan import ConanFile -from conan.tools.build import check_min_cppstd -from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout -from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, rmdir -from conan.tools.scm import Version -import os - -required_conan_version = ">=1.54.0" - - -class SnappyConan(ConanFile): - name = "snappy" - description = "A fast compressor/decompressor" - topics = ("google", "compressor", "decompressor") - url = "https://github.com/conan-io/conan-center-index" - homepage = "https://github.com/google/snappy" - license = "BSD-3-Clause" - - package_type = "library" - settings = "os", "arch", "compiler", "build_type" - options = { - "shared": [True, False], - "fPIC": [True, False], - } - default_options = { - "shared": False, - "fPIC": True, - } - - def export_sources(self): - export_conandata_patches(self) - - def config_options(self): - if self.settings.os == 'Windows': - del self.options.fPIC - - def configure(self): - if self.options.shared: - self.options.rm_safe("fPIC") - - def layout(self): - cmake_layout(self, src_folder="src") - - def validate(self): - if self.settings.compiler.get_safe("cppstd"): - check_min_cppstd(self, 11) - - def source(self): - get(self, **self.conan_data["sources"][self.version], strip_root=True) - - def generate(self): - tc = CMakeToolchain(self) - tc.variables["SNAPPY_BUILD_TESTS"] = False - if Version(self.version) >= "1.1.8": - tc.variables["SNAPPY_FUZZING_BUILD"] = False - tc.variables["SNAPPY_REQUIRE_AVX"] = False - tc.variables["SNAPPY_REQUIRE_AVX2"] = False - tc.variables["SNAPPY_INSTALL"] = True - if Version(self.version) >= "1.1.9": - tc.variables["SNAPPY_BUILD_BENCHMARKS"] = False - tc.generate() - - def build(self): - apply_conandata_patches(self) - cmake = CMake(self) - cmake.configure() - cmake.build() - - def package(self): - copy(self, "COPYING", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) - cmake = CMake(self) - cmake.install() - rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) - - def package_info(self): - self.cpp_info.set_property("cmake_file_name", "Snappy") - self.cpp_info.set_property("cmake_target_name", "Snappy::snappy") - # TODO: back to global scope in conan v2 once cmake_find_package* generators removed - self.cpp_info.components["snappylib"].libs = ["snappy"] - if not self.options.shared: - if self.settings.os in ["Linux", "FreeBSD"]: - self.cpp_info.components["snappylib"].system_libs.append("m") - - # TODO: to remove in conan v2 once cmake_find_package* generators removed - self.cpp_info.names["cmake_find_package"] = "Snappy" - self.cpp_info.names["cmake_find_package_multi"] = "Snappy" - self.cpp_info.components["snappylib"].names["cmake_find_package"] = "snappy" - self.cpp_info.components["snappylib"].names["cmake_find_package_multi"] = "snappy" - self.cpp_info.components["snappylib"].set_property("cmake_target_name", "Snappy::snappy") diff --git a/external/snappy/patches/1.1.10-0001-fix-inlining-failure.patch b/external/snappy/patches/1.1.10-0001-fix-inlining-failure.patch deleted file mode 100644 index 66b0f055219..00000000000 --- a/external/snappy/patches/1.1.10-0001-fix-inlining-failure.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/snappy-stubs-internal.h b/snappy-stubs-internal.h -index 1548ed7..3b4a9f3 100644 ---- a/snappy-stubs-internal.h -+++ b/snappy-stubs-internal.h -@@ -100,7 +100,7 @@ - - // Inlining hints. - #if HAVE_ATTRIBUTE_ALWAYS_INLINE --#define SNAPPY_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) -+#define SNAPPY_ATTRIBUTE_ALWAYS_INLINE - #else - #define SNAPPY_ATTRIBUTE_ALWAYS_INLINE - #endif // HAVE_ATTRIBUTE_ALWAYS_INLINE diff --git a/external/snappy/patches/1.1.10-0003-fix-clobber-list-older-llvm.patch b/external/snappy/patches/1.1.10-0003-fix-clobber-list-older-llvm.patch deleted file mode 100644 index 969ce3805da..00000000000 --- a/external/snappy/patches/1.1.10-0003-fix-clobber-list-older-llvm.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/snappy.cc b/snappy.cc -index d414718..e4efb59 100644 ---- a/snappy.cc -+++ b/snappy.cc -@@ -1132,7 +1132,7 @@ inline size_t AdvanceToNextTagX86Optimized(const uint8_t** ip_p, size_t* tag) { - size_t literal_len = *tag >> 2; - size_t tag_type = *tag; - bool is_literal; --#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__) -+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__) && ( (!defined(__clang__) && !defined(__APPLE__)) || (!defined(__APPLE__) && defined(__clang__) && (__clang_major__ >= 9)) || (defined(__APPLE__) && defined(__clang__) && (__clang_major__ > 11)) ) - // TODO clang misses the fact that the (c & 3) already correctly - // sets the zero flag. - asm("and $3, %k[tag_type]\n\t" diff --git a/external/snappy/patches/1.1.9-0001-fix-inlining-failure.patch b/external/snappy/patches/1.1.9-0001-fix-inlining-failure.patch deleted file mode 100644 index cdc119c0d58..00000000000 --- a/external/snappy/patches/1.1.9-0001-fix-inlining-failure.patch +++ /dev/null @@ -1,14 +0,0 @@ -Fixes the following error: -error: inlining failed in call to ‘always_inline’ ‘size_t snappy::AdvanceToNextTag(const uint8_t**, size_t*)’: function body can be overwritten at link time - ---- snappy-stubs-internal.h -+++ snappy-stubs-internal.h -@@ -100,7 +100,7 @@ - - // Inlining hints. - #ifdef HAVE_ATTRIBUTE_ALWAYS_INLINE --#define SNAPPY_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) -+#define SNAPPY_ATTRIBUTE_ALWAYS_INLINE - #else - #define SNAPPY_ATTRIBUTE_ALWAYS_INLINE - #endif diff --git a/external/snappy/patches/1.1.9-0002-no-Werror.patch b/external/snappy/patches/1.1.9-0002-no-Werror.patch deleted file mode 100644 index d86e4e0a9df..00000000000 --- a/external/snappy/patches/1.1.9-0002-no-Werror.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- CMakeLists.txt -+++ CMakeLists.txt -@@ -69,7 +69,7 @@ -- # Use -Werror for clang only. -+if(0) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - if(NOT CMAKE_CXX_FLAGS MATCHES "-Werror") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") - endif(NOT CMAKE_CXX_FLAGS MATCHES "-Werror") - endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") -- -+endif() diff --git a/external/snappy/patches/1.1.9-0003-fix-clobber-list-older-llvm.patch b/external/snappy/patches/1.1.9-0003-fix-clobber-list-older-llvm.patch deleted file mode 100644 index 84bc674fdd5..00000000000 --- a/external/snappy/patches/1.1.9-0003-fix-clobber-list-older-llvm.patch +++ /dev/null @@ -1,12 +0,0 @@ -asm clobbers do not work for clang < 9 and apple-clang < 11 (found by SpaceIm) ---- snappy.cc -+++ snappy.cc -@@ -1026,7 +1026,7 @@ - size_t literal_len = *tag >> 2; - size_t tag_type = *tag; - bool is_literal; --#if defined(__GNUC__) && defined(__x86_64__) -+#if defined(__GNUC__) && defined(__x86_64__) && ( (!defined(__clang__) && !defined(__APPLE__)) || (!defined(__APPLE__) && defined(__clang__) && (__clang_major__ >= 9)) || (defined(__APPLE__) && defined(__clang__) && (__clang_major__ > 11)) ) - // TODO clang misses the fact that the (c & 3) already correctly - // sets the zero flag. - asm("and $3, %k[tag_type]\n\t" diff --git a/external/snappy/patches/1.1.9-0004-rtti-by-default.patch b/external/snappy/patches/1.1.9-0004-rtti-by-default.patch deleted file mode 100644 index c353a489d0e..00000000000 --- a/external/snappy/patches/1.1.9-0004-rtti-by-default.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -53,8 +53,6 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - add_definitions(-D_HAS_EXCEPTIONS=0) - - # Disable RTTI. -- string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-") - else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - # Use -Wall for clang and gcc. - if(NOT CMAKE_CXX_FLAGS MATCHES "-Wall") -@@ -78,8 +76,6 @@ endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") - - # Disable RTTI. -- string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") - endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - - # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make diff --git a/external/soci/conandata.yml b/external/soci/conandata.yml deleted file mode 100644 index 6eb59aaffa2..00000000000 --- a/external/soci/conandata.yml +++ /dev/null @@ -1,12 +0,0 @@ -sources: - "4.0.3": - url: "https://github.com/SOCI/soci/archive/v4.0.3.tar.gz" - sha256: "4b1ff9c8545c5d802fbe06ee6cd2886630e5c03bf740e269bb625b45cf934928" -patches: - "4.0.3": - - patch_file: "patches/0001-Remove-hardcoded-INSTALL_NAME_DIR-for-relocatable-li.patch" - patch_description: "Generate relocatable libraries on MacOS" - patch_type: "portability" - - patch_file: "patches/0002-Fix-soci_backend.patch" - patch_description: "Fix variable names for dependencies" - patch_type: "conan" diff --git a/external/soci/conanfile.py b/external/soci/conanfile.py deleted file mode 100644 index 7e611493d70..00000000000 --- a/external/soci/conanfile.py +++ /dev/null @@ -1,212 +0,0 @@ -from conan import ConanFile -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, copy, export_conandata_patches, get, rmdir -from conan.tools.microsoft import is_msvc -from conan.tools.scm import Version -from conan.errors import ConanInvalidConfiguration -import os - -required_conan_version = ">=1.55.0" - - -class SociConan(ConanFile): - name = "soci" - homepage = "https://github.com/SOCI/soci" - url = "https://github.com/conan-io/conan-center-index" - description = "The C++ Database Access Library " - topics = ("mysql", "odbc", "postgresql", "sqlite3") - license = "BSL-1.0" - - settings = "os", "arch", "compiler", "build_type" - options = { - "shared": [True, False], - "fPIC": [True, False], - "empty": [True, False], - "with_sqlite3": [True, False], - "with_db2": [True, False], - "with_odbc": [True, False], - "with_oracle": [True, False], - "with_firebird": [True, False], - "with_mysql": [True, False], - "with_postgresql": [True, False], - "with_boost": [True, False], - } - default_options = { - "shared": False, - "fPIC": True, - "empty": False, - "with_sqlite3": False, - "with_db2": False, - "with_odbc": False, - "with_oracle": False, - "with_firebird": False, - "with_mysql": False, - "with_postgresql": False, - "with_boost": False, - } - - def export_sources(self): - export_conandata_patches(self) - - def layout(self): - cmake_layout(self, src_folder="src") - - def config_options(self): - if self.settings.os == "Windows": - self.options.rm_safe("fPIC") - - def configure(self): - if self.options.shared: - self.options.rm_safe("fPIC") - - def requirements(self): - if self.options.with_sqlite3: - self.requires("sqlite3/3.47.0") - if self.options.with_odbc and self.settings.os != "Windows": - self.requires("odbc/2.3.11") - if self.options.with_mysql: - self.requires("libmysqlclient/8.1.0") - if self.options.with_postgresql: - self.requires("libpq/15.5") - if self.options.with_boost: - self.requires("boost/1.83.0") - - @property - def _minimum_compilers_version(self): - return { - "Visual Studio": "14", - "gcc": "4.8", - "clang": "3.8", - "apple-clang": "8.0" - } - - def validate(self): - if self.settings.compiler.get_safe("cppstd"): - check_min_cppstd(self, 11) - - compiler = str(self.settings.compiler) - compiler_version = Version(self.settings.compiler.version.value) - if compiler not in self._minimum_compilers_version: - self.output.warning("{} recipe lacks information about the {} compiler support.".format(self.name, self.settings.compiler)) - elif compiler_version < self._minimum_compilers_version[compiler]: - raise ConanInvalidConfiguration("{} requires a {} version >= {}".format(self.name, compiler, compiler_version)) - - prefix = "Dependencies for" - message = "not configured in this conan package." - if self.options.with_db2: - # self.requires("db2/0.0.0") # TODO add support for db2 - raise ConanInvalidConfiguration("{} DB2 {} ".format(prefix, message)) - if self.options.with_oracle: - # self.requires("oracle_db/0.0.0") # TODO add support for oracle - raise ConanInvalidConfiguration("{} ORACLE {} ".format(prefix, message)) - if self.options.with_firebird: - # self.requires("firebird/0.0.0") # TODO add support for firebird - raise ConanInvalidConfiguration("{} firebird {} ".format(prefix, message)) - - def source(self): - get(self, **self.conan_data["sources"][self.version], strip_root=True) - - def generate(self): - tc = CMakeToolchain(self) - - tc.variables["SOCI_SHARED"] = self.options.shared - tc.variables["SOCI_STATIC"] = not self.options.shared - tc.variables["SOCI_TESTS"] = False - tc.variables["SOCI_CXX11"] = True - tc.variables["SOCI_EMPTY"] = self.options.empty - tc.variables["WITH_SQLITE3"] = self.options.with_sqlite3 - tc.variables["WITH_DB2"] = self.options.with_db2 - tc.variables["WITH_ODBC"] = self.options.with_odbc - tc.variables["WITH_ORACLE"] = self.options.with_oracle - tc.variables["WITH_FIREBIRD"] = self.options.with_firebird - tc.variables["WITH_MYSQL"] = self.options.with_mysql - tc.variables["WITH_POSTGRESQL"] = self.options.with_postgresql - tc.variables["WITH_BOOST"] = self.options.with_boost - tc.generate() - - deps = CMakeDeps(self) - deps.generate() - - def build(self): - apply_conandata_patches(self) - cmake = CMake(self) - cmake.configure() - cmake.build() - - def package(self): - copy(self, "LICENSE_1_0.txt", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder) - - cmake = CMake(self) - cmake.install() - - rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) - - def package_info(self): - self.cpp_info.set_property("cmake_file_name", "SOCI") - - target_suffix = "" if self.options.shared else "_static" - lib_prefix = "lib" if is_msvc(self) and not self.options.shared else "" - version = Version(self.version) - lib_suffix = "_{}_{}".format(version.major, version.minor) if self.settings.os == "Windows" else "" - - # soci_core - self.cpp_info.components["soci_core"].set_property("cmake_target_name", "SOCI::soci_core{}".format(target_suffix)) - self.cpp_info.components["soci_core"].libs = ["{}soci_core{}".format(lib_prefix, lib_suffix)] - if self.options.with_boost: - self.cpp_info.components["soci_core"].requires.append("boost::boost") - - # soci_empty - if self.options.empty: - self.cpp_info.components["soci_empty"].set_property("cmake_target_name", "SOCI::soci_empty{}".format(target_suffix)) - self.cpp_info.components["soci_empty"].libs = ["{}soci_empty{}".format(lib_prefix, lib_suffix)] - self.cpp_info.components["soci_empty"].requires = ["soci_core"] - - # soci_sqlite3 - if self.options.with_sqlite3: - self.cpp_info.components["soci_sqlite3"].set_property("cmake_target_name", "SOCI::soci_sqlite3{}".format(target_suffix)) - self.cpp_info.components["soci_sqlite3"].libs = ["{}soci_sqlite3{}".format(lib_prefix, lib_suffix)] - self.cpp_info.components["soci_sqlite3"].requires = ["soci_core", "sqlite3::sqlite3"] - - # soci_odbc - if self.options.with_odbc: - self.cpp_info.components["soci_odbc"].set_property("cmake_target_name", "SOCI::soci_odbc{}".format(target_suffix)) - self.cpp_info.components["soci_odbc"].libs = ["{}soci_odbc{}".format(lib_prefix, lib_suffix)] - self.cpp_info.components["soci_odbc"].requires = ["soci_core"] - if self.settings.os == "Windows": - self.cpp_info.components["soci_odbc"].system_libs.append("odbc32") - else: - self.cpp_info.components["soci_odbc"].requires.append("odbc::odbc") - - # soci_mysql - if self.options.with_mysql: - self.cpp_info.components["soci_mysql"].set_property("cmake_target_name", "SOCI::soci_mysql{}".format(target_suffix)) - self.cpp_info.components["soci_mysql"].libs = ["{}soci_mysql{}".format(lib_prefix, lib_suffix)] - self.cpp_info.components["soci_mysql"].requires = ["soci_core", "libmysqlclient::libmysqlclient"] - - # soci_postgresql - if self.options.with_postgresql: - self.cpp_info.components["soci_postgresql"].set_property("cmake_target_name", "SOCI::soci_postgresql{}".format(target_suffix)) - self.cpp_info.components["soci_postgresql"].libs = ["{}soci_postgresql{}".format(lib_prefix, lib_suffix)] - self.cpp_info.components["soci_postgresql"].requires = ["soci_core", "libpq::libpq"] - - # TODO: to remove in conan v2 once cmake_find_package* generators removed - self.cpp_info.names["cmake_find_package"] = "SOCI" - self.cpp_info.names["cmake_find_package_multi"] = "SOCI" - self.cpp_info.components["soci_core"].names["cmake_find_package"] = "soci_core{}".format(target_suffix) - self.cpp_info.components["soci_core"].names["cmake_find_package_multi"] = "soci_core{}".format(target_suffix) - if self.options.empty: - self.cpp_info.components["soci_empty"].names["cmake_find_package"] = "soci_empty{}".format(target_suffix) - self.cpp_info.components["soci_empty"].names["cmake_find_package_multi"] = "soci_empty{}".format(target_suffix) - if self.options.with_sqlite3: - self.cpp_info.components["soci_sqlite3"].names["cmake_find_package"] = "soci_sqlite3{}".format(target_suffix) - self.cpp_info.components["soci_sqlite3"].names["cmake_find_package_multi"] = "soci_sqlite3{}".format(target_suffix) - if self.options.with_odbc: - self.cpp_info.components["soci_odbc"].names["cmake_find_package"] = "soci_odbc{}".format(target_suffix) - self.cpp_info.components["soci_odbc"].names["cmake_find_package_multi"] = "soci_odbc{}".format(target_suffix) - if self.options.with_mysql: - self.cpp_info.components["soci_mysql"].names["cmake_find_package"] = "soci_mysql{}".format(target_suffix) - self.cpp_info.components["soci_mysql"].names["cmake_find_package_multi"] = "soci_mysql{}".format(target_suffix) - if self.options.with_postgresql: - self.cpp_info.components["soci_postgresql"].names["cmake_find_package"] = "soci_postgresql{}".format(target_suffix) - self.cpp_info.components["soci_postgresql"].names["cmake_find_package_multi"] = "soci_postgresql{}".format(target_suffix) diff --git a/external/soci/patches/0001-Remove-hardcoded-INSTALL_NAME_DIR-for-relocatable-li.patch b/external/soci/patches/0001-Remove-hardcoded-INSTALL_NAME_DIR-for-relocatable-li.patch deleted file mode 100644 index 5de0027f750..00000000000 --- a/external/soci/patches/0001-Remove-hardcoded-INSTALL_NAME_DIR-for-relocatable-li.patch +++ /dev/null @@ -1,39 +0,0 @@ -From d491bf7b5040d314ffd0c6310ba01f78ff44c85e Mon Sep 17 00:00:00 2001 -From: Rasmus Thomsen -Date: Fri, 14 Apr 2023 09:16:29 +0200 -Subject: [PATCH] Remove hardcoded INSTALL_NAME_DIR for relocatable libraries - on MacOS - ---- - cmake/SociBackend.cmake | 2 +- - src/core/CMakeLists.txt | 1 - - 2 files changed, 1 insertion(+), 2 deletions(-) - -diff --git a/cmake/SociBackend.cmake b/cmake/SociBackend.cmake -index 5d4ef0df..39fe1f77 100644 ---- a/cmake/SociBackend.cmake -+++ b/cmake/SociBackend.cmake -@@ -171,7 +171,7 @@ macro(soci_backend NAME) - set_target_properties(${THIS_BACKEND_TARGET} - PROPERTIES - SOVERSION ${${PROJECT_NAME}_SOVERSION} -- INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) -+ ) - - if(APPLE) - set_target_properties(${THIS_BACKEND_TARGET} -diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt -index 3e7deeae..f9eae564 100644 ---- a/src/core/CMakeLists.txt -+++ b/src/core/CMakeLists.txt -@@ -59,7 +59,6 @@ if (SOCI_SHARED) - PROPERTIES - VERSION ${SOCI_VERSION} - SOVERSION ${SOCI_SOVERSION} -- INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib - CLEAN_DIRECT_OUTPUT 1) - endif() - --- -2.25.1 - diff --git a/external/soci/patches/0002-Fix-soci_backend.patch b/external/soci/patches/0002-Fix-soci_backend.patch deleted file mode 100644 index eab3c3763c0..00000000000 --- a/external/soci/patches/0002-Fix-soci_backend.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/cmake/SociBackend.cmake b/cmake/SociBackend.cmake -index 0a664667..3fa2ed95 100644 ---- a/cmake/SociBackend.cmake -+++ b/cmake/SociBackend.cmake -@@ -31,14 +31,13 @@ macro(soci_backend_deps_found NAME DEPS SUCCESS) - if(NOT DEPEND_FOUND) - list(APPEND DEPS_NOT_FOUND ${dep}) - else() -- string(TOUPPER "${dep}" DEPU) -- if( ${DEPU}_INCLUDE_DIR ) -- list(APPEND DEPS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIR}) -+ if( ${dep}_INCLUDE_DIR ) -+ list(APPEND DEPS_INCLUDE_DIRS ${${dep}_INCLUDE_DIR}) - endif() -- if( ${DEPU}_INCLUDE_DIRS ) -- list(APPEND DEPS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIRS}) -+ if( ${dep}_INCLUDE_DIRS ) -+ list(APPEND DEPS_INCLUDE_DIRS ${${dep}_INCLUDE_DIRS}) - endif() -- list(APPEND DEPS_LIBRARIES ${${DEPU}_LIBRARIES}) -+ list(APPEND DEPS_LIBRARIES ${${dep}_LIBRARIES}) - endif() - endforeach() - diff --git a/include/xrpl/basics/Buffer.h b/include/xrpl/basics/Buffer.h index b2f11634525..3379a923f01 100644 --- a/include/xrpl/basics/Buffer.h +++ b/include/xrpl/basics/Buffer.h @@ -25,6 +25,7 @@ #include #include +#include namespace ripple { diff --git a/include/xrpl/basics/Log.h b/include/xrpl/basics/Log.h index 2506b8ea8dd..833907eb9c8 100644 --- a/include/xrpl/basics/Log.h +++ b/include/xrpl/basics/Log.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include diff --git a/include/xrpl/basics/README.md b/include/xrpl/basics/README.md index 544bc8aece7..290bb7ad0c8 100644 --- a/include/xrpl/basics/README.md +++ b/include/xrpl/basics/README.md @@ -4,37 +4,34 @@ Utility functions and classes. 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` - * For ordered containers with most insertions or erases at the end. +- `std::deque` + - For ordered containers with most insertions or erases at the start or end. -* `std::deque` - * For ordered containers with most insertions or erases at the start or end. - -* `std::list` - * 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 +- `std::list` + - 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. -* `std::set` - * For sorted containers. +- `std::set` + - For sorted containers. -* `ripple::hash_set` - * Where inserts and contains need to be O(1). - * For "small" sets, `std::set` might be faster and smaller. +- `ripple::hash_set` + - Where inserts and contains need to be O(1). + - For "small" sets, `std::set` might be faster and smaller. -* `ripple::hardened_hash_set` - * For data sets where the key could be manipulated by an attacker - in an attempt to mount an algorithmic complexity attack: see +- `ripple::hardened_hash_set` + - For data sets where the key could be manipulated by an attacker + in an attempt to mount an algorithmic complexity attack: see http://en.wikipedia.org/wiki/Algorithmic_complexity_attack - The following container is deprecated -* `std::unordered_set` - * Use `ripple::hash_set` instead, which uses a better hashing algorithm. - * Or use `ripple::hardened_hash_set` to prevent algorithmic complexity attacks. +- `std::unordered_set` +- Use `ripple::hash_set` instead, which uses a better hashing algorithm. +- Or use `ripple::hardened_hash_set` to prevent algorithmic complexity attacks. diff --git a/include/xrpl/basics/StringUtilities.h b/include/xrpl/basics/StringUtilities.h index 23d60e2db49..5f905638cb1 100644 --- a/include/xrpl/basics/StringUtilities.h +++ b/include/xrpl/basics/StringUtilities.h @@ -29,7 +29,6 @@ #include #include #include -#include #include namespace ripple { diff --git a/include/xrpl/basics/algorithm.h b/include/xrpl/basics/algorithm.h index ed6e8080d9a..673d5e955b3 100644 --- a/include/xrpl/basics/algorithm.h +++ b/include/xrpl/basics/algorithm.h @@ -20,7 +20,6 @@ #ifndef RIPPLE_ALGORITHM_H_INCLUDED #define RIPPLE_ALGORITHM_H_INCLUDED -#include #include namespace ripple { diff --git a/include/xrpl/basics/hardened_hash.h b/include/xrpl/basics/hardened_hash.h index 0b77b0a07a8..aae6c55dff5 100644 --- a/include/xrpl/basics/hardened_hash.h +++ b/include/xrpl/basics/hardened_hash.h @@ -24,12 +24,8 @@ #include #include -#include #include #include -#include -#include -#include #include namespace ripple { diff --git a/include/xrpl/basics/mulDiv.h b/include/xrpl/basics/mulDiv.h index e338f87c819..96d466f6c7c 100644 --- a/include/xrpl/basics/mulDiv.h +++ b/include/xrpl/basics/mulDiv.h @@ -23,7 +23,6 @@ #include #include #include -#include namespace ripple { auto constexpr muldiv_max = std::numeric_limits::max(); diff --git a/include/xrpl/basics/tagged_integer.h b/include/xrpl/basics/tagged_integer.h index 471fa8eb1e6..ed30b6f120b 100644 --- a/include/xrpl/basics/tagged_integer.h +++ b/include/xrpl/basics/tagged_integer.h @@ -24,10 +24,8 @@ #include -#include #include #include -#include namespace ripple { diff --git a/include/xrpl/beast/clock/abstract_clock.h b/include/xrpl/beast/clock/abstract_clock.h index 128ab82b4bd..7b0f04225fd 100644 --- a/include/xrpl/beast/clock/abstract_clock.h +++ b/include/xrpl/beast/clock/abstract_clock.h @@ -20,9 +20,6 @@ #ifndef BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED #define BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED -#include -#include - namespace beast { /** Abstract interface to a clock. diff --git a/include/xrpl/beast/clock/manual_clock.h b/include/xrpl/beast/clock/manual_clock.h index 32ff76bb073..a0e82b70141 100644 --- a/include/xrpl/beast/clock/manual_clock.h +++ b/include/xrpl/beast/clock/manual_clock.h @@ -23,6 +23,8 @@ #include #include +#include + namespace beast { /** Manual clock implementation. diff --git a/include/xrpl/beast/container/aged_container_utility.h b/include/xrpl/beast/container/aged_container_utility.h index b64cefbf5ad..d315f05346d 100644 --- a/include/xrpl/beast/container/aged_container_utility.h +++ b/include/xrpl/beast/container/aged_container_utility.h @@ -22,6 +22,7 @@ #include +#include #include namespace beast { diff --git a/include/xrpl/beast/container/detail/aged_associative_container.h b/include/xrpl/beast/container/detail/aged_associative_container.h index 5ff7901552f..678fbe4e173 100644 --- a/include/xrpl/beast/container/detail/aged_associative_container.h +++ b/include/xrpl/beast/container/detail/aged_associative_container.h @@ -20,8 +20,6 @@ #ifndef BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED #define BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED -#include - namespace beast { namespace detail { diff --git a/include/xrpl/beast/container/detail/aged_ordered_container.h b/include/xrpl/beast/container/detail/aged_ordered_container.h index 8c978d05173..ef3e1b5ea17 100644 --- a/include/xrpl/beast/container/detail/aged_ordered_container.h +++ b/include/xrpl/beast/container/detail/aged_ordered_container.h @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/include/xrpl/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h index 3b9c83a0149..23200ae007e 100644 --- a/include/xrpl/beast/container/detail/aged_unordered_container.h +++ b/include/xrpl/beast/container/detail/aged_unordered_container.h @@ -3257,7 +3257,6 @@ operator==(aged_unordered_container< { if (size() != other.size()) return false; - using EqRng = std::pair; for (auto iter(cbegin()), last(cend()); iter != last;) { auto const& k(extract(*iter)); diff --git a/include/xrpl/beast/core/LexicalCast.h b/include/xrpl/beast/core/LexicalCast.h index aa67bcad50f..5551e1f2dc1 100644 --- a/include/xrpl/beast/core/LexicalCast.h +++ b/include/xrpl/beast/core/LexicalCast.h @@ -29,11 +29,9 @@ #include #include #include -#include #include #include #include -#include namespace beast { diff --git a/include/xrpl/beast/hash/hash_append.h b/include/xrpl/beast/hash/hash_append.h index 6b11fe1eb32..a4ffeaf30c7 100644 --- a/include/xrpl/beast/hash/hash_append.h +++ b/include/xrpl/beast/hash/hash_append.h @@ -26,12 +26,9 @@ #include #include -#include #include #include -#include #include -#include #include #include #include diff --git a/include/xrpl/beast/hash/xxhasher.h b/include/xrpl/beast/hash/xxhasher.h index 381980902ac..9cd343f5445 100644 --- a/include/xrpl/beast/hash/xxhasher.h +++ b/include/xrpl/beast/hash/xxhasher.h @@ -24,32 +24,110 @@ #include +#include #include -#include -#include +#include +#include +#include namespace beast { class xxhasher { +public: + using result_type = std::size_t; + private: - // requires 64-bit std::size_t - static_assert(sizeof(std::size_t) == 8, ""); + static_assert(sizeof(std::size_t) == 8, "requires 64-bit std::size_t"); + // Have an internal buffer to avoid the streaming API + // A 64-byte buffer should to be big enough for us + static constexpr std::size_t INTERNAL_BUFFER_SIZE = 64; - XXH3_state_t* state_; + alignas(64) std::array buffer_; + std::span readBuffer_; + std::span writeBuffer_; + + std::optional seed_; + XXH3_state_t* state_ = nullptr; + + void + resetBuffers() + { + writeBuffer_ = std::span{buffer_}; + readBuffer_ = {}; + } + + void + updateHash(void const* data, std::size_t len) + { + if (writeBuffer_.size() < len) + { + flushToState(data, len); + } + else + { + std::memcpy(writeBuffer_.data(), data, len); + writeBuffer_ = writeBuffer_.subspan(len); + readBuffer_ = std::span{ + std::begin(buffer_), buffer_.size() - writeBuffer_.size()}; + } + } static XXH3_state_t* allocState() { auto ret = XXH3_createState(); if (ret == nullptr) - throw std::bad_alloc(); + throw std::bad_alloc(); // LCOV_EXCL_LINE return ret; } -public: - using result_type = std::size_t; + void + flushToState(void const* data, std::size_t len) + { + if (!state_) + { + state_ = allocState(); + if (seed_.has_value()) + { + XXH3_64bits_reset_withSeed(state_, *seed_); + } + else + { + XXH3_64bits_reset(state_); + } + } + XXH3_64bits_update(state_, readBuffer_.data(), readBuffer_.size()); + resetBuffers(); + if (data && len) + { + XXH3_64bits_update(state_, data, len); + } + } + result_type + retrieveHash() + { + if (state_) + { + flushToState(nullptr, 0); + return XXH3_64bits_digest(state_); + } + else + { + if (seed_.has_value()) + { + return XXH3_64bits_withSeed( + readBuffer_.data(), readBuffer_.size(), *seed_); + } + else + { + return XXH3_64bits(readBuffer_.data(), readBuffer_.size()); + } + } + } + +public: static constexpr auto const endian = boost::endian::order::native; xxhasher(xxhasher const&) = delete; @@ -58,43 +136,43 @@ class xxhasher xxhasher() { - state_ = allocState(); - XXH3_64bits_reset(state_); + resetBuffers(); } ~xxhasher() noexcept { - XXH3_freeState(state_); + if (state_) + { + XXH3_freeState(state_); + } } template < class Seed, std::enable_if_t::value>* = nullptr> - explicit xxhasher(Seed seed) + explicit xxhasher(Seed seed) : seed_(seed) { - state_ = allocState(); - XXH3_64bits_reset_withSeed(state_, seed); + resetBuffers(); } template < class Seed, std::enable_if_t::value>* = nullptr> - xxhasher(Seed seed, Seed) + xxhasher(Seed seed, Seed) : seed_(seed) { - state_ = allocState(); - XXH3_64bits_reset_withSeed(state_, seed); + resetBuffers(); } void operator()(void const* key, std::size_t len) noexcept { - XXH3_64bits_update(state_, key, len); + updateHash(key, len); } explicit - operator std::size_t() noexcept + operator result_type() noexcept { - return XXH3_64bits_digest(state_); + return retrieveHash(); } }; diff --git a/include/xrpl/beast/net/IPAddress.h b/include/xrpl/beast/net/IPAddress.h index 62469cfda1b..fb5dac90ece 100644 --- a/include/xrpl/beast/net/IPAddress.h +++ b/include/xrpl/beast/net/IPAddress.h @@ -29,11 +29,7 @@ #include #include -#include -#include -#include #include -#include //------------------------------------------------------------------------------ diff --git a/include/xrpl/beast/net/IPAddressV4.h b/include/xrpl/beast/net/IPAddressV4.h index 98a92dba207..c65adae05b1 100644 --- a/include/xrpl/beast/net/IPAddressV4.h +++ b/include/xrpl/beast/net/IPAddressV4.h @@ -24,12 +24,6 @@ #include -#include -#include -#include -#include -#include - namespace beast { namespace IP { diff --git a/include/xrpl/beast/net/IPAddressV6.h b/include/xrpl/beast/net/IPAddressV6.h index 4a4ef73b86e..9e24b228e59 100644 --- a/include/xrpl/beast/net/IPAddressV6.h +++ b/include/xrpl/beast/net/IPAddressV6.h @@ -24,12 +24,6 @@ #include -#include -#include -#include -#include -#include - namespace beast { namespace IP { diff --git a/include/xrpl/beast/net/IPEndpoint.h b/include/xrpl/beast/net/IPEndpoint.h index 345ba4b8da9..8d43eb0ba9e 100644 --- a/include/xrpl/beast/net/IPEndpoint.h +++ b/include/xrpl/beast/net/IPEndpoint.h @@ -25,7 +25,6 @@ #include #include -#include #include #include diff --git a/include/xrpl/beast/rfc2616.h b/include/xrpl/beast/rfc2616.h index 648fbc22e2f..d6b3fa3cda8 100644 --- a/include/xrpl/beast/rfc2616.h +++ b/include/xrpl/beast/rfc2616.h @@ -28,10 +28,8 @@ #include #include -#include #include #include -#include #include namespace beast { diff --git a/include/xrpl/beast/test/yield_to.h b/include/xrpl/beast/test/yield_to.h index 9e9f83b8974..27a3a2db209 100644 --- a/include/xrpl/beast/test/yield_to.h +++ b/include/xrpl/beast/test/yield_to.h @@ -13,7 +13,6 @@ #include #include -#include #include #include #include diff --git a/include/xrpl/beast/unit_test/reporter.h b/include/xrpl/beast/unit_test/reporter.h index e7a7d4b3adf..0054daab988 100644 --- a/include/xrpl/beast/unit_test/reporter.h +++ b/include/xrpl/beast/unit_test/reporter.h @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/include/xrpl/beast/unit_test/runner.h b/include/xrpl/beast/unit_test/runner.h index 283f7c87238..977cc45035a 100644 --- a/include/xrpl/beast/unit_test/runner.h +++ b/include/xrpl/beast/unit_test/runner.h @@ -13,7 +13,6 @@ #include #include -#include #include namespace beast { diff --git a/include/xrpl/beast/utility/rngfill.h b/include/xrpl/beast/utility/rngfill.h index 0188e5c5294..e1b47618ba4 100644 --- a/include/xrpl/beast/utility/rngfill.h +++ b/include/xrpl/beast/utility/rngfill.h @@ -31,36 +31,28 @@ namespace beast { template void -rngfill(void* buffer, std::size_t bytes, Generator& g) +rngfill(void* const buffer, std::size_t const bytes, Generator& g) { using result_type = typename Generator::result_type; + constexpr std::size_t result_size = sizeof(result_type); - while (bytes >= sizeof(result_type)) + std::uint8_t* const buffer_start = static_cast(buffer); + std::size_t const complete_iterations = bytes / result_size; + std::size_t const bytes_remaining = bytes % result_size; + + for (std::size_t count = 0; count < complete_iterations; ++count) { - auto const v = g(); - std::memcpy(buffer, &v, sizeof(v)); - buffer = reinterpret_cast(buffer) + sizeof(v); - bytes -= sizeof(v); + result_type const v = g(); + std::size_t const offset = count * result_size; + std::memcpy(buffer_start + offset, &v, result_size); } - XRPL_ASSERT( - bytes < sizeof(result_type), "beast::rngfill(void*) : maximum bytes"); - -#ifdef __GNUC__ - // gcc 11.1 (falsely) warns about an array-bounds overflow in release mode. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" -#endif - - if (bytes > 0) + if (bytes_remaining > 0) { - auto const v = g(); - std::memcpy(buffer, &v, bytes); + result_type const v = g(); + std::size_t const offset = complete_iterations * result_size; + std::memcpy(buffer_start + offset, &v, bytes_remaining); } - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif } template < diff --git a/include/xrpl/json/json_value.h b/include/xrpl/json/json_value.h index 2e815b79f2e..272d12d680d 100644 --- a/include/xrpl/json/json_value.h +++ b/include/xrpl/json/json_value.h @@ -26,7 +26,6 @@ #include #include #include -#include #include /** \brief JSON (JavaScript Object Notation). diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/README.md b/include/xrpl/proto/org/xrpl/rpc/v1/README.md index 9268439847d..e9b9b558417 100644 --- a/include/xrpl/proto/org/xrpl/rpc/v1/README.md +++ b/include/xrpl/proto/org/xrpl/rpc/v1/README.md @@ -79,4 +79,3 @@ mirror the JSON test as much as possible. Refer to the Protocol Buffers [language guide](https://developers.google.com/protocol-buffers/docs/proto3) for more detailed information about Protocol Buffers. - diff --git a/include/xrpl/protocol/AccountID.h b/include/xrpl/protocol/AccountID.h index 295cf41e4fe..d546346bb42 100644 --- a/include/xrpl/protocol/AccountID.h +++ b/include/xrpl/protocol/AccountID.h @@ -29,7 +29,6 @@ #include #include -#include #include #include diff --git a/include/xrpl/protocol/ApiVersion.h b/include/xrpl/protocol/ApiVersion.h index dd09cf6bd1a..deafafa5130 100644 --- a/include/xrpl/protocol/ApiVersion.h +++ b/include/xrpl/protocol/ApiVersion.h @@ -20,7 +20,6 @@ #ifndef RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED #define RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED -#include #include #include diff --git a/include/xrpl/protocol/ErrorCodes.h b/include/xrpl/protocol/ErrorCodes.h index 9c9319ba42d..f06b927566c 100644 --- a/include/xrpl/protocol/ErrorCodes.h +++ b/include/xrpl/protocol/ErrorCodes.h @@ -169,6 +169,8 @@ enum warning_code_i { warnRPC_AMENDMENT_BLOCKED = 1002, warnRPC_EXPIRED_VALIDATOR_LIST = 1003, // unused = 1004 + warnRPC_FIELDS_DEPRECATED = 2004, // rippled needs to maintain + // compatibility with Clio on this code. }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index a2eb7d8e50a..5844a70eb0f 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -24,7 +24,6 @@ #include -#include #include #include #include @@ -54,6 +53,18 @@ * then change the macro parameter in features.macro to * `VoteBehavior::DefaultYes`. The communication process is beyond * the scope of these instructions. + + * 5) If a supported feature (`Supported::yes`) was _ever_ in a released + * version, it can never be changed back to `Supported::no`, because + * it _may_ still become enabled at any time. This would cause newer + * versions of `rippled` to become amendment blocked. + * Instead, to prevent newer versions from voting on the feature, use + * `VoteBehavior::Obsolete`. Obsolete features can not be voted for + * by any versions of `rippled` built with that setting, but will still + * work correctly if they get enabled. If a feature remains obsolete + * for long enough that _all_ clients that could vote for it are + * amendment blocked, the feature can be removed from the code + * as if it was unsupported. * * * When a feature has been enabled for several years, the conditional code diff --git a/include/xrpl/protocol/FeeUnits.h b/include/xrpl/protocol/FeeUnits.h index c6949a434c1..31a1886b7f1 100644 --- a/include/xrpl/protocol/FeeUnits.h +++ b/include/xrpl/protocol/FeeUnits.h @@ -27,14 +27,9 @@ #include #include -#include -#include #include #include #include -#include -#include -#include namespace ripple { diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index 57c8727ae6c..3e3f2843c15 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -32,6 +32,7 @@ #include #include +#include namespace ripple { diff --git a/include/xrpl/protocol/Issue.h b/include/xrpl/protocol/Issue.h index 83ef337c357..eb4861f59b7 100644 --- a/include/xrpl/protocol/Issue.h +++ b/include/xrpl/protocol/Issue.h @@ -24,9 +24,6 @@ #include #include -#include -#include - namespace ripple { /** A currency issued by an account. diff --git a/include/xrpl/protocol/MultiApiJson.h b/include/xrpl/protocol/MultiApiJson.h index 1e35bdbda23..4a3d0115def 100644 --- a/include/xrpl/protocol/MultiApiJson.h +++ b/include/xrpl/protocol/MultiApiJson.h @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/include/xrpl/protocol/NFTSyntheticSerializer.h b/include/xrpl/protocol/NFTSyntheticSerializer.h index e57b3ff71c9..cb33744485e 100644 --- a/include/xrpl/protocol/NFTSyntheticSerializer.h +++ b/include/xrpl/protocol/NFTSyntheticSerializer.h @@ -28,6 +28,8 @@ namespace ripple { +namespace RPC { + /** Adds common synthetic fields to transaction-related JSON responses @@ -40,6 +42,7 @@ insertNFTSyntheticInJson( TxMeta const&); /** @} */ +} // namespace RPC } // namespace ripple #endif diff --git a/include/xrpl/protocol/Permissions.h b/include/xrpl/protocol/Permissions.h index 8ba53d94d76..67f3eea8d72 100644 --- a/include/xrpl/protocol/Permissions.h +++ b/include/xrpl/protocol/Permissions.h @@ -25,7 +25,6 @@ #include #include #include -#include namespace ripple { /** diff --git a/include/xrpl/protocol/PublicKey.h b/include/xrpl/protocol/PublicKey.h index c68656877c9..9bf01e5cdac 100644 --- a/include/xrpl/protocol/PublicKey.h +++ b/include/xrpl/protocol/PublicKey.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace ripple { diff --git a/include/xrpl/protocol/README.md b/include/xrpl/protocol/README.md index 9864b700ef2..a6e8d249820 100644 --- a/include/xrpl/protocol/README.md +++ b/include/xrpl/protocol/README.md @@ -23,9 +23,9 @@ optional fields easier to read: if it exists, or nothing if it doesn't." This usage of the tilde/bitwise NOT operator is not standard outside of the `rippled` codebase. - - As a consequence of this, `x[~sfFoo] = y[~sfFoo]` - assigns the value of Foo from y to x, including omitting - Foo from x if it doesn't exist in y. + - As a consequence of this, `x[~sfFoo] = y[~sfFoo]` + assigns the value of Foo from y to x, including omitting + Foo from x if it doesn't exist in y. Typically, for things that are guaranteed to exist, you use `x[sfFoo]` and avoid having to deal with a container that may diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h index 9fd4cbf19d5..14497b42222 100644 --- a/include/xrpl/protocol/SOTemplate.h +++ b/include/xrpl/protocol/SOTemplate.h @@ -25,7 +25,6 @@ #include #include -#include #include namespace ripple { diff --git a/include/xrpl/protocol/STBase.h b/include/xrpl/protocol/STBase.h index eec9a979873..3f5a3b57ab0 100644 --- a/include/xrpl/protocol/STBase.h +++ b/include/xrpl/protocol/STBase.h @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/include/xrpl/protocol/STBlob.h b/include/xrpl/protocol/STBlob.h index 80832b2688f..374abd2a7c7 100644 --- a/include/xrpl/protocol/STBlob.h +++ b/include/xrpl/protocol/STBlob.h @@ -27,7 +27,6 @@ #include #include -#include namespace ripple { diff --git a/include/xrpl/protocol/STValidation.h b/include/xrpl/protocol/STValidation.h index 11ec733c01b..2aa74203a2e 100644 --- a/include/xrpl/protocol/STValidation.h +++ b/include/xrpl/protocol/STValidation.h @@ -28,8 +28,6 @@ #include #include -#include -#include #include #include diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index 9c77aa41115..5ea4d3ca962 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -33,7 +33,6 @@ #include #include -#include #include namespace ripple { diff --git a/include/xrpl/protocol/Sign.h b/include/xrpl/protocol/Sign.h index 7e1156ceda7..5aa9fabddc3 100644 --- a/include/xrpl/protocol/Sign.h +++ b/include/xrpl/protocol/Sign.h @@ -25,8 +25,6 @@ #include #include -#include - namespace ripple { /** Sign an STObject diff --git a/include/xrpl/protocol/XChainAttestations.h b/include/xrpl/protocol/XChainAttestations.h index 721950ca9c1..92fd04731d0 100644 --- a/include/xrpl/protocol/XChainAttestations.h +++ b/include/xrpl/protocol/XChainAttestations.h @@ -35,8 +35,6 @@ #include #include -#include -#include #include namespace ripple { diff --git a/include/xrpl/protocol/detail/b58_utils.h b/include/xrpl/protocol/detail/b58_utils.h index 8fc85f390b0..ecd301524fb 100644 --- a/include/xrpl/protocol/detail/b58_utils.h +++ b/include/xrpl/protocol/detail/b58_utils.h @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index 1be0af5d013..e2725d1fc06 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -32,12 +32,15 @@ // If you add an amendment here, then do not forget to increment `numFeatures` // in include/xrpl/protocol/Feature.h. +XRPL_FIX (PriceOracleOrder, Supported::no, VoteBehavior::DefaultNo) +XRPL_FIX (MPTDeliveredAmount, Supported::no, VoteBehavior::DefaultNo) +XRPL_FIX (AMMClawbackRounding, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMv1_3, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(PermissionedDEX, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(Batch, Supported::yes, VoteBehavior::DefaultNo) -XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo) +XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(PermissionDelegation, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo) // Check flags in Credential transactions @@ -94,7 +97,6 @@ XRPL_FEATURE(HardenedValidations, Supported::yes, VoteBehavior::DefaultYe // fix1781: XRPEndpointSteps should be included in the circular payment check XRPL_FIX (1781, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes) -// fixQualityUpperBound should be activated before FlowCross XRPL_FIX (QualityUpperBound, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes) XRPL_FIX (PayChanRecipientOwnerDir, Supported::yes, VoteBehavior::DefaultYes) @@ -112,9 +114,7 @@ XRPL_FIX (1571, Supported::yes, VoteBehavior::DefaultYe XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes) XRPL_FIX (1513, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(FlowCross, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(OwnerPaysFee, Supported::no, VoteBehavior::DefaultNo) // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. @@ -151,3 +151,4 @@ XRPL_RETIRE(fix1201) XRPL_RETIRE(fix1512) XRPL_RETIRE(fix1523) XRPL_RETIRE(fix1528) +XRPL_RETIRE(FlowCross) diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro index 46c6e60db35..11306ee0f52 100644 --- a/include/xrpl/protocol/detail/ledger_entries.macro +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -482,8 +482,7 @@ LEDGER_ENTRY(ltDELEGATE, 0x0083, Delegate, delegate, ({ })) /** A ledger object representing a single asset vault. - - \sa keylet::mptoken + \sa keylet::vault */ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({ {sfPreviousTxnID, soeREQUIRED}, diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index 1d59e718506..89e9a16df5e 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -409,6 +409,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate, Delegation::de {sfTransferFee, soeOPTIONAL}, {sfMaximumAmount, soeOPTIONAL}, {sfMPTokenMetadata, soeOPTIONAL}, + {sfDomainID, soeOPTIONAL}, })) /** This transaction type destroys a MPTokensIssuance instance */ @@ -420,6 +421,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy, Delegation:: TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet, Delegation::delegatable, ({ {sfMPTokenIssuanceID, soeREQUIRED}, {sfHolder, soeOPTIONAL}, + {sfDomainID, soeOPTIONAL}, })) /** This transaction type authorizes a MPToken instance */ @@ -478,7 +480,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, Delegation::delegatable, ({ {sfAsset, soeREQUIRED, soeMPTSupported}, {sfAssetsMaximum, soeOPTIONAL}, {sfMPTokenMetadata, soeOPTIONAL}, - {sfDomainID, soeOPTIONAL}, // PermissionedDomainID + {sfDomainID, soeOPTIONAL}, {sfWithdrawalPolicy, soeOPTIONAL}, {sfData, soeOPTIONAL}, })) @@ -487,7 +489,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, Delegation::delegatable, ({ TRANSACTION(ttVAULT_SET, 66, VaultSet, Delegation::delegatable, ({ {sfVaultID, soeREQUIRED}, {sfAssetsMaximum, soeOPTIONAL}, - {sfDomainID, soeOPTIONAL}, // PermissionedDomainID + {sfDomainID, soeOPTIONAL}, {sfData, soeOPTIONAL}, })) @@ -507,6 +509,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, Delegation::delegatable, ({ {sfVaultID, soeREQUIRED}, {sfAmount, soeREQUIRED, soeMPTSupported}, {sfDestination, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, })) /** This transaction claws back tokens from a vault. */ diff --git a/include/xrpl/protocol/digest.h b/include/xrpl/protocol/digest.h index efec616a0c8..303fbafe4ff 100644 --- a/include/xrpl/protocol/digest.h +++ b/include/xrpl/protocol/digest.h @@ -25,7 +25,6 @@ #include -#include #include namespace ripple { diff --git a/include/xrpl/protocol/json_get_or_throw.h b/include/xrpl/protocol/json_get_or_throw.h index c59b5a71a36..74d1779339c 100644 --- a/include/xrpl/protocol/json_get_or_throw.h +++ b/include/xrpl/protocol/json_get_or_throw.h @@ -10,7 +10,6 @@ #include #include #include -#include namespace Json { struct JsonMissingKeyError : std::exception diff --git a/include/xrpl/resource/Charge.h b/include/xrpl/resource/Charge.h index a75ad326242..ead46ca31fd 100644 --- a/include/xrpl/resource/Charge.h +++ b/include/xrpl/resource/Charge.h @@ -20,7 +20,6 @@ #ifndef RIPPLE_RESOURCE_CHARGE_H_INCLUDED #define RIPPLE_RESOURCE_CHARGE_H_INCLUDED -#include #include namespace ripple { diff --git a/include/xrpl/resource/Gossip.h b/include/xrpl/resource/Gossip.h index 6e2a86ecd7c..3495de5b95b 100644 --- a/include/xrpl/resource/Gossip.h +++ b/include/xrpl/resource/Gossip.h @@ -22,6 +22,8 @@ #include +#include + namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/README.md b/include/xrpl/resource/README.md index 8fed985bfda..253e3c76253 100644 --- a/include/xrpl/resource/README.md +++ b/include/xrpl/resource/README.md @@ -1,4 +1,4 @@ -# Resource::Manager # +# Resource::Manager The ResourceManager module has these responsibilities: @@ -7,7 +7,7 @@ The ResourceManager module has these responsibilities: - Provide an interface to share load information in a cluster. - Warn and/or disconnect endpoints for imposing load. -## Description ## +## Description To prevent monopolization of server resources or attacks on servers, resource consumption is monitored at each endpoint. When consumption @@ -33,44 +33,44 @@ Although RPC connections consume resources, they are transient and cannot be rate limited. It is advised not to expose RPC interfaces to the general public. -## Consumer Types ## +## Consumer Types Consumers are placed into three classifications (as identified by the Resource::Kind enumeration): - - InBound, - - OutBound, and - - Admin +- InBound, +- OutBound, and +- Admin - Each caller determines for itself the classification of the Consumer it is - creating. +Each caller determines for itself the classification of the Consumer it is +creating. -## Resource Loading ## +## Resource Loading It is expected that a client will impose a higher load on the server when it first connects: the client may need to catch up on transactions -it has missed, or get trust lines, or transfer fees. The Manager must +it has missed, or get trust lines, or transfer fees. The Manager must expect this initial peak load, but not allow that high load to continue because over the long term that would unduly stress the server. If a client places a sustained high load on the server, that client -is initially given a warning message. If that high load continues +is initially given a warning message. If that high load continues the Manager may tell the heavily loaded server to drop the connection entirely and not allow re-connection for some amount of time. Each load is monitored by capturing peaks and then decaying those peak values over time: this is implemented by the DecayingSample class. -## Gossip ## +## Gossip Each server in a cluster creates a list of IP addresses of end points -that are imposing a significant load. This list is called Gossip, which -is passed to other nodes in that cluster. Gossip helps individual +that are imposing a significant load. This list is called Gossip, which +is passed to other nodes in that cluster. Gossip helps individual servers in the cluster identify IP addreses that might be unduly loading -the entire cluster. Again the recourse of the individual servers is to +the entire cluster. Again the recourse of the individual servers is to drop connections to those IP addresses that occur commonly in the gossip. -## Access ## +## Access In rippled, the Application holds a unique instance of Resource::Manager, which may be retrieved by calling the method diff --git a/include/xrpl/server/detail/BaseHTTPPeer.h b/include/xrpl/server/detail/BaseHTTPPeer.h index 51ac866e1e7..b065a97cf0e 100644 --- a/include/xrpl/server/detail/BaseHTTPPeer.h +++ b/include/xrpl/server/detail/BaseHTTPPeer.h @@ -41,7 +41,6 @@ #include #include #include -#include #include namespace ripple { diff --git a/include/xrpl/server/detail/Door.h b/include/xrpl/server/detail/Door.h index 90de885579d..88e19db8cd1 100644 --- a/include/xrpl/server/detail/Door.h +++ b/include/xrpl/server/detail/Door.h @@ -37,10 +37,8 @@ #include #include -#include #include #include -#include namespace ripple { diff --git a/include/xrpl/server/detail/io_list.h b/include/xrpl/server/detail/io_list.h index fbf60c9a7fc..fba8b28f87a 100644 --- a/include/xrpl/server/detail/io_list.h +++ b/include/xrpl/server/detail/io_list.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/src/libxrpl/basics/FileUtilities.cpp b/src/libxrpl/basics/FileUtilities.cpp index 291eb43c7bc..ffb97926146 100644 --- a/src/libxrpl/basics/FileUtilities.cpp +++ b/src/libxrpl/basics/FileUtilities.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -55,7 +56,7 @@ getFileContents( return {}; } - ifstream fileStream(fullPath, std::ios::in); + std::ifstream fileStream(fullPath.string(), std::ios::in); if (!fileStream) { @@ -85,7 +86,8 @@ writeFileContents( using namespace boost::filesystem; using namespace boost::system::errc; - ofstream fileStream(destPath, std::ios::out | std::ios::trunc); + std::ofstream fileStream( + destPath.string(), std::ios::out | std::ios::trunc); if (!fileStream) { diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 4cb6fbfd363..d5077aa44d9 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -36,7 +36,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.5.0" +char const* const versionString = "2.6.0" // clang-format on #if defined(DEBUG) || defined(SANITIZER) diff --git a/src/libxrpl/protocol/NFTSyntheticSerializer.cpp b/src/libxrpl/protocol/NFTSyntheticSerializer.cpp index 0c0a657512d..64fa9319de7 100644 --- a/src/libxrpl/protocol/NFTSyntheticSerializer.cpp +++ b/src/libxrpl/protocol/NFTSyntheticSerializer.cpp @@ -28,6 +28,7 @@ #include namespace ripple { +namespace RPC { void insertNFTSyntheticInJson( @@ -39,4 +40,5 @@ insertNFTSyntheticInJson( insertNFTokenOfferID(response[jss::meta], transaction, transactionMeta); } +} // namespace RPC } // namespace ripple diff --git a/src/libxrpl/protocol/PublicKey.cpp b/src/libxrpl/protocol/PublicKey.cpp index cdf646e0f86..54b50c80ef1 100644 --- a/src/libxrpl/protocol/PublicKey.cpp +++ b/src/libxrpl/protocol/PublicKey.cpp @@ -107,8 +107,9 @@ sliceToHex(Slice const& slice) } for (int i = 0; i < slice.size(); ++i) { - s += "0123456789ABCDEF"[((slice[i] & 0xf0) >> 4)]; - s += "0123456789ABCDEF"[((slice[i] & 0x0f) >> 0)]; + constexpr char hex[] = "0123456789ABCDEF"; + s += hex[((slice[i] & 0xf0) >> 4)]; + s += hex[((slice[i] & 0x0f) >> 0)]; } return s; } diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index 615012dba4d..8be8f906a5e 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -671,12 +671,12 @@ isMemoOkay(STObject const& st, std::string& reason) "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"); - for (char c : symbols) + for (unsigned char c : symbols) a[c] = 1; return a; }(); - for (auto c : *optData) + for (unsigned char c : *optData) { if (!allowedSymbols[c]) { diff --git a/src/libxrpl/protocol/TxMeta.cpp b/src/libxrpl/protocol/TxMeta.cpp index 2083fc8eaf3..2343a6a7949 100644 --- a/src/libxrpl/protocol/TxMeta.cpp +++ b/src/libxrpl/protocol/TxMeta.cpp @@ -185,6 +185,18 @@ TxMeta::getAffectedAccounts() const { auto issuer = lim->getIssuer(); + if (issuer.isNonZero()) + list.insert(issuer); + } + } + else if (field.getFName() == sfMPTokenIssuanceID) + { + auto mptID = + dynamic_cast const*>(&field); + if (mptID != nullptr) + { + auto issuer = MPTIssue(mptID->value()).getIssuer(); + if (issuer.isNonZero()) list.insert(issuer); } diff --git a/src/libxrpl/protocol/tokens.cpp b/src/libxrpl/protocol/tokens.cpp index a822b1937fb..52cffd7a5cb 100644 --- a/src/libxrpl/protocol/tokens.cpp +++ b/src/libxrpl/protocol/tokens.cpp @@ -544,7 +544,7 @@ b58_to_b256_be(std::string_view input, std::span out) XRPL_ASSERT( num_b_58_10_coeffs <= b_58_10_coeff.size(), "ripple::b58_fast::detail::b58_to_b256_be : maximum coeff"); - for (auto c : input.substr(0, partial_coeff_len)) + for (unsigned char c : input.substr(0, partial_coeff_len)) { auto cur_val = ::ripple::alphabetReverse[c]; if (cur_val < 0) @@ -558,7 +558,7 @@ b58_to_b256_be(std::string_view input, std::span out) { for (int j = 0; j < num_full_coeffs; ++j) { - auto c = input[partial_coeff_len + j * 10 + i]; + unsigned char c = input[partial_coeff_len + j * 10 + i]; auto cur_val = ::ripple::alphabetReverse[c]; if (cur_val < 0) { diff --git a/src/test/README.md b/src/test/README.md index 7d342f24bf3..b012607f588 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -1,4 +1,3 @@ - # Unit Tests ## Running Tests @@ -12,13 +11,13 @@ just `NoRippleCheckLimits`). More than one suite or group of suites can be specified as a comma separated list via the argument. For example, `--unittest=beast,OversizeMeta` will run all suites in the `beast` library (root identifier) as well as the test suite -named `OversizeMeta`). All name matches are case sensitive. +named `OversizeMeta`). All name matches are case sensitive. Tests can be executed in parallel using several child processes by specifying the `--unittest-jobs=N` parameter. The default behavior is to execute serially using a single process. -The order that suites are executed is determined by the suite priority that +The order that suites are executed is determined by the suite priority that is optionally specified when the suite is declared in the code with one of the `BEAST_DEFINE_TESTSUITE` macros. By default, suites have a priority of 0, and other suites can choose to declare an integer priority value to make themselves diff --git a/src/test/app/AMMClawback_test.cpp b/src/test/app/AMMClawback_test.cpp index 77e908d5fe4..95649116640 100644 --- a/src/test/app/AMMClawback_test.cpp +++ b/src/test/app/AMMClawback_test.cpp @@ -17,26 +17,25 @@ #include #include -#include -#include +#include -#include +#include -#include +#include namespace ripple { namespace test { -class AMMClawback_test : public jtx::AMMTest +class AMMClawback_test : public beast::unit_test::suite { void - testInvalidRequest(FeatureBitset features) + testInvalidRequest() { testcase("test invalid request"); using namespace jtx; // Test if holder does not exist. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(100000), gw, alice); @@ -47,8 +46,9 @@ class AMMClawback_test : public jtx::AMMTest env.close(); env.require(flags(gw, asfAllowTrustLineClawback)); + auto const USD = gw["USD"]; env.trust(USD(10000), alice); - env(pay(gw, alice, gw["USD"](100))); + env(pay(gw, alice, USD(100))); AMM amm(env, alice, XRP(100), USD(100)); env.close(); @@ -61,7 +61,7 @@ class AMMClawback_test : public jtx::AMMTest // Test if asset pair provided does not exist. This should // return terNO_AMM error. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(100000), gw, alice); @@ -87,14 +87,14 @@ class AMMClawback_test : public jtx::AMMTest // The AMM account does not exist at all now. // It should return terNO_AMM error. - env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), + env(amm::ammClawback(gw, alice, USD, gw["EUR"], std::nullopt), ter(terNO_AMM)); } // Test if the issuer field and holder field is the same. This should // return temMALFORMED error. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(10000), gw, alice); @@ -124,7 +124,7 @@ class AMMClawback_test : public jtx::AMMTest // Test if the Asset field matches the Account field. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(10000), gw, alice); @@ -156,7 +156,7 @@ class AMMClawback_test : public jtx::AMMTest // Test if the Amount field matches the Asset field. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(10000), gw, alice); @@ -189,7 +189,7 @@ class AMMClawback_test : public jtx::AMMTest // Test if the Amount is invalid, which is less than zero. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(10000), gw, alice); @@ -230,7 +230,7 @@ class AMMClawback_test : public jtx::AMMTest // Test if the issuer did not set asfAllowTrustLineClawback, AMMClawback // transaction is prohibited. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(10000), gw, alice); @@ -241,7 +241,7 @@ class AMMClawback_test : public jtx::AMMTest env.trust(USD(1000), alice); env(pay(gw, alice, USD(100))); env.close(); - env.require(balance(alice, gw["USD"](100))); + env.require(balance(alice, USD(100))); env.require(balance(gw, alice["USD"](-100))); // gw creates AMM pool of XRP/USD. @@ -255,7 +255,7 @@ class AMMClawback_test : public jtx::AMMTest // Test invalid flag. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(10000), gw, alice); @@ -283,7 +283,7 @@ class AMMClawback_test : public jtx::AMMTest // Test if tfClawTwoAssets is set when the two assets in the AMM pool // are not issued by the same issuer. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(10000), gw, alice); @@ -314,7 +314,7 @@ class AMMClawback_test : public jtx::AMMTest // Test clawing back XRP is being prohibited. { - Env env(*this, features); + Env env(*this); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(1000000), gw, alice); @@ -400,7 +400,7 @@ class AMMClawback_test : public jtx::AMMTest env(pay(gw, alice, USD(3000))); env.close(); env.require(balance(gw, alice["USD"](-3000))); - env.require(balance(alice, gw["USD"](3000))); + env.require(balance(alice, USD(3000))); // gw2 issues 3000 EUR to Alice. auto const EUR = gw2["EUR"]; @@ -408,7 +408,7 @@ class AMMClawback_test : public jtx::AMMTest env(pay(gw2, alice, EUR(3000))); env.close(); env.require(balance(gw2, alice["EUR"](-3000))); - env.require(balance(alice, gw2["EUR"](3000))); + env.require(balance(alice, EUR(3000))); // Alice creates AMM pool of EUR/USD. AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); @@ -426,13 +426,13 @@ class AMMClawback_test : public jtx::AMMTest // USD into the pool, then she has 1000 USD. And 1000 USD was clawed // back from the AMM pool, so she still has 1000 USD. env.require(balance(gw, alice["USD"](-1000))); - env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, USD(1000))); // Alice's initial balance for EUR is 3000 EUR. Alice deposited 1000 // EUR into the pool, 500 EUR was withdrawn proportionally. So she // has 2500 EUR now. env.require(balance(gw2, alice["EUR"](-2500))); - env.require(balance(alice, gw2["EUR"](2500))); + env.require(balance(alice, EUR(2500))); // 1000 USD and 500 EUR was withdrawn from the AMM pool, so the // current balance is 1000 USD and 500 EUR. @@ -452,12 +452,12 @@ class AMMClawback_test : public jtx::AMMTest // Alice should still has 1000 USD because gw clawed back from the // AMM pool. env.require(balance(gw, alice["USD"](-1000))); - env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, USD(1000))); // Alice should has 3000 EUR now because another 500 EUR was // withdrawn. env.require(balance(gw2, alice["EUR"](-3000))); - env.require(balance(alice, gw2["EUR"](3000))); + env.require(balance(alice, EUR(3000))); // amm is automatically deleted. BEAST_EXPECT(!amm.ammExists()); @@ -483,7 +483,7 @@ class AMMClawback_test : public jtx::AMMTest env(pay(gw, alice, USD(3000))); env.close(); env.require(balance(gw, alice["USD"](-3000))); - env.require(balance(alice, gw["USD"](3000))); + env.require(balance(alice, USD(3000))); // Alice creates AMM pool of XRP/USD. AMM amm(env, alice, XRP(1000), USD(2000), ter(tesSUCCESS)); @@ -503,11 +503,12 @@ class AMMClawback_test : public jtx::AMMTest // USD into the pool, then she has 1000 USD. And 1000 USD was clawed // back from the AMM pool, so she still has 1000 USD. env.require(balance(gw, alice["USD"](-1000))); - env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, USD(1000))); // Alice will get 500 XRP back. BEAST_EXPECT( expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(500))); + aliceXrpBalance = env.balance(alice, XRP); // 1000 USD and 500 XRP was withdrawn from the AMM pool, so the // current balance is 1000 USD and 500 XRP. @@ -527,11 +528,11 @@ class AMMClawback_test : public jtx::AMMTest // Alice should still has 1000 USD because gw clawed back from the // AMM pool. env.require(balance(gw, alice["USD"](-1000))); - env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, USD(1000))); - // Alice will get another 1000 XRP back. + // Alice will get another 500 XRP back. BEAST_EXPECT( - expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); + expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(500))); // amm is automatically deleted. BEAST_EXPECT(!amm.ammExists()); @@ -568,14 +569,14 @@ class AMMClawback_test : public jtx::AMMTest env.trust(USD(100000), alice); env(pay(gw, alice, USD(6000))); env.close(); - env.require(balance(alice, gw["USD"](6000))); + env.require(balance(alice, USD(6000))); // gw2 issues 6000 EUR to Alice. auto const EUR = gw2["EUR"]; env.trust(EUR(100000), alice); env(pay(gw2, alice, EUR(6000))); env.close(); - env.require(balance(alice, gw2["EUR"](6000))); + env.require(balance(alice, EUR(6000))); // Alice creates AMM pool of EUR/USD AMM amm(env, alice, EUR(5000), USD(4000), ter(tesSUCCESS)); @@ -596,12 +597,12 @@ class AMMClawback_test : public jtx::AMMTest // Alice's initial balance for USD is 6000 USD. Alice deposited 4000 // USD into the pool, then she has 2000 USD. And 1000 USD was clawed // back from the AMM pool, so she still has 2000 USD. - env.require(balance(alice, gw["USD"](2000))); + env.require(balance(alice, USD(2000))); // Alice's initial balance for EUR is 6000 EUR. Alice deposited 5000 // EUR into the pool, 1250 EUR was withdrawn proportionally. So she // has 2500 EUR now. - env.require(balance(alice, gw2["EUR"](2250))); + env.require(balance(alice, EUR(2250))); // 1000 USD and 1250 EUR was withdrawn from the AMM pool, so the // current balance is 3000 USD and 3750 EUR. @@ -627,7 +628,7 @@ class AMMClawback_test : public jtx::AMMTest // Alice should still has 2000 USD because gw clawed back from the // AMM pool. - env.require(balance(alice, gw["USD"](2000))); + env.require(balance(alice, USD(2000))); if (!features[fixAMMv1_3]) BEAST_EXPECT(amm.expectBalances( @@ -650,23 +651,32 @@ class AMMClawback_test : public jtx::AMMTest env.close(); // Another 1 USD / 1.25 EUR was withdrawn. - env.require(balance(alice, gw["USD"](2000))); + env.require(balance(alice, USD(2000))); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2499000000000002), -12}, STAmount{EUR, UINT64_C(3123750000000002), -12}, IOUAmount{2793966937885989, -12})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(2499), EUR(3123.75), IOUAmount{2793966937885987, -12})); + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(2499000000000001), -12}, + STAmount{EUR, UINT64_C(3123750000000001), -12}, + IOUAmount{2793966937885988, -12})); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT( env.balance(alice, EUR) == - STAmount(EUR, UINT64_C(2'876'249999999998), -12)); - else + STAmount(EUR, UINT64_C(2876'249999999998), -12)); + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(env.balance(alice, EUR) == EUR(2876.25)); + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT( + env.balance(alice, EUR) == + STAmount(EUR, UINT64_C(2876'249999999999), -12)); // gw clawback 4000 USD, exceeding the current balance. We // will clawback all. @@ -674,7 +684,7 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw["USD"](2000))); + env.require(balance(alice, USD(2000))); // All alice's EUR in the pool goes back to alice. BEAST_EXPECT( @@ -745,6 +755,7 @@ class AMMClawback_test : public jtx::AMMTest else BEAST_EXPECT(amm2.expectBalances( EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9})); + amm2.deposit(alice, EUR(1000), XRP(3000)); if (!features[fixAMMv1_3]) BEAST_EXPECT(amm2.expectBalances( @@ -752,6 +763,7 @@ class AMMClawback_test : public jtx::AMMTest else BEAST_EXPECT(amm2.expectBalances( EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9})); + amm2.deposit(bob, EUR(1000), XRP(3000)); if (!features[fixAMMv1_3]) BEAST_EXPECT(amm2.expectBalances( @@ -772,27 +784,42 @@ class AMMClawback_test : public jtx::AMMTest // Alice's initial balance for USD is 6000 USD. Alice deposited 1000 // USD into the pool, then she has 5000 USD. And 500 USD was clawed // back from the AMM pool, so she still has 5000 USD. - env.require(balance(alice, gw["USD"](5000))); + env.require(balance(alice, USD(5000))); // Bob's balance is not changed. - env.require(balance(bob, gw["USD"](4000))); + env.require(balance(bob, USD(4000))); // Alice gets 1000 XRP back. - BEAST_EXPECT( - expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); + if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT(expectLedgerEntryRoot( + env, alice, aliceXrpBalance + XRP(1000) - XRPAmount(1))); + else + BEAST_EXPECT(expectLedgerEntryRoot( + env, alice, aliceXrpBalance + XRP(1000))); + aliceXrpBalance = env.balance(alice, XRP); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(2500), XRP(5000), IOUAmount{3535533905932738, -9})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(2500), XRP(5000), IOUAmount{3535533905932737, -9})); - if (!features[fixAMMv1_3]) + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT(amm.expectBalances( + USD(2500), + XRPAmount(5000000001), + IOUAmount{3'535'533'905932738, -9})); + + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectLPTokens( alice, IOUAmount{7071067811865480, -10})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectLPTokens( alice, IOUAmount{7071067811865474, -10})); + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{707106781186548, -9})); + BEAST_EXPECT( amm.expectLPTokens(bob, IOUAmount{1414213562373095, -9})); @@ -800,50 +827,79 @@ class AMMClawback_test : public jtx::AMMTest env(amm::ammClawback(gw, bob, USD, XRP, USD(10)), ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw["USD"](5000))); - env.require(balance(bob, gw["USD"](4000))); + env.require(balance(alice, USD(5000))); + env.require(balance(bob, USD(4000))); // Bob gets 20 XRP back. BEAST_EXPECT( expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(20))); - if (!features[fixAMMv1_3]) + bobXrpBalance = env.balance(bob, XRP); + + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2490000000000001), -12}, XRP(4980), IOUAmount{3521391770309008, -9})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(2'490), XRP(4980), IOUAmount{3521391770309006, -9})); - if (!features[fixAMMv1_3]) + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(2490000000000001), -12}, + XRPAmount(4980000001), + IOUAmount{3521391'770309008, -9})); + + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectLPTokens( alice, IOUAmount{7071067811865480, -10})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectLPTokens( alice, IOUAmount{7071067811865474, -10})); - if (!features[fixAMMv1_3]) + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{707106781186548, -9})); + + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT( amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT( amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9})); + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT( + amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); // gw2 clawback 200 EUR from amm2. env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(200)), ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw2["EUR"](4000))); - env.require(balance(bob, gw2["EUR"](3000))); + env.require(balance(alice, EUR(4000))); + env.require(balance(bob, EUR(3000))); - // Alice gets 600 XRP back. - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(1000) + XRP(600))); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + BEAST_EXPECT(expectLedgerEntryRoot( + env, alice, aliceXrpBalance + XRP(600))); + else if (!features[fixAMMClawbackRounding]) + BEAST_EXPECT(expectLedgerEntryRoot( + env, alice, aliceXrpBalance + XRP(600))); + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT(expectLedgerEntryRoot( + env, alice, aliceXrpBalance + XRP(600) - XRPAmount{1})); + aliceXrpBalance = env.balance(alice, XRP); + + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm2.expectBalances( EUR(2800), XRP(8400), IOUAmount{4849742261192859, -9})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm2.expectBalances( EUR(2800), XRP(8400), IOUAmount{4849742261192856, -9})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT(amm2.expectBalances( + EUR(2800), + XRPAmount(8400000001), + IOUAmount{4849742261192856, -9})); + if (!features[fixAMMv1_3]) BEAST_EXPECT(amm2.expectLPTokens( alice, IOUAmount{1385640646055103, -9})); @@ -864,38 +920,47 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw["USD"](5000))); - env.require(balance(bob, gw["USD"](4000))); + env.require(balance(alice, USD(5000))); + env.require(balance(bob, USD(4000))); // Alice gets 1000 XRP back. - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000))); - else + env, alice, aliceXrpBalance + XRP(1000))); + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) - - XRPAmount{1})); + env, alice, aliceXrpBalance + XRP(1000) - XRPAmount{1})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT(expectLedgerEntryRoot( + env, alice, aliceXrpBalance + XRP(1000))); + aliceXrpBalance = env.balance(alice, XRP); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT( amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT( amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9})); - if (!features[fixAMMv1_3]) + else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + BEAST_EXPECT( + amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(1990000000000001), -12}, XRP(3980), IOUAmount{2814284989122460, -9})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(1'990), XRPAmount{3'980'000'001}, IOUAmount{2814284989122459, -9})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(1990000000000001), -12}, + XRPAmount{3'980'000'001}, + IOUAmount{2814284989122460, -9})); // gw clawback 1000 USD from bob in amm, which also exceeds bob's // balance in amm. All bob's lptoken in amm will be consumed, which @@ -904,22 +969,14 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw["USD"](5000))); - env.require(balance(bob, gw["USD"](4000))); + env.require(balance(alice, USD(5000))); + env.require(balance(bob, USD(4000))); - if (!features[fixAMMv1_3]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000))); - else - BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) - - XRPAmount{1})); - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, bobXrpBalance + XRP(20) + XRP(1980))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance)); + + BEAST_EXPECT( + expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(1980))); + bobXrpBalance = env.balance(bob, XRP); // Now neither alice nor bob has any lptoken in amm. BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); @@ -932,35 +989,31 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw2["EUR"](4000))); - env.require(balance(bob, gw2["EUR"](3000))); + env.require(balance(alice, EUR(4000))); + env.require(balance(bob, EUR(3000))); // Alice gets another 2400 XRP back, bob's XRP balance remains the // same. - if (!features[fixAMMv1_3]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) + - XRP(2400))); - else - BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) + - XRP(2400) - XRPAmount{1})); - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, bobXrpBalance + XRP(20) + XRP(1980))); + BEAST_EXPECT( + expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(2400))); + + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, bobXrpBalance)); + aliceXrpBalance = env.balance(alice, XRP); // Alice now does not have any lptoken in amm2 BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount(0))); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm2.expectBalances( EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm2.expectBalances( EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT(amm2.expectBalances( + EUR(2000), + XRPAmount(6000000001), + IOUAmount{3464101615137754, -9})); // gw2 claw back 2000 EUR from bob in amm2, which exceeds bob's // balance. All bob's lptokens will be consumed, which corresponds @@ -969,36 +1022,32 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw2["EUR"](4000))); - env.require(balance(bob, gw2["EUR"](3000))); + env.require(balance(alice, EUR(4000))); + env.require(balance(bob, EUR(3000))); // Bob gets another 3000 XRP back. Alice's XRP balance remains the // same. - if (!features[fixAMMv1_3]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) + - XRP(2400))); - else - BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) + - XRP(2400) - XRPAmount{1})); - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, bobXrpBalance + XRP(20) + XRP(1980) + XRP(3000))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance)); + + BEAST_EXPECT( + expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(3000))); + bobXrpBalance = env.balance(bob, XRP); // Neither alice nor bob has any lptoken in amm2 BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount(0))); BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount(0))); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm2.expectBalances( EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm2.expectBalances( EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT(amm2.expectBalances( + EUR(1000), + XRPAmount(3000000001), + IOUAmount{1732050807568877, -9})); } } @@ -1096,12 +1145,12 @@ class AMMClawback_test : public jtx::AMMTest BEAST_EXPECT(amm.expectLPTokens( carol, IOUAmount{1118033988749894, -12})); - env.require(balance(alice, gw["USD"](2000))); - env.require(balance(alice, gw2["EUR"](1000))); - env.require(balance(bob, gw["USD"](3000))); - env.require(balance(bob, gw2["EUR"](2500))); - env.require(balance(carol, gw["USD"](3000))); - env.require(balance(carol, gw2["EUR"](2750))); + env.require(balance(alice, USD(2000))); + env.require(balance(alice, EUR(1000))); + env.require(balance(bob, USD(3000))); + env.require(balance(bob, EUR(2500))); + env.require(balance(carol, USD(3000))); + env.require(balance(carol, EUR(2750))); // gw clawback all the bob's USD in amm. (2000 USD / 2500 EUR) env(amm::ammClawback(gw, bob, USD, EUR, std::nullopt), @@ -1134,8 +1183,8 @@ class AMMClawback_test : public jtx::AMMTest carol, IOUAmount{1118033988749894, -12})); // Bob will get 2500 EUR back. - env.require(balance(alice, gw["USD"](2000))); - env.require(balance(alice, gw2["EUR"](1000))); + env.require(balance(alice, USD(2000))); + env.require(balance(alice, EUR(1000))); BEAST_EXPECT( env.balance(bob, USD) == STAmount(USD, UINT64_C(3000000000000000), -12)); @@ -1148,8 +1197,8 @@ class AMMClawback_test : public jtx::AMMTest BEAST_EXPECT( env.balance(bob, EUR) == STAmount(EUR, UINT64_C(4999999999999999), -12)); - env.require(balance(carol, gw["USD"](3000))); - env.require(balance(carol, gw2["EUR"](2750))); + env.require(balance(carol, USD(3000))); + env.require(balance(carol, EUR(2750))); // gw2 clawback all carol's EUR in amm. (1000 USD / 1250 EUR) env(amm::ammClawback(gw2, carol, EUR, USD, std::nullopt), @@ -1180,8 +1229,8 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(carol, gw2["EUR"](2750))); - env.require(balance(carol, gw["USD"](4000))); + env.require(balance(carol, EUR(2750))); + env.require(balance(carol, USD(4000))); BEAST_EXPECT(!amm.ammExists()); } @@ -1564,11 +1613,20 @@ class AMMClawback_test : public jtx::AMMTest // gw claws back 1000 USD from gw2. env(amm::ammClawback(gw, gw2, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT(amm.expectBalances( - USD(5000), EUR(10000), IOUAmount{7071067811865475, -12})); + if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) + BEAST_EXPECT(amm.expectBalances( + USD(5000), EUR(10000), IOUAmount{7071067811865475, -12})); + else + BEAST_EXPECT(amm.expectBalances( + USD(5000), EUR(10000), IOUAmount{7071067811865474, -12})); BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{1414213562373095, -12})); - BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) + BEAST_EXPECT( + amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + else + BEAST_EXPECT( + amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); BEAST_EXPECT( amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); @@ -1580,22 +1638,37 @@ class AMMClawback_test : public jtx::AMMTest // gw2 claws back 1000 EUR from gw. env(amm::ammClawback(gw2, gw, EUR, USD, EUR(1000)), ter(tesSUCCESS)); env.close(); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(4500), STAmount(EUR, UINT64_C(9000000000000001), -12), IOUAmount{6363961030678928, -12})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(4500), EUR(9000), IOUAmount{6363961030678928, -12})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT(amm.expectBalances( + USD(4500), + STAmount(EUR, UINT64_C(9000000000000001), -12), + IOUAmount{6363961030678927, -12})); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT( amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT( amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13})); - BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT( + amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + + if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) + BEAST_EXPECT( + amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + else + BEAST_EXPECT( + amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); + BEAST_EXPECT( amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); @@ -1607,22 +1680,36 @@ class AMMClawback_test : public jtx::AMMTest // gw2 claws back 4000 EUR from alice. env(amm::ammClawback(gw2, alice, EUR, USD, EUR(4000)), ter(tesSUCCESS)); env.close(); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(2500), STAmount(EUR, UINT64_C(5000000000000001), -12), IOUAmount{3535533905932738, -12})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( USD(2500), EUR(5000), IOUAmount{3535533905932738, -12})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT(amm.expectBalances( + USD(2500), + STAmount(EUR, UINT64_C(5000000000000001), -12), + IOUAmount{3535533905932737, -12})); - if (!features[fixAMMv1_3]) + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT( amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); - else + else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT( amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13})); - BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + BEAST_EXPECT( + amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + + if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) + BEAST_EXPECT( + amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + else + BEAST_EXPECT( + amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); BEAST_EXPECT( amm.expectLPTokens(alice, IOUAmount{1414213562373095, -12})); @@ -1689,14 +1776,14 @@ class AMMClawback_test : public jtx::AMMTest env.trust(USD(100000), alice); env(pay(gw, alice, USD(3000))); env.close(); - env.require(balance(alice, gw["USD"](3000))); + env.require(balance(alice, USD(3000))); // gw2 issues 3000 EUR to Alice. auto const EUR = gw2["EUR"]; env.trust(EUR(100000), alice); env(pay(gw2, alice, EUR(3000))); env.close(); - env.require(balance(alice, gw2["EUR"](3000))); + env.require(balance(alice, EUR(3000))); // Alice creates AMM pool of EUR/USD. AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); @@ -1714,8 +1801,8 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw["USD"](1000))); - env.require(balance(alice, gw2["EUR"](2500))); + env.require(balance(alice, USD(1000))); + env.require(balance(alice, EUR(2500))); BEAST_EXPECT(amm.expectBalances( USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); @@ -1731,8 +1818,8 @@ class AMMClawback_test : public jtx::AMMTest // Alice should still has 1000 USD because gw clawed back from the // AMM pool. - env.require(balance(alice, gw["USD"](1000))); - env.require(balance(alice, gw2["EUR"](3000))); + env.require(balance(alice, USD(1000))); + env.require(balance(alice, EUR(3000))); // amm is automatically deleted. BEAST_EXPECT(!amm.ammExists()); @@ -1757,14 +1844,14 @@ class AMMClawback_test : public jtx::AMMTest env.trust(USD(100000), alice); env(pay(gw, alice, USD(3000))); env.close(); - env.require(balance(alice, gw["USD"](3000))); + env.require(balance(alice, USD(3000))); // gw2 issues 3000 EUR to Alice. auto const EUR = gw2["EUR"]; env.trust(EUR(100000), alice); env(pay(gw2, alice, EUR(3000))); env.close(); - env.require(balance(alice, gw2["EUR"](3000))); + env.require(balance(alice, EUR(3000))); // Alice creates AMM pool of EUR/USD. AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); @@ -1783,8 +1870,8 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw["USD"](1000))); - env.require(balance(alice, gw2["EUR"](2500))); + env.require(balance(alice, USD(1000))); + env.require(balance(alice, EUR(2500))); BEAST_EXPECT(amm.expectBalances( USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); BEAST_EXPECT( @@ -1810,14 +1897,14 @@ class AMMClawback_test : public jtx::AMMTest env.trust(USD(100000), alice); env(pay(gw, alice, USD(3000))); env.close(); - env.require(balance(alice, gw["USD"](3000))); + env.require(balance(alice, USD(3000))); // gw2 issues 3000 EUR to Alice. auto const EUR = gw2["EUR"]; env.trust(EUR(100000), alice); env(pay(gw2, alice, EUR(3000))); env.close(); - env.require(balance(alice, gw2["EUR"](3000))); + env.require(balance(alice, EUR(3000))); // Alice creates AMM pool of EUR/USD. AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); @@ -1835,8 +1922,8 @@ class AMMClawback_test : public jtx::AMMTest ter(tesSUCCESS)); env.close(); - env.require(balance(alice, gw["USD"](1000))); - env.require(balance(alice, gw2["EUR"](2500))); + env.require(balance(alice, USD(1000))); + env.require(balance(alice, EUR(2500))); BEAST_EXPECT(amm.expectBalances( USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); BEAST_EXPECT( @@ -1975,10 +2062,11 @@ class AMMClawback_test : public jtx::AMMTest { testcase("test single depoit and clawback"); using namespace jtx; + std::string logs; // Test AMMClawback for USD/XRP pool. Claw back USD, and XRP goes back // to the holder. - Env env(*this, features); + Env env(*this, features, std::make_unique(&logs)); Account gw{"gateway"}; Account alice{"alice"}; env.fund(XRP(1000000000), gw, alice); @@ -1994,7 +2082,7 @@ class AMMClawback_test : public jtx::AMMTest env.trust(USD(100000), alice); env(pay(gw, alice, USD(1000))); env.close(); - env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, USD(1000))); // gw creates AMM pool of XRP/USD. AMM amm(env, gw, XRP(100), USD(400), ter(tesSUCCESS)); @@ -2032,26 +2120,349 @@ class AMMClawback_test : public jtx::AMMTest env, alice, aliceXrpBalance + XRP(29.289321))); } + void + testLastHolderLPTokenBalance(FeatureBitset features) + { + testcase( + "test last holder's lptoken balance not equal to AMM's lptoken " + "balance before clawback"); + using namespace jtx; + std::string logs; + + auto setupAccounts = + [&](Env& env, Account& gw, Account& alice, Account& bob) { + env.fund(XRP(100000), gw, alice, bob); + env.close(); + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(50000))); + env.trust(USD(100000), bob); + env(pay(gw, bob, USD(40000))); + env.close(); + + return USD; + }; + + auto getLPTokenBalances = + [&](auto& env, + auto const& amm, + auto const& account) -> std::pair { + auto const lpToken = + getAccountLines( + env, account, amm.lptIssue())[jss::lines][0u][jss::balance] + .asString(); + auto const lpTokenBalance = + amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value] + .asString(); + return {lpToken, lpTokenBalance}; + }; + + // IOU/XRP pool. AMMClawback almost last holder's USD balance + { + Env env(*this, features, std::make_unique(&logs)); + Account gw{"gateway"}, alice{"alice"}, bob{"bob"}; + auto const USD = setupAccounts(env, gw, alice, bob); + + AMM amm(env, alice, XRP(2), USD(1)); + amm.deposit(alice, IOUAmount{1'876123487565916, -15}); + amm.deposit(bob, IOUAmount{1'000'000}); + amm.withdraw(alice, IOUAmount{1'876123487565916, -15}); + amm.withdrawAll(bob); + + auto [lpToken, lpTokenBalance] = + getLPTokenBalances(env, amm, alice); + BEAST_EXPECT( + lpToken == "1414.21356237366" && + lpTokenBalance == "1414.213562374"); + + auto res = + isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + BEAST_EXPECT(res && res.value()); + + if (!features[fixAMMClawbackRounding] || !features[fixAMMv1_3]) + { + env(amm::ammClawback(gw, alice, USD, XRP, USD(1)), + ter(tecAMM_BALANCE)); + BEAST_EXPECT(amm.ammExists()); + } + else + { + auto const lpBalance = IOUAmount{989, -12}; + env(amm::ammClawback(gw, alice, USD, XRP, USD(1))); + BEAST_EXPECT(amm.expectBalances( + STAmount(USD, UINT64_C(7000000000000000), -28), + XRPAmount(1), + lpBalance)); + BEAST_EXPECT(amm.expectLPTokens(alice, lpBalance)); + } + } + + // IOU/XRP pool. AMMClawback part of last holder's USD balance + { + Env env(*this, features, std::make_unique(&logs)); + Account gw{"gateway"}, alice{"alice"}, bob{"bob"}; + auto const USD = setupAccounts(env, gw, alice, bob); + + AMM amm(env, alice, XRP(2), USD(1)); + amm.deposit(alice, IOUAmount{1'876123487565916, -15}); + amm.deposit(bob, IOUAmount{1'000'000}); + amm.withdrawAll(bob); + + auto [lpToken, lpTokenBalance] = + getLPTokenBalances(env, amm, alice); + BEAST_EXPECT( + lpToken == "1416.08968586066" && + lpTokenBalance == "1416.089685861"); + + auto res = + isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + BEAST_EXPECT(res && res.value()); + + env(amm::ammClawback(gw, alice, USD, XRP, USD(0.5))); + + if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { + BEAST_EXPECT(amm.expectBalances( + STAmount(USD, UINT64_C(5013266196406), -13), + XRPAmount(1002653), + IOUAmount{708'9829046744236, -13})); + } + else if (!features[fixAMMClawbackRounding]) + { + BEAST_EXPECT(amm.expectBalances( + STAmount(USD, UINT64_C(5013266196407), -13), + XRPAmount(1002654), + IOUAmount{708'9829046744941, -13})); + } + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { + auto const lpBalance = IOUAmount{708'9829046743238, -13}; + BEAST_EXPECT(amm.expectBalances( + STAmount(USD, UINT64_C(5013266196406999), -16), + XRPAmount(1002655), + lpBalance)); + BEAST_EXPECT(amm.expectLPTokens(alice, lpBalance)); + } + } + + // IOU/XRP pool. AMMClawback all of last holder's USD balance + { + Env env(*this, features, std::make_unique(&logs)); + Account gw{"gateway"}, alice{"alice"}, bob{"bob"}; + auto const USD = setupAccounts(env, gw, alice, bob); + + AMM amm(env, alice, XRP(2), USD(1)); + amm.deposit(alice, IOUAmount{1'876123487565916, -15}); + amm.deposit(bob, IOUAmount{1'000'000}); + amm.withdraw(alice, IOUAmount{1'876123487565916, -15}); + amm.withdrawAll(bob); + + auto [lpToken, lpTokenBalance] = + getLPTokenBalances(env, amm, alice); + BEAST_EXPECT( + lpToken == "1414.21356237366" && + lpTokenBalance == "1414.213562374"); + + auto res = + isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + BEAST_EXPECT(res && res.value()); + + if (!features[fixAMMClawbackRounding] && !features[fixAMMv1_3]) + { + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), + ter(tecAMM_BALANCE)); + } + else if (!features[fixAMMClawbackRounding]) + { + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt)); + BEAST_EXPECT(amm.expectBalances( + STAmount(USD, UINT64_C(2410000000000000), -28), + XRPAmount(1), + IOUAmount{34, -11})); + } + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt)); + BEAST_EXPECT(!amm.ammExists()); + } + } + + // IOU/IOU pool, different issuers + { + Env env(*this, features, std::make_unique(&logs)); + Account gw{"gateway"}, alice{"alice"}, bob{"bob"}; + auto const USD = setupAccounts(env, gw, alice, bob); + + Account gw2{"gateway2"}; + env.fund(XRP(100000), gw2); + env.close(); + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(50000))); + env.trust(EUR(100000), bob); + env(pay(gw2, bob, EUR(50000))); + env.close(); + + AMM amm(env, alice, USD(2), EUR(1)); + amm.deposit(alice, IOUAmount{1'576123487565916, -15}); + amm.deposit(bob, IOUAmount{1'000}); + amm.withdraw(alice, IOUAmount{1'576123487565916, -15}); + amm.withdrawAll(bob); + + auto [lpToken, lpTokenBalance] = + getLPTokenBalances(env, amm, alice); + BEAST_EXPECT( + lpToken == "1.414213562374011" && + lpTokenBalance == "1.414213562374"); + + auto res = + isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + BEAST_EXPECT(res && res.value()); + + if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt)); + BEAST_EXPECT(!amm.ammExists()); + } + else + { + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), + ter(tecINTERNAL)); + BEAST_EXPECT(amm.ammExists()); + } + } + + // IOU/IOU pool, same issuer + { + Env env(*this, features, std::make_unique(&logs)); + Account gw{"gateway"}, alice{"alice"}, bob{"bob"}; + auto const USD = setupAccounts(env, gw, alice, bob); + + auto const EUR = gw["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw, alice, EUR(50000))); + env.trust(EUR(100000), bob); + env(pay(gw, bob, EUR(50000))); + env.close(); + + AMM amm(env, alice, USD(1), EUR(2)); + amm.deposit(alice, IOUAmount{1'076123487565916, -15}); + amm.deposit(bob, IOUAmount{1'000}); + amm.withdraw(alice, IOUAmount{1'076123487565916, -15}); + amm.withdrawAll(bob); + + auto [lpToken, lpTokenBalance] = + getLPTokenBalances(env, amm, alice); + BEAST_EXPECT( + lpToken == "1.414213562374011" && + lpTokenBalance == "1.414213562374"); + + auto res = + isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + BEAST_EXPECT(res && res.value()); + + if (features[fixAMMClawbackRounding]) + { + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), + txflags(tfClawTwoAssets)); + BEAST_EXPECT(!amm.ammExists()); + } + else + { + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), + txflags(tfClawTwoAssets), + ter(tecINTERNAL)); + BEAST_EXPECT(amm.ammExists()); + } + } + + // IOU/IOU pool, larger asset ratio + { + Env env(*this, features, std::make_unique(&logs)); + Account gw{"gateway"}, alice{"alice"}, bob{"bob"}; + auto const USD = setupAccounts(env, gw, alice, bob); + + auto const EUR = gw["EUR"]; + env.trust(EUR(1000000000), alice); + env(pay(gw, alice, EUR(500000000))); + env.trust(EUR(1000000000), bob); + env(pay(gw, bob, EUR(500000000))); + env.close(); + + AMM amm(env, alice, USD(1), EUR(2000000)); + amm.deposit(alice, IOUAmount{1'076123487565916, -12}); + amm.deposit(bob, IOUAmount{10000}); + amm.withdraw(alice, IOUAmount{1'076123487565916, -12}); + amm.withdrawAll(bob); + + auto [lpToken, lpTokenBalance] = + getLPTokenBalances(env, amm, alice); + + BEAST_EXPECT( + lpToken == "1414.213562373101" && + lpTokenBalance == "1414.2135623731"); + + auto res = + isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + BEAST_EXPECT(res && res.value()); + + if (!features[fixAMMClawbackRounding] && !features[fixAMMv1_3]) + { + env(amm::ammClawback(gw, alice, USD, EUR, USD(1))); + BEAST_EXPECT(amm.expectBalances( + STAmount(USD, UINT64_C(4), -15), + STAmount(EUR, UINT64_C(8), -9), + IOUAmount{6, -12})); + } + else if (!features[fixAMMClawbackRounding]) + { + // sqrt(amount * amount2) >= LPTokens and exceeds the allowed + // tolerance + env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), + ter(tecINVARIANT_FAILED)); + BEAST_EXPECT(amm.ammExists()); + } + else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { + env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), + txflags(tfClawTwoAssets)); + auto const lpBalance = IOUAmount{5, -12}; + BEAST_EXPECT(amm.expectBalances( + STAmount(USD, UINT64_C(4), -15), + STAmount(EUR, UINT64_C(8), -9), + lpBalance)); + BEAST_EXPECT(amm.expectLPTokens(alice, lpBalance)); + } + } + } + void run() override { - FeatureBitset const all{jtx::supported_amendments()}; - testInvalidRequest(all); + FeatureBitset const all{ + jtx::testable_amendments() | fixAMMClawbackRounding}; + + testInvalidRequest(); testFeatureDisabled(all - featureAMMClawback); - testAMMClawbackSpecificAmount(all); - testAMMClawbackExceedBalance(all); - testAMMClawbackExceedBalance(all - fixAMMv1_3); - testAMMClawbackAll(all); - testAMMClawbackAll(all - fixAMMv1_3); - testAMMClawbackSameIssuerAssets(all); - testAMMClawbackSameIssuerAssets(all - fixAMMv1_3); - testAMMClawbackSameCurrency(all); - testAMMClawbackIssuesEachOther(all); - testNotHoldingLptoken(all); - testAssetFrozen(all); - testAssetFrozen(all - fixAMMv1_3); - testSingleDepositAndClawback(all); - testSingleDepositAndClawback(all - fixAMMv1_3); + for (auto const& features : + {all - fixAMMv1_3 - fixAMMClawbackRounding, + all - fixAMMClawbackRounding, + all}) + { + testAMMClawbackSpecificAmount(features); + testAMMClawbackExceedBalance(features); + testAMMClawbackAll(features); + testAMMClawbackSameIssuerAssets(features); + testAMMClawbackSameCurrency(features); + testAMMClawbackIssuesEachOther(features); + testNotHoldingLptoken(features); + testAssetFrozen(features); + testSingleDepositAndClawback(features); + testLastHolderLPTokenBalance(features); + } } }; BEAST_DEFINE_TESTSUITE(AMMClawback, app, ripple); diff --git a/src/test/app/AMMExtended_test.cpp b/src/test/app/AMMExtended_test.cpp index 3d959a6a094..893e9e4f753 100644 --- a/src/test/app/AMMExtended_test.cpp +++ b/src/test/app/AMMExtended_test.cpp @@ -1183,9 +1183,7 @@ struct AMMExtended_test : public jtx::AMMTest using namespace jtx; - // The problem was identified when featureOwnerPaysFee was enabled, - // so make sure that gets included. - Env env{*this, features | featureOwnerPaysFee}; + Env env{*this, features}; // The fee that's charged for transactions. auto const fee = env.current()->fees().base; @@ -1449,7 +1447,7 @@ struct AMMExtended_test : public jtx::AMMTest testOffers() { using namespace jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testRmFundedOffer(all); testRmFundedOffer(all - fixAMMv1_1 - fixAMMv1_3); testEnforceNoRipple(all); @@ -2217,271 +2215,6 @@ struct AMMExtended_test : public jtx::AMMTest } } - void - testTransferRate(FeatureBitset features) - { - testcase("Transfer Rate"); - - using namespace jtx; - - { - // transfer fee on AMM - Env env(*this, features); - - fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(1'000)}); - env(rate(gw, 1.25)); - env.close(); - - AMM ammBob(env, bob, XRP(100), USD(150)); - // no transfer fee on create - BEAST_EXPECT(expectLine(env, bob, USD(1000 - 150))); - - env(pay(alice, carol, USD(50)), path(~USD), sendmax(XRP(50))); - env.close(); - - BEAST_EXPECT(expectLine(env, bob, USD(1'000 - 150))); - BEAST_EXPECT( - ammBob.expectBalances(XRP(150), USD(100), ammBob.tokens())); - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, xrpMinusFee(env, 10'000 - 50))); - BEAST_EXPECT(expectLine(env, carol, USD(1'050))); - } - - { - // Transfer fee AMM and offer - Env env(*this, features); - - fund( - env, - gw, - {alice, bob, carol}, - XRP(10'000), - {USD(1'000), EUR(1'000)}); - env(rate(gw, 1.25)); - env.close(); - - AMM ammBob(env, bob, XRP(100), USD(140)); - BEAST_EXPECT(expectLine(env, bob, USD(1'000 - 140))); - - env(offer(bob, USD(50), EUR(50))); - - // alice buys 40EUR with 40XRP - env(pay(alice, carol, EUR(40)), path(~USD, ~EUR), sendmax(XRP(40))); - - // 40XRP is swapped in for 40USD - BEAST_EXPECT( - ammBob.expectBalances(XRP(140), USD(100), ammBob.tokens())); - // 40USD buys 40EUR via bob's offer. 40EUR delivered to carol - // and bob pays 25% on 40EUR, 40EUR*0.25=10EUR - BEAST_EXPECT(expectLine(env, bob, EUR(1'000 - 40 - 40 * 0.25))); - // bob gets 40USD back from the offer - BEAST_EXPECT(expectLine(env, bob, USD(1'000 - 140 + 40))); - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, xrpMinusFee(env, 10'000 - 40))); - BEAST_EXPECT(expectLine(env, carol, EUR(1'040))); - BEAST_EXPECT(expectOffers(env, bob, 1, {{USD(10), EUR(10)}})); - } - - { - // Transfer fee two consecutive AMM - Env env(*this, features); - - fund( - env, - gw, - {alice, bob, carol}, - XRP(10'000), - {USD(1'000), EUR(1'000)}); - env(rate(gw, 1.25)); - env.close(); - - AMM ammBobXRP_USD(env, bob, XRP(100), USD(140)); - BEAST_EXPECT(expectLine(env, bob, USD(1'000 - 140))); - - AMM ammBobUSD_EUR(env, bob, USD(100), EUR(140)); - BEAST_EXPECT(expectLine(env, bob, EUR(1'000 - 140))); - BEAST_EXPECT(expectLine(env, bob, USD(1'000 - 140 - 100))); - - // alice buys 40EUR with 40XRP - env(pay(alice, carol, EUR(40)), path(~USD, ~EUR), sendmax(XRP(40))); - - // 40XRP is swapped in for 40USD - BEAST_EXPECT(ammBobXRP_USD.expectBalances( - XRP(140), USD(100), ammBobXRP_USD.tokens())); - // 40USD is swapped in for 40EUR - BEAST_EXPECT(ammBobUSD_EUR.expectBalances( - USD(140), EUR(100), ammBobUSD_EUR.tokens())); - // no other charges on bob - BEAST_EXPECT(expectLine(env, bob, USD(1'000 - 140 - 100))); - BEAST_EXPECT(expectLine(env, bob, EUR(1'000 - 140))); - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, xrpMinusFee(env, 10'000 - 40))); - BEAST_EXPECT(expectLine(env, carol, EUR(1'040))); - } - - { - // Payment via AMM with limit quality, deliver less - // than requested - Env env(*this, features); - - fund( - env, - gw, - {alice, bob, carol}, - XRP(1'000), - {USD(1'200), GBP(1'200)}); - env(rate(gw, 1.25)); - env.close(); - - AMM amm(env, bob, GBP(1'000), USD(1'100)); - - // requested quality limit is 90USD/110GBP = 0.8181 - // trade quality is 77.2727USD/94.4444GBP = 0.8181 - env(pay(alice, carol, USD(90)), - path(~USD), - sendmax(GBP(110)), - txflags(tfNoRippleDirect | tfPartialPayment | tfLimitQuality)); - env.close(); - - if (!features[fixAMMv1_1]) - { - // alice buys 77.2727USD with 75.5555GBP and pays 25% tr fee - // on 75.5555GBP - // 1,200 - 75.55555*1.25 = 1200 - 94.4444 = 1105.55555GBP - BEAST_EXPECT(expectLine( - env, - alice, - STAmount{GBP, UINT64_C(1'105'555555555555), -12})); - // 75.5555GBP is swapped in for 77.7272USD - BEAST_EXPECT(amm.expectBalances( - STAmount{GBP, UINT64_C(1'075'555555555556), -12}, - STAmount{USD, UINT64_C(1'022'727272727272), -12}, - amm.tokens())); - } - else - { - // alice buys 77.2727USD with 75.5555GBP and pays 25% tr fee - // on 75.5555GBP - // 1,200 - 75.55555*1.25 = 1200 - 94.4444 = 1105.55555GBP - BEAST_EXPECT(expectLine( - env, - alice, - STAmount{GBP, UINT64_C(1'105'555555555554), -12})); - // 75.5555GBP is swapped in for 77.7272USD - BEAST_EXPECT(amm.expectBalances( - STAmount{GBP, UINT64_C(1'075'555555555557), -12}, - STAmount{USD, UINT64_C(1'022'727272727272), -12}, - amm.tokens())); - } - BEAST_EXPECT(expectLine( - env, carol, STAmount{USD, UINT64_C(1'277'272727272728), -12})); - } - - { - // AMM offer crossing - Env env(*this, features); - - fund(env, gw, {alice, bob}, XRP(1'000), {USD(1'200), EUR(1'200)}); - env(rate(gw, 1.25)); - env.close(); - - AMM amm(env, bob, USD(1'000), EUR(1'150)); - - env(offer(alice, EUR(100), USD(100))); - env.close(); - - if (!features[fixAMMv1_1]) - { - // 95.2380USD is swapped in for 100EUR - BEAST_EXPECT(amm.expectBalances( - STAmount{USD, UINT64_C(1'095'238095238095), -12}, - EUR(1'050), - amm.tokens())); - // alice pays 25% tr fee on 95.2380USD - // 1200-95.2380*1.25 = 1200 - 119.0477 = 1080.9523USD - BEAST_EXPECT(expectLine( - env, - alice, - STAmount{USD, UINT64_C(1'080'952380952381), -12}, - EUR(1'300))); - } - else - { - // 95.2380USD is swapped in for 100EUR - BEAST_EXPECT(amm.expectBalances( - STAmount{USD, UINT64_C(1'095'238095238096), -12}, - EUR(1'050), - amm.tokens())); - // alice pays 25% tr fee on 95.2380USD - // 1200-95.2380*1.25 = 1200 - 119.0477 = 1080.9523USD - BEAST_EXPECT(expectLine( - env, - alice, - STAmount{USD, UINT64_C(1'080'95238095238), -11}, - EUR(1'300))); - } - BEAST_EXPECT(expectOffers(env, alice, 0)); - } - - { - // First pass through a strand redeems, second pass issues, - // through an offer limiting step is not an endpoint - Env env(*this, features); - auto const USDA = alice["USD"]; - auto const USDB = bob["USD"]; - Account const dan("dan"); - - env.fund(XRP(10'000), bob, carol, dan, gw); - fund(env, {alice}, XRP(10'000)); - env(rate(gw, 1.25)); - env.trust(USD(2'000), alice, bob, carol, dan); - env.trust(EUR(2'000), carol, dan); - env.trust(USDA(1'000), bob); - env.trust(USDB(1'000), gw); - env(pay(gw, bob, USD(50))); - env(pay(gw, dan, EUR(1'050))); - env(pay(gw, dan, USD(1'000))); - AMM ammDan(env, dan, USD(1'000), EUR(1'050)); - - if (!features[fixAMMv1_1]) - { - // alice -> bob -> gw -> carol. $50 should have transfer fee; - // $10, no fee - env(pay(alice, carol, EUR(50)), - path(bob, gw, ~EUR), - sendmax(USDA(60)), - txflags(tfNoRippleDirect)); - BEAST_EXPECT(ammDan.expectBalances( - USD(1'050), EUR(1'000), ammDan.tokens())); - BEAST_EXPECT(expectLine(env, dan, USD(0))); - BEAST_EXPECT(expectLine(env, dan, EUR(0))); - BEAST_EXPECT(expectLine(env, bob, USD(-10))); - BEAST_EXPECT(expectLine(env, bob, USDA(60))); - BEAST_EXPECT(expectLine(env, carol, EUR(50))); - } - else - { - // alice -> bob -> gw -> carol. $50 should have transfer fee; - // $10, no fee - env(pay(alice, carol, EUR(50)), - path(bob, gw, ~EUR), - sendmax(USDA(60.1)), - txflags(tfNoRippleDirect)); - BEAST_EXPECT(ammDan.expectBalances( - STAmount{USD, UINT64_C(1'050'000000000001), -12}, - EUR(1'000), - ammDan.tokens())); - BEAST_EXPECT(expectLine(env, dan, USD(0))); - BEAST_EXPECT(expectLine(env, dan, EUR(0))); - BEAST_EXPECT(expectLine( - env, bob, STAmount{USD, INT64_C(-10'000000000001), -12})); - BEAST_EXPECT(expectLine( - env, bob, STAmount{USDA, UINT64_C(60'000000000001), -12})); - BEAST_EXPECT(expectLine(env, carol, EUR(50))); - } - } - } - void testTransferRateNoOwnerFee(FeatureBitset features) { @@ -3090,8 +2823,8 @@ struct AMMExtended_test : public jtx::AMMTest for (auto const withFix : {true, false}) { auto const feats = withFix - ? supported_amendments() - : supported_amendments() - FeatureBitset{fix1781}; + ? testable_amendments() + : testable_amendments() - FeatureBitset{fix1781}; // Payment path starting with XRP Env env(*this, feats); @@ -4056,14 +3789,10 @@ struct AMMExtended_test : public jtx::AMMTest testFlow() { using namespace jtx; - FeatureBitset const all{supported_amendments()}; - FeatureBitset const ownerPaysFee{featureOwnerPaysFee}; + FeatureBitset const all{testable_amendments()}; testFalseDry(all); testBookStep(all); - testBookStep(all | ownerPaysFee); - testTransferRate(all | ownerPaysFee); - testTransferRate((all - fixAMMv1_1 - fixAMMv1_3) | ownerPaysFee); testTransferRateNoOwnerFee(all); testTransferRateNoOwnerFee(all - fixAMMv1_1 - fixAMMv1_3); testLimitQuality(); @@ -4074,7 +3803,7 @@ struct AMMExtended_test : public jtx::AMMTest testCrossingLimits() { using namespace jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testStepLimit(all); testStepLimit(all - fixAMMv1_1 - fixAMMv1_3); } @@ -4083,7 +3812,7 @@ struct AMMExtended_test : public jtx::AMMTest testDeliverMin() { using namespace jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; test_convert_all_of_an_asset(all); test_convert_all_of_an_asset(all - fixAMMv1_1 - fixAMMv1_3); } @@ -4091,7 +3820,7 @@ struct AMMExtended_test : public jtx::AMMTest void testDepositAuth() { - auto const supported{jtx::supported_amendments()}; + auto const supported{jtx::testable_amendments()}; testPayment(supported - featureDepositPreauth); testPayment(supported); testPayIOU(); @@ -4101,7 +3830,7 @@ struct AMMExtended_test : public jtx::AMMTest testFreeze() { using namespace test::jtx; - auto const sa = supported_amendments(); + auto const sa = testable_amendments(); testRippleState(sa); testGlobalFreeze(sa); testOffersWhenFrozen(sa); @@ -4111,7 +3840,7 @@ struct AMMExtended_test : public jtx::AMMTest testMultisign() { using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); testTxMultisign( all - featureMultiSignReserve - featureExpandedSignerList); @@ -4123,7 +3852,7 @@ struct AMMExtended_test : public jtx::AMMTest testPayStrand() { using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); testToStrand(all); testRIPD1373(all); diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index 2ee9e5f1f37..c89aebf813c 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -66,7 +66,7 @@ struct AMM_test : public jtx::AMMTest {}, 0, {}, - {supported_amendments() | featureSingleAssetVault}); + {testable_amendments() | featureSingleAssetVault}); // XRP to IOU, without featureSingleAssetVault testAMM( @@ -77,7 +77,7 @@ struct AMM_test : public jtx::AMMTest {}, 0, {}, - {supported_amendments() - featureSingleAssetVault}); + {testable_amendments() - featureSingleAssetVault}); // IOU to IOU testAMM( @@ -1385,7 +1385,7 @@ struct AMM_test : public jtx::AMMTest testcase("Deposit"); using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); // Equal deposit: 1000000 tokens, 10% of the current pool testAMM([&](AMM& ammAlice, Env& env) { @@ -1687,7 +1687,7 @@ struct AMM_test : public jtx::AMMTest testcase("Invalid Withdraw"); using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); testAMM( [&](AMM& ammAlice, Env& env) { @@ -2267,7 +2267,7 @@ struct AMM_test : public jtx::AMMTest testcase("Withdraw"); using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); // Equal withdrawal by Carol: 1000000 of tokens, 10% of the current // pool @@ -2688,7 +2688,7 @@ struct AMM_test : public jtx::AMMTest { testcase("Fee Vote"); using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); // One vote sets fee to 1%. testAMM([&](AMM& ammAlice, Env& env) { @@ -4855,7 +4855,7 @@ struct AMM_test : public jtx::AMMTest { testcase("Amendment"); using namespace jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; FeatureBitset const noAMM{all - featureAMM}; FeatureBitset const noNumber{all - fixUniversalNumber}; FeatureBitset const noAMMAndNumber{ @@ -5646,7 +5646,7 @@ struct AMM_test : public jtx::AMMTest testcase("Auto Delete"); using namespace jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; { Env env( @@ -6306,7 +6306,7 @@ struct AMM_test : public jtx::AMMTest { testcase("Fix Default Inner Object"); using namespace jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; auto test = [&](FeatureBitset features, TER const& err1, @@ -7043,7 +7043,7 @@ struct AMM_test : public jtx::AMMTest {{xrpPool, iouPool}}, 889, std::nullopt, - {jtx::supported_amendments() | fixAMMv1_1}); + {jtx::testable_amendments() | fixAMMv1_1}); } void @@ -7322,7 +7322,8 @@ struct AMM_test : public jtx::AMMTest } // If featureAMMClawback is enabled, AMMCreate is allowed for // clawback-enabled issuer. Clawback from the AMM Account is not - // allowed, which will return tecAMM_ACCOUNT. We can only use + // allowed, which will return tecAMM_ACCOUNT or tecPSEUDO_ACCOUNT, + // depending on whether SingleAssetVault is enabled. We can only use // AMMClawback transaction to claw back from AMM Account. else { @@ -7333,13 +7334,16 @@ struct AMM_test : public jtx::AMMTest // By doing this, we make the clawback transaction's Amount field's // subfield `issuer` to be the AMM account, which means // we are clawing back from an AMM account. This should return an - // tecAMM_ACCOUNT error because regular Clawback transaction is not + // error because regular Clawback transaction is not // allowed for clawing back from an AMM account. Please notice the // `issuer` subfield represents the account being clawed back, which // is confusing. + auto const error = features[featureSingleAssetVault] + ? ter{tecPSEUDO_ACCOUNT} + : ter{tecAMM_ACCOUNT}; Issue usd(USD.issue().currency, amm.ammAccount()); auto amount = amountFromString(usd, "10"); - env(claw(gw, amount), ter(tecAMM_ACCOUNT)); + env(claw(gw, amount), error); } } @@ -7513,10 +7517,10 @@ struct AMM_test : public jtx::AMMTest }; testCase( - "tecDUPLICATE", supported_amendments() - featureSingleAssetVault); + "tecDUPLICATE", testable_amendments() - featureSingleAssetVault); testCase( "terADDRESS_COLLISION", - supported_amendments() | featureSingleAssetVault); + testable_amendments() | featureSingleAssetVault); } void @@ -7894,7 +7898,7 @@ struct AMM_test : public jtx::AMMTest void run() override { - FeatureBitset const all{jtx::supported_amendments()}; + FeatureBitset const all{jtx::testable_amendments()}; testInvalidInstance(); testInstanceCreate(); testInvalidDeposit(all); @@ -7945,6 +7949,8 @@ struct AMM_test : public jtx::AMMTest testLPTokenBalance(all - fixAMMv1_3); testLPTokenBalance(all - fixAMMv1_1 - fixAMMv1_3); testAMMClawback(all); + testAMMClawback(all - featureSingleAssetVault); + testAMMClawback(all - featureAMMClawback - featureSingleAssetVault); testAMMClawback(all - featureAMMClawback); testAMMClawback(all - fixAMMv1_1 - fixAMMv1_3 - featureAMMClawback); testAMMDepositWithFrozenAssets(all); diff --git a/src/test/app/AccountDelete_test.cpp b/src/test/app/AccountDelete_test.cpp index 1ac0256dcbb..f7c4ddc5097 100644 --- a/src/test/app/AccountDelete_test.cpp +++ b/src/test/app/AccountDelete_test.cpp @@ -292,7 +292,7 @@ class AccountDelete_test : public beast::unit_test::suite // o New-styled PayChannels with the backlink. // So we start the test using old-style PayChannels. Then we pass // the amendment to get new-style PayChannels. - Env env{*this, supported_amendments() - fixPayChanRecipientOwnerDir}; + Env env{*this, testable_amendments() - fixPayChanRecipientOwnerDir}; Account const alice("alice"); Account const becky("becky"); Account const gw("gw"); @@ -461,7 +461,7 @@ class AccountDelete_test : public beast::unit_test::suite // We need an old-style PayChannel that doesn't provide a backlink // from the destination. So don't enable the amendment with that fix. - Env env{*this, supported_amendments() - fixPayChanRecipientOwnerDir}; + Env env{*this, testable_amendments() - fixPayChanRecipientOwnerDir}; Account const alice("alice"); Account const becky("becky"); @@ -536,7 +536,7 @@ class AccountDelete_test : public beast::unit_test::suite testcase("Amendment enable"); - Env env{*this, supported_amendments() - featureDeletableAccounts}; + Env env{*this, testable_amendments() - featureDeletableAccounts}; Account const alice("alice"); Account const becky("becky"); @@ -1128,7 +1128,7 @@ class AccountDelete_test : public beast::unit_test::suite Account const becky{"becky"}; Account const carol{"carol"}; - Env env{*this, supported_amendments() - featureCredentials}; + Env env{*this, testable_amendments() - featureCredentials}; env.fund(XRP(100000), alice, becky, carol); env.close(); diff --git a/src/test/app/AmendmentTable_test.cpp b/src/test/app/AmendmentTable_test.cpp index 5ba820da951..407b2fafe1c 100644 --- a/src/test/app/AmendmentTable_test.cpp +++ b/src/test/app/AmendmentTable_test.cpp @@ -1288,7 +1288,7 @@ class AmendmentTable_test final : public beast::unit_test::suite void run() override { - FeatureBitset const all{test::jtx::supported_amendments()}; + FeatureBitset const all{test::jtx::testable_amendments()}; FeatureBitset const fixMajorityCalc{fixAmendmentMajorityCalc}; testConstruct(); diff --git a/src/test/app/Batch_test.cpp b/src/test/app/Batch_test.cpp index 6ce95c56d07..92f286ca6a9 100644 --- a/src/test/app/Batch_test.cpp +++ b/src/test/app/Batch_test.cpp @@ -3652,14 +3652,18 @@ class Batch_test : public beast::unit_test::suite { // Submit a tx with tfInnerBatchTxn uint256 const txBad = submitTx(tfInnerBatchTxn); - BEAST_EXPECT(env.app().getHashRouter().getFlags(txBad) == 0); + BEAST_EXPECT( + env.app().getHashRouter().getFlags(txBad) == + HashRouterFlags::UNDEFINED); } // Validate: NetworkOPs::processTransaction() { uint256 const txid = processTxn(tfInnerBatchTxn); - // HashRouter::getFlags() should return SF_BAD - BEAST_EXPECT(env.app().getHashRouter().getFlags(txid) == SF_BAD); + // HashRouter::getFlags() should return LedgerFlags::BAD + BEAST_EXPECT( + env.app().getHashRouter().getFlags(txid) == + HashRouterFlags::BAD); } } @@ -4164,7 +4168,7 @@ class Batch_test : public beast::unit_test::suite run() override { using namespace test::jtx; - auto const sa = supported_amendments(); + auto const sa = testable_amendments(); testWithFeats(sa); } }; diff --git a/src/test/app/Check_test.cpp b/src/test/app/Check_test.cpp index 99b0c8dba3b..e724b83535e 100644 --- a/src/test/app/Check_test.cpp +++ b/src/test/app/Check_test.cpp @@ -2720,7 +2720,7 @@ class Check_test : public beast::unit_test::suite run() override { using namespace test::jtx; - auto const sa = supported_amendments(); + auto const sa = testable_amendments(); testWithFeats(sa - featureCheckCashMakesTrustLine); testWithFeats(sa - disallowIncoming); testWithFeats(sa); @@ -2729,6 +2729,6 @@ class Check_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Check, tx, ripple); +BEAST_DEFINE_TESTSUITE(Check, app, ripple); } // namespace ripple diff --git a/src/test/app/Clawback_test.cpp b/src/test/app/Clawback_test.cpp index d41f6de5561..adfe80133ac 100644 --- a/src/test/app/Clawback_test.cpp +++ b/src/test/app/Clawback_test.cpp @@ -949,7 +949,7 @@ class Clawback_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testWithFeats(all - featureMPTokensV1); testWithFeats(all); diff --git a/src/test/app/Credentials_test.cpp b/src/test/app/Credentials_test.cpp index fa6505e9263..54826cbb120 100644 --- a/src/test/app/Credentials_test.cpp +++ b/src/test/app/Credentials_test.cpp @@ -1090,7 +1090,7 @@ struct Credentials_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testSuccessful(all); testCredentialsDelete(all); testCreateFailed(all); diff --git a/src/test/app/CrossingLimits_test.cpp b/src/test/app/CrossingLimits_test.cpp index cef0b03399a..18fc21078c6 100644 --- a/src/test/app/CrossingLimits_test.cpp +++ b/src/test/app/CrossingLimits_test.cpp @@ -77,10 +77,8 @@ class CrossingLimits_test : public beast::unit_test::suite auto const gw = Account("gateway"); auto const USD = gw["USD"]; - // The number of allowed offers to cross is different between - // Taker and FlowCross. Taker allows 850 and FlowCross allows 1000. - // Accommodate that difference in the test. - int const maxConsumed = features[featureFlowCross] ? 1000 : 850; + // The payment engine allows 1000 offers to cross. + int const maxConsumed = 1000; env.fund(XRP(100000000), gw, "alice", "bob", "carol"); int const bobsOfferCount = maxConsumed + 150; @@ -119,11 +117,8 @@ class CrossingLimits_test : public beast::unit_test::suite env.fund(XRP(100000000), gw, "alice", "bob", "carol", "dan", "evita"); - // The number of offers allowed to cross is different between - // Taker and FlowCross. Taker allows 850 and FlowCross allows 1000. - // Accommodate that difference in the test. - bool const isFlowCross{features[featureFlowCross]}; - int const maxConsumed = isFlowCross ? 1000 : 850; + // The payment engine allows 1000 offers to cross. + int const maxConsumed = 1000; int const evitasOfferCount{maxConsumed + 49}; env.trust(USD(1000), "alice"); @@ -133,14 +128,8 @@ class CrossingLimits_test : public beast::unit_test::suite env.trust(USD(evitasOfferCount + 1), "evita"); env(pay(gw, "evita", USD(evitasOfferCount + 1))); - // Taker and FlowCross have another difference we must accommodate. - // Taker allows a total of 1000 unfunded offers to be consumed - // beyond the 850 offers it can take. FlowCross draws no such - // distinction; its limit is 1000 funded or unfunded. - // - // Give carol an extra 150 (unfunded) offers when we're using Taker - // to accommodate that difference. - int const carolsOfferCount{isFlowCross ? 700 : 850}; + // The payment engine has a limit of 1000 funded or unfunded offers. + int const carolsOfferCount{700}; n_offers(env, 400, "alice", XRP(1), USD(1)); n_offers(env, carolsOfferCount, "carol", XRP(1), USD(1)); n_offers(env, evitasOfferCount, "evita", XRP(1), USD(1)); @@ -268,9 +257,9 @@ class CrossingLimits_test : public beast::unit_test::suite } void - testAutoBridgedLimitsFlowCross(FeatureBitset features) + testAutoBridgedLimits(FeatureBitset features) { - testcase("Auto Bridged Limits FlowCross"); + testcase("Auto Bridged Limits"); // If any book step in a payment strand consumes 1000 offers, the // liquidity from the offers is used, but that strand will be marked as @@ -452,26 +441,6 @@ class CrossingLimits_test : public beast::unit_test::suite } } - void - testAutoBridgedLimits(FeatureBitset features) - { - // Taker and FlowCross are too different in the way they handle - // autobridging to make one test suit both approaches. - // - // o Taker alternates between books, completing one full increment - // before returning to make another pass. - // - // o FlowCross extracts as much as possible in one book at one Quality - // before proceeding to the other book. This reduces the number of - // times we change books. - // - // So the tests for the two forms of autobridging are separate. - if (features[featureFlowCross]) - testAutoBridgedLimitsFlowCross(features); - else - testAutoBridgedLimitsTaker(features); - } - void testOfferOverflow(FeatureBitset features) { @@ -522,11 +491,10 @@ class CrossingLimits_test : public beast::unit_test::suite n_offers(env, 998, alice, XRP(0.96), USD(1)); n_offers(env, 998, alice, XRP(0.95), USD(1)); - bool const withFlowCross = features[featureFlowCross]; bool const withSortStrands = features[featureFlowSortStrands]; auto const expectedTER = [&]() -> TER { - if (withFlowCross && !withSortStrands) + if (!withSortStrands) return TER{tecOVERSIZE}; return tesSUCCESS; }(); @@ -535,8 +503,6 @@ class CrossingLimits_test : public beast::unit_test::suite env.close(); auto const expectedUSD = [&] { - if (!withFlowCross) - return USD(850); if (!withSortStrands) return USD(0); return USD(1996); @@ -556,17 +522,15 @@ class CrossingLimits_test : public beast::unit_test::suite testOfferOverflow(features); }; using namespace jtx; - auto const sa = supported_amendments(); + auto const sa = testable_amendments(); testAll(sa); + testAll(sa - featureFlowSortStrands); testAll(sa - featurePermissionedDEX); testAll(sa - featureFlowSortStrands - featurePermissionedDEX); - testAll( - sa - featureFlowCross - featureFlowSortStrands - - featurePermissionedDEX); } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(CrossingLimits, tx, ripple, 10); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(CrossingLimits, app, ripple, 10); } // namespace test } // namespace ripple diff --git a/src/test/app/DID_test.cpp b/src/test/app/DID_test.cpp index c885ed08618..1f28af2d6a6 100644 --- a/src/test/app/DID_test.cpp +++ b/src/test/app/DID_test.cpp @@ -390,7 +390,7 @@ struct DID_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; FeatureBitset const emptyDID{fixEmptyDID}; testEnabled(all); testAccountReserve(all); diff --git a/src/test/app/DNS_test.cpp b/src/test/app/DNS_test.cpp index 7e209deb1c0..28a143e93da 100644 --- a/src/test/app/DNS_test.cpp +++ b/src/test/app/DNS_test.cpp @@ -128,7 +128,7 @@ class DNS_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(DNS, ripple_data, ripple, 20); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(DNS, app, ripple, 20); } // namespace test } // namespace ripple diff --git a/src/test/app/Delegate_test.cpp b/src/test/app/Delegate_test.cpp index ca13e4f4cdc..179532140da 100644 --- a/src/test/app/Delegate_test.cpp +++ b/src/test/app/Delegate_test.cpp @@ -31,7 +31,7 @@ class Delegate_test : public beast::unit_test::suite testcase("test featurePermissionDelegation not enabled"); using namespace jtx; - Env env{*this, supported_amendments() - featurePermissionDelegation}; + Env env{*this, testable_amendments() - featurePermissionDelegation}; Account gw{"gateway"}; Account alice{"alice"}; Account bob{"bob"}; diff --git a/src/test/app/DeliverMin_test.cpp b/src/test/app/DeliverMin_test.cpp index 4ee7c9c72e0..a9373fb0022 100644 --- a/src/test/app/DeliverMin_test.cpp +++ b/src/test/app/DeliverMin_test.cpp @@ -142,9 +142,7 @@ class DeliverMin_test : public beast::unit_test::suite run() override { using namespace jtx; - auto const sa = supported_amendments(); - test_convert_all_of_an_asset( - sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); test_convert_all_of_an_asset(sa - featurePermissionedDEX); test_convert_all_of_an_asset(sa); } diff --git a/src/test/app/DepositAuth_test.cpp b/src/test/app/DepositAuth_test.cpp index 6f314e3a798..ffe8c4448bc 100644 --- a/src/test/app/DepositAuth_test.cpp +++ b/src/test/app/DepositAuth_test.cpp @@ -53,7 +53,7 @@ struct DepositAuth_test : public beast::unit_test::suite { // featureDepositAuth is disabled. - Env env(*this, supported_amendments() - featureDepositAuth); + Env env(*this, testable_amendments() - featureDepositAuth); env.fund(XRP(10000), alice); // Note that, to support old behavior, invalid flags are ignored. @@ -352,27 +352,27 @@ struct DepositAuth_test : public beast::unit_test::suite auto const noRippleNext = i & 0x2; auto const withDepositAuth = i & 0x4; testIssuer( - supported_amendments() | featureDepositAuth, + testable_amendments() | featureDepositAuth, noRipplePrev, noRippleNext, withDepositAuth); if (!withDepositAuth) testIssuer( - supported_amendments() - featureDepositAuth, + testable_amendments() - featureDepositAuth, noRipplePrev, noRippleNext, withDepositAuth); testNonIssuer( - supported_amendments() | featureDepositAuth, + testable_amendments() | featureDepositAuth, noRipplePrev, noRippleNext, withDepositAuth); if (!withDepositAuth) testNonIssuer( - supported_amendments() - featureDepositAuth, + testable_amendments() - featureDepositAuth, noRipplePrev, noRippleNext, withDepositAuth); @@ -420,7 +420,7 @@ struct DepositPreauth_test : public beast::unit_test::suite Account const becky{"becky"}; { // featureDepositPreauth is disabled. - Env env(*this, supported_amendments() - featureDepositPreauth); + Env env(*this, testable_amendments() - featureDepositPreauth); env.fund(XRP(10000), alice, becky); env.close(); @@ -830,7 +830,7 @@ struct DepositPreauth_test : public beast::unit_test::suite { testcase("Payment failure with disabled credentials rule."); - Env env(*this, supported_amendments() - featureCredentials); + Env env(*this, testable_amendments() - featureCredentials); env.fund(XRP(5000), issuer, bob, alice); env.close(); @@ -1563,7 +1563,7 @@ struct DepositPreauth_test : public beast::unit_test::suite { testEnable(); testInvalid(); - auto const supported{jtx::supported_amendments()}; + auto const supported{jtx::testable_amendments()}; testPayment(supported - featureDepositPreauth - featureCredentials); testPayment(supported - featureDepositPreauth); testPayment(supported - featureCredentials); diff --git a/src/test/app/Discrepancy_test.cpp b/src/test/app/Discrepancy_test.cpp index bc72b2fd168..da419698857 100644 --- a/src/test/app/Discrepancy_test.cpp +++ b/src/test/app/Discrepancy_test.cpp @@ -146,8 +146,7 @@ class Discrepancy_test : public beast::unit_test::suite run() override { using namespace test::jtx; - auto const sa = supported_amendments(); - testXRPDiscrepancy(sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); testXRPDiscrepancy(sa - featurePermissionedDEX); testXRPDiscrepancy(sa); } diff --git a/src/test/app/EscrowToken_test.cpp b/src/test/app/EscrowToken_test.cpp index 6ba8c48c93c..e81064c825b 100644 --- a/src/test/app/EscrowToken_test.cpp +++ b/src/test/app/EscrowToken_test.cpp @@ -3875,7 +3875,7 @@ struct EscrowToken_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testIOUWithFeats(all); testMPTWithFeats(all); } diff --git a/src/test/app/Escrow_test.cpp b/src/test/app/Escrow_test.cpp index 21ef70a86e3..3eaf0f13ea0 100644 --- a/src/test/app/Escrow_test.cpp +++ b/src/test/app/Escrow_test.cpp @@ -294,7 +294,7 @@ struct Escrow_test : public beast::unit_test::suite { testcase("Implied Finish Time (without fix1571)"); - Env env(*this, supported_amendments() - fix1571); + Env env(*this, testable_amendments() - fix1571); auto const baseFee = env.current()->fees().base; env.fund(XRP(5000), "alice", "bob", "carol"); env.close(); @@ -1715,7 +1715,7 @@ struct Escrow_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testWithFeats(all); testWithFeats(all - featureTokenEscrow); } diff --git a/src/test/app/FeeVote_test.cpp b/src/test/app/FeeVote_test.cpp index 1cf2e67f83e..ba3d3792196 100644 --- a/src/test/app/FeeVote_test.cpp +++ b/src/test/app/FeeVote_test.cpp @@ -100,7 +100,7 @@ class FeeVote_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(FeeVote, server, ripple); +BEAST_DEFINE_TESTSUITE(FeeVote, app, ripple); } // namespace test } // namespace ripple diff --git a/src/test/app/FixNFTokenPageLinks_test.cpp b/src/test/app/FixNFTokenPageLinks_test.cpp index f87d70aacf7..4acd650a083 100644 --- a/src/test/app/FixNFTokenPageLinks_test.cpp +++ b/src/test/app/FixNFTokenPageLinks_test.cpp @@ -139,7 +139,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite { // Verify that the LedgerStateFix transaction is disabled // without the fixNFTokenPageLinks amendment. - Env env{*this, supported_amendments() - fixNFTokenPageLinks}; + Env env{*this, testable_amendments() - fixNFTokenPageLinks}; env.fund(XRP(1000), alice); auto const linkFixFee = drops(env.current()->fees().increment); @@ -148,7 +148,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite ter(temDISABLED)); } - Env env{*this, supported_amendments()}; + Env env{*this, testable_amendments()}; env.fund(XRP(1000), alice); std::uint32_t const ticketSeq = env.seq(alice); env(ticket::create(alice, 1)); @@ -206,7 +206,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite Account const alice("alice"); - Env env{*this, supported_amendments()}; + Env env{*this, testable_amendments()}; env.fund(XRP(1000), alice); // These cases all return the same TER code, but they exercise @@ -259,7 +259,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite Account const carol("carol"); Account const daria("daria"); - Env env{*this, supported_amendments() - fixNFTokenPageLinks}; + Env env{*this, testable_amendments() - fixNFTokenPageLinks}; env.fund(XRP(1000), alice, bob, carol, daria); //********************************************************************** @@ -663,6 +663,6 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(FixNFTokenPageLinks, tx, ripple); +BEAST_DEFINE_TESTSUITE(FixNFTokenPageLinks, app, ripple); } // namespace ripple diff --git a/src/test/app/Flow_test.cpp b/src/test/app/Flow_test.cpp index d0b8686db61..0f40d70b57f 100644 --- a/src/test/app/Flow_test.cpp +++ b/src/test/app/Flow_test.cpp @@ -599,158 +599,18 @@ struct Flow_test : public beast::unit_test::suite Account const bob("bob"); Account const carol("carol"); - { - // Simple payment through a gateway with a - // transfer rate - Env env(*this, features); - - env.fund(XRP(10000), alice, bob, carol, gw); - env.close(); - env(rate(gw, 1.25)); - env.trust(USD(1000), alice, bob, carol); - env(pay(gw, alice, USD(50))); - env.require(balance(alice, USD(50))); - env(pay(alice, bob, USD(40)), sendmax(USD(50))); - env.require(balance(bob, USD(40)), balance(alice, USD(0))); - } - { - // transfer rate is not charged when issuer is src or dst - Env env(*this, features); - - env.fund(XRP(10000), alice, bob, carol, gw); - env.close(); - env(rate(gw, 1.25)); - env.trust(USD(1000), alice, bob, carol); - env(pay(gw, alice, USD(50))); - env.require(balance(alice, USD(50))); - env(pay(alice, gw, USD(40)), sendmax(USD(40))); - env.require(balance(alice, USD(10))); - } - { - // transfer fee on an offer - Env env(*this, features); - - env.fund(XRP(10000), alice, bob, carol, gw); - env.close(); - env(rate(gw, 1.25)); - env.trust(USD(1000), alice, bob, carol); - env(pay(gw, bob, USD(65))); - - env(offer(bob, XRP(50), USD(50))); - - env(pay(alice, carol, USD(50)), path(~USD), sendmax(XRP(50))); - env.require( - balance(alice, xrpMinusFee(env, 10000 - 50)), - balance(bob, USD(2.5)), // owner pays transfer fee - balance(carol, USD(50))); - } - - { - // Transfer fee two consecutive offers - Env env(*this, features); - - env.fund(XRP(10000), alice, bob, carol, gw); - env.close(); - env(rate(gw, 1.25)); - env.trust(USD(1000), alice, bob, carol); - env.trust(EUR(1000), alice, bob, carol); - env(pay(gw, bob, USD(50))); - env(pay(gw, bob, EUR(50))); - - env(offer(bob, XRP(50), USD(50))); - env(offer(bob, USD(50), EUR(50))); - - env(pay(alice, carol, EUR(40)), path(~USD, ~EUR), sendmax(XRP(40))); - env.require( - balance(alice, xrpMinusFee(env, 10000 - 40)), - balance(bob, USD(40)), - balance(bob, EUR(0)), - balance(carol, EUR(40))); - } - - { - // First pass through a strand redeems, second pass issues, no - // offers limiting step is not an endpoint - Env env(*this, features); - auto const USDA = alice["USD"]; - auto const USDB = bob["USD"]; - - env.fund(XRP(10000), alice, bob, carol, gw); - env.close(); - env(rate(gw, 1.25)); - env.trust(USD(1000), alice, bob, carol); - env.trust(USDA(1000), bob); - env.trust(USDB(1000), gw); - env(pay(gw, bob, USD(50))); - // alice -> bob -> gw -> carol. $50 should have transfer fee; $10, - // no fee - env(pay(alice, carol, USD(50)), path(bob), sendmax(USDA(60))); - env.require( - balance(bob, USD(-10)), - balance(bob, USDA(60)), - balance(carol, USD(50))); - } - { - // First pass through a strand redeems, second pass issues, through - // an offer limiting step is not an endpoint - Env env(*this, features); - auto const USDA = alice["USD"]; - auto const USDB = bob["USD"]; - Account const dan("dan"); - - env.fund(XRP(10000), alice, bob, carol, dan, gw); - env.close(); - env(rate(gw, 1.25)); - env.trust(USD(1000), alice, bob, carol, dan); - env.trust(EUR(1000), carol, dan); - env.trust(USDA(1000), bob); - env.trust(USDB(1000), gw); - env(pay(gw, bob, USD(50))); - env(pay(gw, dan, EUR(100))); - env(offer(dan, USD(100), EUR(100))); - // alice -> bob -> gw -> carol. $50 should have transfer fee; $10, - // no fee - env(pay(alice, carol, EUR(50)), - path(bob, gw, ~EUR), - sendmax(USDA(60)), - txflags(tfNoRippleDirect)); - env.require( - balance(bob, USD(-10)), - balance(bob, USDA(60)), - balance(dan, USD(50)), - balance(dan, EUR(37.5)), - balance(carol, EUR(50))); - } - - { - // Offer where the owner is also the issuer, owner pays fee - Env env(*this, features); - - env.fund(XRP(10000), alice, bob, gw); - env.close(); - env(rate(gw, 1.25)); - env.trust(USD(1000), alice, bob); - env(offer(gw, XRP(100), USD(100))); - env(pay(alice, bob, USD(100)), sendmax(XRP(100))); - env.require( - balance(alice, xrpMinusFee(env, 10000 - 100)), - balance(bob, USD(100))); - } - if (!features[featureOwnerPaysFee]) - { - // Offer where the owner is also the issuer, sender pays fee - Env env(*this, features); + // Offer where the owner is also the issuer, sender pays fee + Env env(*this, features); - env.fund(XRP(10000), alice, bob, gw); - env.close(); - env(rate(gw, 1.25)); - env.trust(USD(1000), alice, bob); - env(offer(gw, XRP(125), USD(125))); - env(pay(alice, bob, USD(100)), sendmax(XRP(200))); - env.require( - balance(alice, xrpMinusFee(env, 10000 - 125)), - balance(bob, USD(100))); - } + env.fund(XRP(10000), alice, bob, gw); + env.close(); + env(rate(gw, 1.25)); + env.trust(USD(1000), alice, bob); + env(offer(gw, XRP(125), USD(125))); + env(pay(alice, bob, USD(100)), sendmax(XRP(200))); + env.require( + balance(alice, xrpMinusFee(env, 10000 - 125)), + balance(bob, USD(100))); } void @@ -1334,8 +1194,8 @@ struct Flow_test : public beast::unit_test::suite { auto const feats = [&withFix]() -> FeatureBitset { if (withFix) - return supported_amendments(); - return supported_amendments() - FeatureBitset{fix1781}; + return testable_amendments(); + return testable_amendments() - FeatureBitset{fix1781}; }(); { // Payment path starting with XRP @@ -1445,7 +1305,6 @@ struct Flow_test : public beast::unit_test::suite testWithFeats(FeatureBitset features) { using namespace jtx; - FeatureBitset const ownerPaysFee{featureOwnerPaysFee}; FeatureBitset const reducedOffersV2(fixReducedOffersV2); testLineQuality(features); @@ -1453,9 +1312,7 @@ struct Flow_test : public beast::unit_test::suite testBookStep(features - reducedOffersV2); testDirectStep(features); testBookStep(features); - testDirectStep(features | ownerPaysFee); - testBookStep(features | ownerPaysFee); - testTransferRate(features | ownerPaysFee); + testTransferRate(features); testSelfPayment1(features); testSelfPayment2(features); testSelfFundedXRPEndpoint(false, features); @@ -1475,8 +1332,7 @@ struct Flow_test : public beast::unit_test::suite testRIPD1449(); using namespace jtx; - auto const sa = supported_amendments(); - testWithFeats(sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); testWithFeats(sa - featurePermissionedDEX); testWithFeats(sa); testEmptyStrand(sa); @@ -1489,13 +1345,10 @@ struct Flow_manual_test : public Flow_test run() override { using namespace jtx; - auto const all = supported_amendments(); - FeatureBitset const flowCross{featureFlowCross}; + auto const all = testable_amendments(); FeatureBitset const f1513{fix1513}; FeatureBitset const permDex{featurePermissionedDEX}; - testWithFeats(all - flowCross - f1513 - permDex); - testWithFeats(all - flowCross - permDex); testWithFeats(all - f1513 - permDex); testWithFeats(all - permDex); testWithFeats(all); diff --git a/src/test/app/Freeze_test.cpp b/src/test/app/Freeze_test.cpp index 8c2021d657c..3bde3a30afa 100644 --- a/src/test/app/Freeze_test.cpp +++ b/src/test/app/Freeze_test.cpp @@ -961,24 +961,12 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 wants to buy, must fail - if (features[featureFlowCross]) - { - env(offer(A1, USD(1), XRP(2)), - txflags(tfFillOrKill), - ter(tecKILLED)); - env.close(); - env.require( - balance(A1, USD(1002)), - balance(A2, USD(997)), - offers(A1, 0)); - } - else - { - // The transaction that should be here would succeed. - // I don't want to adjust balances in following tests. Flow - // cross feature flag is not relevant to this particular test - // case so we're not missing out some corner cases checks. - } + env(offer(A1, USD(1), XRP(2)), + txflags(tfFillOrKill), + ter(tecKILLED)); + env.close(); + env.require( + balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 0)); // test: A1 can create passive sell offer env(offer(A1, XRP(2), USD(1)), txflags(tfPassive)); @@ -2106,18 +2094,15 @@ class Freeze_test : public beast::unit_test::suite testNFTOffersWhenFreeze(features); }; using namespace test::jtx; - auto const sa = supported_amendments(); - testAll( - sa - featureFlowCross - featureDeepFreeze - featurePermissionedDEX - - fixEnforceNFTokenTrustlineV2); - testAll( - sa - featureFlowCross - featurePermissionedDEX - - fixEnforceNFTokenTrustlineV2); + auto const sa = testable_amendments(); testAll( sa - featureDeepFreeze - featurePermissionedDEX - fixEnforceNFTokenTrustlineV2); testAll(sa - featurePermissionedDEX - fixEnforceNFTokenTrustlineV2); + testAll(sa - featureDeepFreeze - featurePermissionedDEX); + testAll(sa - featurePermissionedDEX); testAll(sa - fixEnforceNFTokenTrustlineV2); + testAll(sa - featureDeepFreeze); testAll(sa); } }; diff --git a/src/test/app/HashRouter_test.cpp b/src/test/app/HashRouter_test.cpp index 0737116f136..44170e152e8 100644 --- a/src/test/app/HashRouter_test.cpp +++ b/src/test/app/HashRouter_test.cpp @@ -45,15 +45,19 @@ class HashRouter_test : public beast::unit_test::suite TestStopwatch stopwatch; HashRouter router(getSetup(2s, 1s), stopwatch); - uint256 const key1(1); - uint256 const key2(2); - uint256 const key3(3); + HashRouterFlags key1(HashRouterFlags::PRIVATE1); + HashRouterFlags key2(HashRouterFlags::PRIVATE2); + HashRouterFlags key3(HashRouterFlags::PRIVATE3); + + auto const ukey1 = uint256{static_cast(key1)}; + auto const ukey2 = uint256{static_cast(key2)}; + auto const ukey3 = uint256{static_cast(key3)}; // t=0 - router.setFlags(key1, 11111); - BEAST_EXPECT(router.getFlags(key1) == 11111); - router.setFlags(key2, 22222); - BEAST_EXPECT(router.getFlags(key2) == 22222); + router.setFlags(ukey1, HashRouterFlags::PRIVATE1); + BEAST_EXPECT(router.getFlags(ukey1) == HashRouterFlags::PRIVATE1); + router.setFlags(ukey2, HashRouterFlags::PRIVATE2); + BEAST_EXPECT(router.getFlags(ukey2) == HashRouterFlags::PRIVATE2); // key1 : 0 // key2 : 0 // key3: null @@ -62,7 +66,7 @@ class HashRouter_test : public beast::unit_test::suite // Because we are accessing key1 here, it // will NOT be expired for another two ticks - BEAST_EXPECT(router.getFlags(key1) == 11111); + BEAST_EXPECT(router.getFlags(ukey1) == HashRouterFlags::PRIVATE1); // key1 : 1 // key2 : 0 // key3 null @@ -70,9 +74,9 @@ class HashRouter_test : public beast::unit_test::suite ++stopwatch; // t=3 - router.setFlags(key3, 33333); // force expiration - BEAST_EXPECT(router.getFlags(key1) == 11111); - BEAST_EXPECT(router.getFlags(key2) == 0); + router.setFlags(ukey3, HashRouterFlags::PRIVATE3); // force expiration + BEAST_EXPECT(router.getFlags(ukey1) == HashRouterFlags::PRIVATE1); + BEAST_EXPECT(router.getFlags(ukey2) == HashRouterFlags::UNDEFINED); } void @@ -83,15 +87,21 @@ class HashRouter_test : public beast::unit_test::suite TestStopwatch stopwatch; HashRouter router(getSetup(2s, 1s), stopwatch); - uint256 const key1(1); - uint256 const key2(2); - uint256 const key3(3); - uint256 const key4(4); + HashRouterFlags key1(HashRouterFlags::PRIVATE1); + HashRouterFlags key2(HashRouterFlags::PRIVATE2); + HashRouterFlags key3(HashRouterFlags::PRIVATE3); + HashRouterFlags key4(HashRouterFlags::PRIVATE4); + + auto const ukey1 = uint256{static_cast(key1)}; + auto const ukey2 = uint256{static_cast(key2)}; + auto const ukey3 = uint256{static_cast(key3)}; + auto const ukey4 = uint256{static_cast(key4)}; + BEAST_EXPECT(key1 != key2 && key2 != key3 && key3 != key4); // t=0 - router.setFlags(key1, 12345); - BEAST_EXPECT(router.getFlags(key1) == 12345); + router.setFlags(ukey1, HashRouterFlags::BAD); + BEAST_EXPECT(router.getFlags(ukey1) == HashRouterFlags::BAD); // key1 : 0 // key2 : null // key3 : null @@ -103,26 +113,27 @@ class HashRouter_test : public beast::unit_test::suite // so key1 will be expired after the second // call to setFlags. // t=1 - router.setFlags(key2, 9999); - BEAST_EXPECT(router.getFlags(key1) == 12345); - BEAST_EXPECT(router.getFlags(key2) == 9999); + + router.setFlags(ukey2, HashRouterFlags::PRIVATE5); + BEAST_EXPECT(router.getFlags(ukey1) == HashRouterFlags::BAD); + BEAST_EXPECT(router.getFlags(ukey2) == HashRouterFlags::PRIVATE5); // key1 : 1 // key2 : 1 // key3 : null ++stopwatch; // t=2 - BEAST_EXPECT(router.getFlags(key2) == 9999); + BEAST_EXPECT(router.getFlags(ukey2) == HashRouterFlags::PRIVATE5); // key1 : 1 // key2 : 2 // key3 : null ++stopwatch; // t=3 - router.setFlags(key3, 2222); - BEAST_EXPECT(router.getFlags(key1) == 0); - BEAST_EXPECT(router.getFlags(key2) == 9999); - BEAST_EXPECT(router.getFlags(key3) == 2222); + router.setFlags(ukey3, HashRouterFlags::BAD); + BEAST_EXPECT(router.getFlags(ukey1) == HashRouterFlags::UNDEFINED); + BEAST_EXPECT(router.getFlags(ukey2) == HashRouterFlags::PRIVATE5); + BEAST_EXPECT(router.getFlags(ukey3) == HashRouterFlags::BAD); // key1 : 3 // key2 : 3 // key3 : 3 @@ -130,10 +141,10 @@ class HashRouter_test : public beast::unit_test::suite ++stopwatch; // t=4 // No insertion, no expiration - router.setFlags(key1, 7654); - BEAST_EXPECT(router.getFlags(key1) == 7654); - BEAST_EXPECT(router.getFlags(key2) == 9999); - BEAST_EXPECT(router.getFlags(key3) == 2222); + router.setFlags(ukey1, HashRouterFlags::SAVED); + BEAST_EXPECT(router.getFlags(ukey1) == HashRouterFlags::SAVED); + BEAST_EXPECT(router.getFlags(ukey2) == HashRouterFlags::PRIVATE5); + BEAST_EXPECT(router.getFlags(ukey3) == HashRouterFlags::BAD); // key1 : 4 // key2 : 4 // key3 : 4 @@ -142,11 +153,11 @@ class HashRouter_test : public beast::unit_test::suite ++stopwatch; // t=6 - router.setFlags(key4, 7890); - BEAST_EXPECT(router.getFlags(key1) == 0); - BEAST_EXPECT(router.getFlags(key2) == 0); - BEAST_EXPECT(router.getFlags(key3) == 0); - BEAST_EXPECT(router.getFlags(key4) == 7890); + router.setFlags(ukey4, HashRouterFlags::TRUSTED); + BEAST_EXPECT(router.getFlags(ukey1) == HashRouterFlags::UNDEFINED); + BEAST_EXPECT(router.getFlags(ukey2) == HashRouterFlags::UNDEFINED); + BEAST_EXPECT(router.getFlags(ukey3) == HashRouterFlags::UNDEFINED); + BEAST_EXPECT(router.getFlags(ukey4) == HashRouterFlags::TRUSTED); // key1 : 6 // key2 : 6 // key3 : 6 @@ -168,18 +179,18 @@ class HashRouter_test : public beast::unit_test::suite uint256 const key4(4); BEAST_EXPECT(key1 != key2 && key2 != key3 && key3 != key4); - int flags = 12345; // This value is ignored + HashRouterFlags flags(HashRouterFlags::BAD); // This value is ignored router.addSuppression(key1); BEAST_EXPECT(router.addSuppressionPeer(key2, 15)); BEAST_EXPECT(router.addSuppressionPeer(key3, 20, flags)); - BEAST_EXPECT(flags == 0); + BEAST_EXPECT(flags == HashRouterFlags::UNDEFINED); ++stopwatch; BEAST_EXPECT(!router.addSuppressionPeer(key1, 2)); BEAST_EXPECT(!router.addSuppressionPeer(key2, 3)); BEAST_EXPECT(!router.addSuppressionPeer(key3, 4, flags)); - BEAST_EXPECT(flags == 0); + BEAST_EXPECT(flags == HashRouterFlags::UNDEFINED); BEAST_EXPECT(router.addSuppressionPeer(key4, 5)); } @@ -192,9 +203,9 @@ class HashRouter_test : public beast::unit_test::suite HashRouter router(getSetup(2s, 1s), stopwatch); uint256 const key1(1); - BEAST_EXPECT(router.setFlags(key1, 10)); - BEAST_EXPECT(!router.setFlags(key1, 10)); - BEAST_EXPECT(router.setFlags(key1, 20)); + BEAST_EXPECT(router.setFlags(key1, HashRouterFlags::PRIVATE1)); + BEAST_EXPECT(!router.setFlags(key1, HashRouterFlags::PRIVATE1)); + BEAST_EXPECT(router.setFlags(key1, HashRouterFlags::PRIVATE2)); } void @@ -250,7 +261,7 @@ class HashRouter_test : public beast::unit_test::suite HashRouter router(getSetup(5s, 1s), stopwatch); uint256 const key(1); HashRouter::PeerShortID peer = 1; - int flags; + HashRouterFlags flags; BEAST_EXPECT(router.shouldProcess(key, peer, flags, 1s)); BEAST_EXPECT(!router.shouldProcess(key, peer, flags, 1s)); @@ -364,6 +375,39 @@ class HashRouter_test : public beast::unit_test::suite } } + void + testFlagsOps() + { + testcase("Bitwise Operations"); + + using HF = HashRouterFlags; + using UHF = std::underlying_type_t; + + HF f1 = HF::BAD; + HF f2 = HF::SAVED; + HF combined = f1 | f2; + + BEAST_EXPECT( + static_cast(combined) == + (static_cast(f1) | static_cast(f2))); + + HF temp = f1; + temp |= f2; + BEAST_EXPECT(temp == combined); + + HF intersect = combined & f1; + BEAST_EXPECT(intersect == f1); + + HF temp2 = combined; + temp2 &= f1; + BEAST_EXPECT(temp2 == f1); + + BEAST_EXPECT(any(f1)); + BEAST_EXPECT(any(f2)); + BEAST_EXPECT(any(combined)); + BEAST_EXPECT(!any(HF::UNDEFINED)); + } + public: void run() override @@ -375,6 +419,7 @@ class HashRouter_test : public beast::unit_test::suite testRelay(); testProcess(); testSetup(); + testFlagsOps(); } }; diff --git a/src/test/ledger/Invariants_test.cpp b/src/test/app/Invariants_test.cpp similarity index 99% rename from src/test/ledger/Invariants_test.cpp rename to src/test/app/Invariants_test.cpp index 6178b413d52..ae2a1c45df1 100644 --- a/src/test/ledger/Invariants_test.cpp +++ b/src/test/app/Invariants_test.cpp @@ -78,7 +78,7 @@ class Invariants_test : public beast::unit_test::suite Preclose const& preclose = {}) { using namespace test::jtx; - FeatureBitset amendments = supported_amendments() | + FeatureBitset amendments = testable_amendments() | featureInvariantsV1_1 | featureSingleAssetVault; Env env{*this, amendments}; @@ -1626,6 +1626,6 @@ class Invariants_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Invariants, ledger, ripple); +BEAST_DEFINE_TESTSUITE(Invariants, app, ripple); } // namespace ripple diff --git a/src/test/app/LPTokenTransfer_test.cpp b/src/test/app/LPTokenTransfer_test.cpp index 96e621dccfe..e95e974547d 100644 --- a/src/test/app/LPTokenTransfer_test.cpp +++ b/src/test/app/LPTokenTransfer_test.cpp @@ -467,7 +467,7 @@ class LPTokenTransfer_test : public jtx::AMMTest void run() override { - FeatureBitset const all{jtx::supported_amendments()}; + FeatureBitset const all{jtx::testable_amendments()}; for (auto const features : {all, all - fixFrozenLPTokenTransfer}) { diff --git a/src/test/app/LedgerMaster_test.cpp b/src/test/app/LedgerMaster_test.cpp index 19664616b11..828e4b09c2e 100644 --- a/src/test/app/LedgerMaster_test.cpp +++ b/src/test/app/LedgerMaster_test.cpp @@ -124,7 +124,7 @@ class LedgerMaster_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testWithFeats(all); } diff --git a/src/test/app/LoadFeeTrack_test.cpp b/src/test/app/LoadFeeTrack_test.cpp index 9b0cf2fa2db..8a88e0273f1 100644 --- a/src/test/app/LoadFeeTrack_test.cpp +++ b/src/test/app/LoadFeeTrack_test.cpp @@ -87,6 +87,6 @@ class LoadFeeTrack_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(LoadFeeTrack, ripple_core, ripple); +BEAST_DEFINE_TESTSUITE(LoadFeeTrack, app, ripple); } // namespace ripple diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index deee217aa80..6470962f2f0 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -18,10 +18,16 @@ //============================================================================== #include +#include +#include #include #include +#include +#include #include +#include +#include #include namespace ripple { @@ -61,6 +67,48 @@ class MPToken_test : public beast::unit_test::suite .metadata = "test", .err = temMALFORMED}); + if (!features[featureSingleAssetVault]) + { + // tries to set DomainID when SAV is disabled + mptAlice.create( + {.maxAmt = 100, + .assetScale = 0, + .metadata = "test", + .flags = tfMPTRequireAuth, + .domainID = uint256(42), + .err = temDISABLED}); + } + else if (!features[featurePermissionedDomains]) + { + // tries to set DomainID when PD is disabled + mptAlice.create( + {.maxAmt = 100, + .assetScale = 0, + .metadata = "test", + .flags = tfMPTRequireAuth, + .domainID = uint256(42), + .err = temDISABLED}); + } + else + { + // tries to set DomainID when RequireAuth is not set + mptAlice.create( + {.maxAmt = 100, + .assetScale = 0, + .metadata = "test", + .domainID = uint256(42), + .err = temMALFORMED}); + + // tries to set zero DomainID + mptAlice.create( + {.maxAmt = 100, + .assetScale = 0, + .metadata = "test", + .flags = tfMPTRequireAuth, + .domainID = beast::zero, + .err = temMALFORMED}); + } + // tries to set a txfee greater than max mptAlice.create( {.maxAmt = 100, @@ -140,6 +188,48 @@ class MPToken_test : public beast::unit_test::suite BEAST_EXPECT( result[sfMaximumAmount.getJsonName()] == "9223372036854775807"); } + + if (features[featureSingleAssetVault]) + { + // Add permissioned domain + Account const credIssuer1{"credIssuer1"}; + std::string const credType = "credential"; + + pdomain::Credentials const credentials1{ + {.issuer = credIssuer1, .credType = credType}}; + + { + Env env{*this, features}; + env.fund(XRP(1000), credIssuer1); + + env(pdomain::setTx(credIssuer1, credentials1)); + auto const domainId1 = [&]() { + auto tx = env.tx()->getJson(JsonOptions::none); + return pdomain::getNewDomain(env.meta()); + }(); + + MPTTester mptAlice(env, alice); + mptAlice.create({ + .maxAmt = maxMPTokenAmount, // 9'223'372'036'854'775'807 + .assetScale = 1, + .transferFee = 10, + .metadata = "123", + .ownerCount = 1, + .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | + tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback, + .domainID = domainId1, + }); + + // Get the hash for the most recent transaction. + std::string const txHash{ + env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + + Json::Value const result = env.rpc("tx", txHash)[jss::result]; + BEAST_EXPECT( + result[sfMaximumAmount.getJsonName()] == + "9223372036854775807"); + } + } } void @@ -499,6 +589,59 @@ class MPToken_test : public beast::unit_test::suite .flags = 0x00000008, .err = temINVALID_FLAG}); + if (!features[featureSingleAssetVault]) + { + // test invalid flags - nothing is being changed + mptAlice.set( + {.account = alice, + .flags = 0x00000000, + .err = tecNO_PERMISSION}); + + mptAlice.set( + {.account = alice, + .holder = bob, + .flags = 0x00000000, + .err = tecNO_PERMISSION}); + + // cannot set DomainID since SAV is not enabled + mptAlice.set( + {.account = alice, + .domainID = uint256(42), + .err = temDISABLED}); + } + else + { + // test invalid flags - nothing is being changed + mptAlice.set( + {.account = alice, + .flags = 0x00000000, + .err = temMALFORMED}); + + mptAlice.set( + {.account = alice, + .holder = bob, + .flags = 0x00000000, + .err = temMALFORMED}); + + if (!features[featurePermissionedDomains]) + { + // cannot set DomainID since PD is not enabled + mptAlice.set( + {.account = alice, + .domainID = uint256(42), + .err = temDISABLED}); + } + else + { + // cannot set DomainID since Holder is set + mptAlice.set( + {.account = alice, + .holder = bob, + .domainID = uint256(42), + .err = temMALFORMED}); + } + } + // set both lock and unlock flags at the same time will fail mptAlice.set( {.account = alice, @@ -582,6 +725,53 @@ class MPToken_test : public beast::unit_test::suite mptAlice.set( {.holder = cindy, .flags = tfMPTLock, .err = tecNO_DST}); } + + if (features[featureSingleAssetVault] && + features[featurePermissionedDomains]) + { + // Add permissioned domain + Account const credIssuer1{"credIssuer1"}; + std::string const credType = "credential"; + + pdomain::Credentials const credentials1{ + {.issuer = credIssuer1, .credType = credType}}; + + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice); + mptAlice.create({}); + + // Trying to set DomainID on a public MPTokenIssuance + mptAlice.set( + {.domainID = uint256(42), .err = tecNO_PERMISSION}); + + mptAlice.set( + {.domainID = beast::zero, .err = tecNO_PERMISSION}); + } + + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice); + mptAlice.create({.flags = tfMPTRequireAuth}); + + // Trying to set non-existing DomainID + mptAlice.set( + {.domainID = uint256(42), .err = tecOBJECT_NOT_FOUND}); + + // Trying to lock but locking is disabled + mptAlice.set( + {.flags = tfMPTUnlock, + .domainID = uint256(42), + .err = tecNO_PERMISSION}); + + mptAlice.set( + {.flags = tfMPTUnlock, + .domainID = beast::zero, + .err = tecNO_PERMISSION}); + } + } } void @@ -590,71 +780,136 @@ class MPToken_test : public beast::unit_test::suite testcase("Enabled set transaction"); using namespace test::jtx; - - // Test locking and unlocking - Env env{*this, features}; Account const alice("alice"); // issuer Account const bob("bob"); // holder - MPTTester mptAlice(env, alice, {.holders = {bob}}); + { + // Test locking and unlocking + Env env{*this, features}; - // create a mptokenissuance with locking - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock}); + MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.authorize({.account = bob, .holderCount = 1}); + // create a mptokenissuance with locking + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock}); - // locks bob's mptoken - mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + mptAlice.authorize({.account = bob, .holderCount = 1}); - // trying to lock bob's mptoken again will still succeed - // but no changes to the objects - mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + // locks bob's mptoken + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); - // alice locks the mptissuance - mptAlice.set({.account = alice, .flags = tfMPTLock}); + // trying to lock bob's mptoken again will still succeed + // but no changes to the objects + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); - // alice tries to lock up both mptissuance and mptoken again - // it will not change the flags and both will remain locked. - mptAlice.set({.account = alice, .flags = tfMPTLock}); - mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + // alice locks the mptissuance + mptAlice.set({.account = alice, .flags = tfMPTLock}); - // alice unlocks bob's mptoken - mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); + // alice tries to lock up both mptissuance and mptoken again + // it will not change the flags and both will remain locked. + mptAlice.set({.account = alice, .flags = tfMPTLock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); - // locks up bob's mptoken again - mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); - if (!features[featureSingleAssetVault]) - { - // Delete bobs' mptoken even though it is locked - mptAlice.authorize({.account = bob, .flags = tfMPTUnauthorize}); + // alice unlocks bob's mptoken + mptAlice.set( + {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + // locks up bob's mptoken again + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + if (!features[featureSingleAssetVault]) + { + // Delete bobs' mptoken even though it is locked + mptAlice.authorize({.account = bob, .flags = tfMPTUnauthorize}); + + mptAlice.set( + {.account = alice, + .holder = bob, + .flags = tfMPTUnlock, + .err = tecOBJECT_NOT_FOUND}); + + return; + } + + // Cannot delete locked MPToken + mptAlice.authorize( + {.account = bob, + .flags = tfMPTUnauthorize, + .err = tecNO_PERMISSION}); + + // alice unlocks mptissuance + mptAlice.set({.account = alice, .flags = tfMPTUnlock}); + + // alice unlocks bob's mptoken mptAlice.set( - {.account = alice, - .holder = bob, - .flags = tfMPTUnlock, - .err = tecOBJECT_NOT_FOUND}); + {.account = alice, .holder = bob, .flags = tfMPTUnlock}); - return; + // alice unlocks mptissuance and bob's mptoken again despite that + // they are already unlocked. Make sure this will not change the + // flags + mptAlice.set( + {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .flags = tfMPTUnlock}); } - // Cannot delete locked MPToken - mptAlice.authorize( - {.account = bob, - .flags = tfMPTUnauthorize, - .err = tecNO_PERMISSION}); + if (features[featureSingleAssetVault]) + { + // Add permissioned domain + std::string const credType = "credential"; + + // Test setting and resetting domain ID + Env env{*this, features}; + + auto const domainId1 = [&]() { + Account const credIssuer1{"credIssuer1"}; + env.fund(XRP(1000), credIssuer1); + + pdomain::Credentials const credentials1{ + {.issuer = credIssuer1, .credType = credType}}; + + env(pdomain::setTx(credIssuer1, credentials1)); + return [&]() { + auto tx = env.tx()->getJson(JsonOptions::none); + return pdomain::getNewDomain(env.meta()); + }(); + }(); + + auto const domainId2 = [&]() { + Account const credIssuer2{"credIssuer2"}; + env.fund(XRP(1000), credIssuer2); - // alice unlocks mptissuance - mptAlice.set({.account = alice, .flags = tfMPTUnlock}); + pdomain::Credentials const credentials2{ + {.issuer = credIssuer2, .credType = credType}}; - // alice unlocks bob's mptoken - mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); + env(pdomain::setTx(credIssuer2, credentials2)); + return [&]() { + auto tx = env.tx()->getJson(JsonOptions::none); + return pdomain::getNewDomain(env.meta()); + }(); + }(); - // alice unlocks mptissuance and bob's mptoken again despite that - // they are already unlocked. Make sure this will not change the - // flags - mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); - mptAlice.set({.account = alice, .flags = tfMPTUnlock}); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // create a mptokenissuance with auth. + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth}); + BEAST_EXPECT(mptAlice.checkDomainID(std::nullopt)); + + // reset "domain not set" to "domain not set", i.e. no change + mptAlice.set({.domainID = beast::zero}); + BEAST_EXPECT(mptAlice.checkDomainID(std::nullopt)); + + // reset "domain not set" to domain1 + mptAlice.set({.domainID = domainId1}); + BEAST_EXPECT(mptAlice.checkDomainID(domainId1)); + + // reset domain1 to domain2 + mptAlice.set({.domainID = domainId2}); + BEAST_EXPECT(mptAlice.checkDomainID(domainId2)); + + // reset domain to "domain not set" + mptAlice.set({.domainID = beast::zero}); + BEAST_EXPECT(mptAlice.checkDomainID(std::nullopt)); + } } void @@ -889,6 +1144,200 @@ class MPToken_test : public beast::unit_test::suite mptAlice.pay(bob, alice, 100, tecNO_AUTH); } + if (features[featureSingleAssetVault] && + features[featurePermissionedDomains]) + { + // If RequireAuth is enabled and domain is a match, payment succeeds + { + Env env{*this, features}; + std::string const credType = "credential"; + Account const credIssuer1{"credIssuer1"}; + env.fund(XRP(1000), credIssuer1, bob); + + auto const domainId1 = [&]() { + pdomain::Credentials const credentials1{ + {.issuer = credIssuer1, .credType = credType}}; + + env(pdomain::setTx(credIssuer1, credentials1)); + return [&]() { + auto tx = env.tx()->getJson(JsonOptions::none); + return pdomain::getNewDomain(env.meta()); + }(); + }(); + // bob is authorized via domain + env(credentials::create(bob, credIssuer1, credType)); + env(credentials::accept(bob, credIssuer1, credType)); + env.close(); + + MPTTester mptAlice(env, alice, {}); + env.close(); + + mptAlice.create({ + .ownerCount = 1, + .holderCount = 0, + .flags = tfMPTRequireAuth | tfMPTCanTransfer, + .domainID = domainId1, + }); + + mptAlice.authorize({.account = bob}); + env.close(); + + // bob is authorized via domain + mptAlice.pay(alice, bob, 100); + mptAlice.set({.domainID = beast::zero}); + + // bob is no longer authorized + mptAlice.pay(alice, bob, 100, tecNO_AUTH); + } + + { + Env env{*this, features}; + std::string const credType = "credential"; + Account const credIssuer1{"credIssuer1"}; + env.fund(XRP(1000), credIssuer1, bob); + + auto const domainId1 = [&]() { + pdomain::Credentials const credentials1{ + {.issuer = credIssuer1, .credType = credType}}; + + env(pdomain::setTx(credIssuer1, credentials1)); + return [&]() { + auto tx = env.tx()->getJson(JsonOptions::none); + return pdomain::getNewDomain(env.meta()); + }(); + }(); + // bob is authorized via domain + env(credentials::create(bob, credIssuer1, credType)); + env(credentials::accept(bob, credIssuer1, credType)); + env.close(); + + MPTTester mptAlice(env, alice, {}); + env.close(); + + mptAlice.create({ + .ownerCount = 1, + .holderCount = 0, + .flags = tfMPTRequireAuth | tfMPTCanTransfer, + .domainID = domainId1, + }); + + // bob creates an empty MPToken + mptAlice.authorize({.account = bob}); + + // alice authorizes bob to hold funds + mptAlice.authorize({.account = alice, .holder = bob}); + + // alice sends 100 MPT to bob + mptAlice.pay(alice, bob, 100); + + // alice UNAUTHORIZES bob + mptAlice.authorize( + {.account = alice, + .holder = bob, + .flags = tfMPTUnauthorize}); + + // bob is still authorized, via domain + mptAlice.pay(bob, alice, 10); + + mptAlice.set({.domainID = beast::zero}); + + // bob fails to send back to alice because he is no longer + // authorize to move his funds! + mptAlice.pay(bob, alice, 10, tecNO_AUTH); + } + + { + Env env{*this, features}; + std::string const credType = "credential"; + // credIssuer1 is the owner of domainId1 and a credential issuer + Account const credIssuer1{"credIssuer1"}; + // credIssuer2 is the owner of domainId2 and a credential issuer + // Note, domainId2 also lists credentials issued by credIssuer1 + Account const credIssuer2{"credIssuer2"}; + env.fund(XRP(1000), credIssuer1, credIssuer2, bob, carol); + + auto const domainId1 = [&]() { + pdomain::Credentials const credentials{ + {.issuer = credIssuer1, .credType = credType}}; + + env(pdomain::setTx(credIssuer1, credentials)); + return [&]() { + auto tx = env.tx()->getJson(JsonOptions::none); + return pdomain::getNewDomain(env.meta()); + }(); + }(); + + auto const domainId2 = [&]() { + pdomain::Credentials const credentials{ + {.issuer = credIssuer1, .credType = credType}, + {.issuer = credIssuer2, .credType = credType}}; + + env(pdomain::setTx(credIssuer2, credentials)); + return [&]() { + auto tx = env.tx()->getJson(JsonOptions::none); + return pdomain::getNewDomain(env.meta()); + }(); + }(); + + // bob is authorized via credIssuer1 which is recognized by both + // domainId1 and domainId2 + env(credentials::create(bob, credIssuer1, credType)); + env(credentials::accept(bob, credIssuer1, credType)); + env.close(); + + // carol is authorized via credIssuer2, only recognized by + // domainId2 + env(credentials::create(carol, credIssuer2, credType)); + env(credentials::accept(carol, credIssuer2, credType)); + env.close(); + + MPTTester mptAlice(env, alice, {}); + env.close(); + + mptAlice.create({ + .ownerCount = 1, + .holderCount = 0, + .flags = tfMPTRequireAuth | tfMPTCanTransfer, + .domainID = domainId1, + }); + + // bob and carol create an empty MPToken + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + env.close(); + + // alice sends 50 MPT to bob but cannot send to carol + mptAlice.pay(alice, bob, 50); + mptAlice.pay(alice, carol, 50, tecNO_AUTH); + env.close(); + + // bob cannot send to carol because they are not on the same + // domain (since credIssuer2 is not recognized by domainId1) + mptAlice.pay(bob, carol, 10, tecNO_AUTH); + env.close(); + + // alice updates domainID to domainId2 which recognizes both + // credIssuer1 and credIssuer2 + mptAlice.set({.domainID = domainId2}); + // alice can now send to carol + mptAlice.pay(alice, carol, 10); + env.close(); + + // bob can now send to carol because both are in the same + // domain + mptAlice.pay(bob, carol, 10); + env.close(); + + // bob loses his authorization and can no longer send MPT + env(credentials::deleteCred( + credIssuer1, bob, credIssuer1, credType)); + env.close(); + + mptAlice.pay(bob, carol, 10, tecNO_AUTH); + mptAlice.pay(bob, alice, 10, tecNO_AUTH); + } + } + // Non-issuer cannot send to each other if MPTCanTransfer isn't set { Env env(*this, features); @@ -1340,10 +1789,8 @@ class MPToken_test : public beast::unit_test::suite } void - testDepositPreauth() + testDepositPreauth(FeatureBitset features) { - testcase("DepositPreauth"); - using namespace test::jtx; Account const alice("alice"); // issuer Account const bob("bob"); // holder @@ -1352,8 +1799,11 @@ class MPToken_test : public beast::unit_test::suite char const credType[] = "abcde"; + if (features[featureCredentials]) { - Env env(*this); + testcase("DepositPreauth"); + + Env env(*this, features); env.fund(XRP(50000), diana, dpIssuer); env.close(); @@ -1428,7 +1878,7 @@ class MPToken_test : public beast::unit_test::suite testcase("DepositPreauth disabled featureCredentials"); { - Env env(*this, supported_amendments() - featureCredentials); + Env env(*this, testable_amendments() - featureCredentials); std::string const credIdx = "D007AE4B6E1274B4AF872588267B810C2F82716726351D1C7D38D3E5499FC6" @@ -2293,10 +2743,12 @@ class MPToken_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; // MPTokenIssuanceCreate testCreateValidation(all - featureSingleAssetVault); + testCreateValidation( + (all | featureSingleAssetVault) - featurePermissionedDomains); testCreateValidation(all | featureSingleAssetVault); testCreateEnabled(all - featureSingleAssetVault); testCreateEnabled(all | featureSingleAssetVault); @@ -2314,7 +2766,11 @@ class MPToken_test : public beast::unit_test::suite testAuthorizeEnabled(all | featureSingleAssetVault); // MPTokenIssuanceSet - testSetValidation(all); + testSetValidation(all - featureSingleAssetVault); + testSetValidation( + (all | featureSingleAssetVault) - featurePermissionedDomains); + testSetValidation(all | featureSingleAssetVault); + testSetEnabled(all - featureSingleAssetVault); testSetEnabled(all | featureSingleAssetVault); @@ -2323,8 +2779,9 @@ class MPToken_test : public beast::unit_test::suite testClawback(all); // Test Direct Payment - testPayment(all); - testDepositPreauth(); + testPayment(all | featureSingleAssetVault); + testDepositPreauth(all); + testDepositPreauth(all - featureCredentials); // Test MPT Amount is invalid in Tx, which don't support MPT testMPTInvalidInTx(all); @@ -2340,7 +2797,7 @@ class MPToken_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(MPToken, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(MPToken, app, ripple, 2); } // namespace test } // namespace ripple diff --git a/src/test/app/MultiSign_test.cpp b/src/test/app/MultiSign_test.cpp index 8c1880c1a03..571ec33417d 100644 --- a/src/test/app/MultiSign_test.cpp +++ b/src/test/app/MultiSign_test.cpp @@ -1478,7 +1478,7 @@ class MultiSign_test : public beast::unit_test::suite Account const cheri{"cheri", KeyType::secp256k1}; Account const daria{"daria", KeyType::ed25519}; - Env env{*this, supported_amendments() - featureMultiSignReserve}; + Env env{*this, testable_amendments() - featureMultiSignReserve}; env.fund(XRP(1000), alice, becky, cheri, daria); env.close(); @@ -1729,7 +1729,7 @@ class MultiSign_test : public beast::unit_test::suite run() override { using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); // The reserve required on a signer list changes based on // featureMultiSignReserve. Limits on the number of signers diff --git a/src/test/app/NFTokenAuth_test.cpp b/src/test/app/NFTokenAuth_test.cpp index 9558a03f7ae..f5eedfce77a 100644 --- a/src/test/app/NFTokenAuth_test.cpp +++ b/src/test/app/NFTokenAuth_test.cpp @@ -599,7 +599,7 @@ class NFTokenAuth_test : public beast::unit_test::suite run() override { using namespace test::jtx; - static FeatureBitset const all{supported_amendments()}; + static FeatureBitset const all{testable_amendments()}; static std::array const features = { all - fixEnforceNFTokenTrustlineV2, all}; @@ -619,6 +619,6 @@ class NFTokenAuth_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAuth, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAuth, app, ripple, 2); } // namespace ripple \ No newline at end of file diff --git a/src/test/app/NFTokenBurn_test.cpp b/src/test/app/NFTokenBurn_test.cpp index a970b11789d..44c55f2b8c8 100644 --- a/src/test/app/NFTokenBurn_test.cpp +++ b/src/test/app/NFTokenBurn_test.cpp @@ -1385,7 +1385,7 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite run(std::uint32_t instance, bool last = false) { using namespace test::jtx; - static FeatureBitset const all{supported_amendments()}; + static FeatureBitset const all{testable_amendments()}; static FeatureBitset const fixNFTV1_2{fixNonFungibleTokensV1_2}; static FeatureBitset const fixNFTDir{fixNFTokenDirV1}; static FeatureBitset const fixNFTRemint{fixNFTokenRemint}; @@ -1454,10 +1454,10 @@ class NFTokenBurnAllFeatures_test : public NFTokenBurnBaseUtil_test } }; -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnBaseUtil, tx, ripple, 3); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOfixFungTokens, tx, ripple, 3); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOFixTokenRemint, tx, ripple, 3); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOFixNFTPageLinks, tx, ripple, 3); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnAllFeatures, tx, ripple, 3); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnBaseUtil, app, ripple, 3); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOfixFungTokens, app, ripple, 3); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOFixTokenRemint, app, ripple, 3); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOFixNFTPageLinks, app, ripple, 3); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnAllFeatures, app, ripple, 3); } // namespace ripple diff --git a/src/test/app/NFTokenDir_test.cpp b/src/test/app/NFTokenDir_test.cpp index fe21e027393..a63653d8dcf 100644 --- a/src/test/app/NFTokenDir_test.cpp +++ b/src/test/app/NFTokenDir_test.cpp @@ -1100,7 +1100,7 @@ class NFTokenDir_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; FeatureBitset const fixNFTDir{ fixNFTokenDirV1, featureNonFungibleTokensV1_1}; @@ -1110,7 +1110,7 @@ class NFTokenDir_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDir, tx, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDir, app, ripple, 1); } // namespace ripple diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 41bcc673d57..1c4314643cb 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -8075,7 +8075,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite run(std::uint32_t instance, bool last = false) { using namespace test::jtx; - static FeatureBitset const all{supported_amendments()}; + static FeatureBitset const all{testable_amendments()}; static FeatureBitset const fixNFTDir{fixNFTokenDirV1}; static std::array const feats{ @@ -8171,13 +8171,13 @@ class NFTokenAllFeatures_test : public NFTokenBaseUtil_test } }; -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBaseUtil, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBaseUtil, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, app, ripple, 2); } // namespace ripple diff --git a/src/test/app/OfferStream_test.cpp b/src/test/app/OfferStream_test.cpp index 691d327cd82..35f38da29a5 100644 --- a/src/test/app/OfferStream_test.cpp +++ b/src/test/app/OfferStream_test.cpp @@ -39,6 +39,6 @@ class OfferStream_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(OfferStream, tx, ripple); +BEAST_DEFINE_TESTSUITE(OfferStream, app, ripple); } // namespace ripple diff --git a/src/test/app/Offer_test.cpp b/src/test/app/Offer_test.cpp index 0891b27df8b..aa647925fa3 100644 --- a/src/test/app/Offer_test.cpp +++ b/src/test/app/Offer_test.cpp @@ -1343,18 +1343,10 @@ class OfferBaseUtil_test : public beast::unit_test::suite // NOTE : // At this point, all offers are expected to be consumed. - // Alas, they are not - because of a bug in the Taker auto-bridging - // implementation which is addressed by fixTakerDryOfferRemoval. - // The pre-fixTakerDryOfferRemoval implementation (incorrect) leaves - // an empty offer in the second leg of the bridge. Validate both the - // old and the new behavior. { auto acctOffers = offersOnAccount(env, account_to_test); - bool const noStaleOffers{ - features[featureFlowCross] || - features[fixTakerDryOfferRemoval]}; - BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1)); + BEAST_EXPECT(acctOffers.size() == 0); for (auto const& offerPtr : acctOffers) { auto const& offer = *offerPtr; @@ -1464,8 +1456,7 @@ class OfferBaseUtil_test : public beast::unit_test::suite std::uint32_t const bobOfferSeq = env.seq(bob); env(offer(bob, XRP(2000), USD(1))); - if (localFeatures[featureFlowCross] && - localFeatures[fixReducedOffersV2]) + if (localFeatures[fixReducedOffersV2]) { // With the rounding introduced by fixReducedOffersV2, bob's // offer does not cross alice's offer and goes straight into @@ -1489,8 +1480,7 @@ class OfferBaseUtil_test : public beast::unit_test::suite // crossing algorithms becomes apparent. The old offer crossing // would consume small_amount and transfer no XRP. The new offer // crossing transfers a single drop, rather than no drops. - auto const crossingDelta = - localFeatures[featureFlowCross] ? drops(1) : drops(0); + auto const crossingDelta = drops(1); jrr = ledgerEntryState(env, alice, gw, "USD"); BEAST_EXPECT( @@ -2044,15 +2034,9 @@ class OfferBaseUtil_test : public beast::unit_test::suite env.require(balance(carol, USD(0))); env.require(balance(carol, EUR(none))); - // If neither featureFlowCross nor fixTakerDryOfferRemoval are defined - // then carol's offer will be left on the books, but with zero value. - int const emptyOfferCount{ - features[featureFlowCross] || features[fixTakerDryOfferRemoval] - ? 0 - : 1}; - - env.require(offers(carol, 0 + emptyOfferCount)); - env.require(owners(carol, 1 + emptyOfferCount)); + + env.require(offers(carol, 0)); + env.require(owners(carol, 1)); } void @@ -3643,9 +3627,7 @@ class OfferBaseUtil_test : public beast::unit_test::suite using namespace jtx; - // The problem was identified when featureOwnerPaysFee was enabled, - // so make sure that gets included. - Env env{*this, features | featureOwnerPaysFee}; + Env env{*this, features}; // The fee that's charged for transactions. auto const fee = env.current()->fees().base; @@ -4238,22 +4220,13 @@ class OfferBaseUtil_test : public beast::unit_test::suite }; // clang-format off - TestData const takerTests[]{ - // btcStart ------------------- actor[0] -------------------- ------------------- actor[1] -------------------- - {0, 0, 1, BTC(5), {{"deb", 0, drops(3900000'000000 - 4 * baseFee), BTC(5), USD(3000)}, {"dan", 0, drops(4100000'000000 - 3 * baseFee), BTC(0), USD(750)}}}, // no BTC xfer fee - {0, 0, 0, BTC(5), {{"flo", 0, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }} // no xfer fee - }; - - TestData const flowTests[]{ + TestData const tests[]{ // btcStart ------------------- actor[0] -------------------- ------------------- actor[1] -------------------- {0, 0, 1, BTC(5), {{"gay", 1, drops(3950000'000000 - 4 * baseFee), BTC(5), USD(2500)}, {"gar", 1, drops(4050000'000000 - 3 * baseFee), BTC(0), USD(1375)}}}, // no BTC xfer fee {0, 0, 0, BTC(5), {{"hye", 2, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }} // no xfer fee }; // clang-format on - // Pick the right tests. - auto const& tests = features[featureFlowCross] ? flowTests : takerTests; - for (auto const& t : tests) { Account const& self = t.actors[t.self].acct; @@ -4380,9 +4353,8 @@ class OfferBaseUtil_test : public beast::unit_test::suite // 1. alice creates an offer to acquire USD/gw, an asset for which // she does not have a trust line. At some point in the future, // gw adds lsfRequireAuth. Then, later, alice's offer is crossed. - // a. With Taker alice's unauthorized offer is consumed. - // b. With FlowCross alice's offer is deleted, not consumed, - // since alice is not authorized to hold USD/gw. + // Alice's offer is deleted, not consumed, since alice is not + // authorized to hold USD/gw. // // 2. alice tries to create an offer for USD/gw, now that gw has // lsfRequireAuth set. This time the offer create fails because @@ -4430,33 +4402,17 @@ class OfferBaseUtil_test : public beast::unit_test::suite // gw now requires authorization and bob has gwUSD(50). Let's see if // bob can cross alice's offer. // - // o With Taker bob's offer should cross alice's. - // o With FlowCross bob's offer shouldn't cross and alice's - // unauthorized offer should be deleted. + // Bob's offer shouldn't cross and alice's unauthorized offer should be + // deleted. env(offer(bob, XRP(4000), gwUSD(40))); env.close(); std::uint32_t const bobOfferSeq = env.seq(bob) - 1; - bool const flowCross = features[featureFlowCross]; - env.require(offers(alice, 0)); - if (flowCross) - { - // alice's unauthorized offer is deleted & bob's offer not crossed. - env.require(balance(alice, gwUSD(none))); - env.require(offers(bob, 1)); - env.require(balance(bob, gwUSD(50))); - } - else - { - // alice's offer crosses bob's - env.require(balance(alice, gwUSD(40))); - env.require(offers(bob, 0)); - env.require(balance(bob, gwUSD(10))); - - // The rest of the test verifies FlowCross behavior. - return; - } + // alice's unauthorized offer is deleted & bob's offer not crossed. + env.require(balance(alice, gwUSD(none))); + env.require(offers(bob, 1)); + env.require(balance(bob, gwUSD(50))); // See if alice can create an offer without authorization. alice // should not be able to create the offer and bob's offer should be @@ -5188,9 +5144,7 @@ class OfferBaseUtil_test : public beast::unit_test::suite // tfFillOrKill, TakerPays must be filled { TER const err = - features[fixFillOrKill] || !features[featureFlowCross] - ? TER(tesSUCCESS) - : tecKILLED; + features[fixFillOrKill] ? TER(tesSUCCESS) : tecKILLED; env(offer(maker, XRP(100), USD(100))); env.close(); @@ -5411,8 +5365,7 @@ class OfferBaseUtil_test : public beast::unit_test::suite run(std::uint32_t instance, bool last = false) { using namespace jtx; - static FeatureBitset const all{supported_amendments()}; - static FeatureBitset const flowCross{featureFlowCross}; + static FeatureBitset const all{testable_amendments()}; static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval}; static FeatureBitset const rmSmallIncreasedQOffers{ fixRmSmallIncreasedQOffers}; @@ -5421,10 +5374,9 @@ class OfferBaseUtil_test : public beast::unit_test::suite FeatureBitset const fillOrKill{fixFillOrKill}; FeatureBitset const permDEX{featurePermissionedDEX}; - static std::array const feats{ + static std::array const feats{ all - takerDryOffer - immediateOfferKilled - permDEX, - all - flowCross - takerDryOffer - immediateOfferKilled - permDEX, - all - flowCross - immediateOfferKilled - permDEX, + all - immediateOfferKilled - permDEX, all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill - permDEX, all - fillOrKill - permDEX, @@ -5446,21 +5398,12 @@ class OfferBaseUtil_test : public beast::unit_test::suite } }; -class OfferWOFlowCross_test : public OfferBaseUtil_test -{ - void - run() override - { - OfferBaseUtil_test::run(1); - } -}; - class OfferWTakerDryOffer_test : public OfferBaseUtil_test { void run() override { - OfferBaseUtil_test::run(2); + OfferBaseUtil_test::run(1); } }; @@ -5469,7 +5412,7 @@ class OfferWOSmallQOffers_test : public OfferBaseUtil_test void run() override { - OfferBaseUtil_test::run(3); + OfferBaseUtil_test::run(2); } }; @@ -5478,7 +5421,7 @@ class OfferWOFillOrKill_test : public OfferBaseUtil_test void run() override { - OfferBaseUtil_test::run(4); + OfferBaseUtil_test::run(3); } }; @@ -5487,7 +5430,7 @@ class OfferWOPermDEX_test : public OfferBaseUtil_test void run() override { - OfferBaseUtil_test::run(5); + OfferBaseUtil_test::run(4); } }; @@ -5496,7 +5439,7 @@ class OfferAllFeatures_test : public OfferBaseUtil_test void run() override { - OfferBaseUtil_test::run(6, true); + OfferBaseUtil_test::run(5, true); } }; @@ -5506,33 +5449,30 @@ class Offer_manual_test : public OfferBaseUtil_test run() override { using namespace jtx; - FeatureBitset const all{supported_amendments()}; - FeatureBitset const flowCross{featureFlowCross}; + FeatureBitset const all{testable_amendments()}; FeatureBitset const f1513{fix1513}; FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled}; FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval}; FeatureBitset const fillOrKill{fixFillOrKill}; FeatureBitset const permDEX{featurePermissionedDEX}; - testAll(all - flowCross - f1513 - immediateOfferKilled - permDEX); - testAll(all - flowCross - immediateOfferKilled - permDEX); + testAll(all - f1513 - immediateOfferKilled - permDEX); testAll(all - immediateOfferKilled - fillOrKill - permDEX); testAll(all - fillOrKill - permDEX); testAll(all - permDEX); testAll(all); - testAll(all - flowCross - takerDryOffer - permDEX); + testAll(all - takerDryOffer - permDEX); } }; -BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, tx, ripple, 20); +BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, app, ripple, 20); } // namespace test } // namespace ripple diff --git a/src/test/app/Oracle_test.cpp b/src/test/app/Oracle_test.cpp index a968970395e..fdd7ad941e6 100644 --- a/src/test/app/Oracle_test.cpp +++ b/src/test/app/Oracle_test.cpp @@ -678,6 +678,61 @@ struct Oracle_test : public beast::unit_test::suite oracle.set( UpdateArg{.series = {{"XRP", "USD", 742, 2}}, .fee = baseFee}); } + + for (bool const withFixOrder : {false, true}) + { + // Should be same order as creation + Env env( + *this, + withFixOrder ? testable_amendments() + : testable_amendments() - fixPriceOracleOrder); + auto const baseFee = + static_cast(env.current()->fees().base.drops()); + + auto test = [&](Env& env, DataSeries const& series) { + env.fund(XRP(1'000), owner); + Oracle oracle( + env, {.owner = owner, .series = series, .fee = baseFee}); + BEAST_EXPECT(oracle.exists()); + auto sle = env.le(keylet::oracle(owner, oracle.documentID())); + BEAST_EXPECT( + sle->getFieldArray(sfPriceDataSeries).size() == + series.size()); + + auto const beforeQuoteAssetName1 = + sle->getFieldArray(sfPriceDataSeries)[0] + .getFieldCurrency(sfQuoteAsset) + .getText(); + auto const beforeQuoteAssetName2 = + sle->getFieldArray(sfPriceDataSeries)[1] + .getFieldCurrency(sfQuoteAsset) + .getText(); + + oracle.set(UpdateArg{.series = series, .fee = baseFee}); + sle = env.le(keylet::oracle(owner, oracle.documentID())); + + auto const afterQuoteAssetName1 = + sle->getFieldArray(sfPriceDataSeries)[0] + .getFieldCurrency(sfQuoteAsset) + .getText(); + auto const afterQuoteAssetName2 = + sle->getFieldArray(sfPriceDataSeries)[1] + .getFieldCurrency(sfQuoteAsset) + .getText(); + + if (env.current()->rules().enabled(fixPriceOracleOrder)) + { + BEAST_EXPECT(afterQuoteAssetName1 == beforeQuoteAssetName1); + BEAST_EXPECT(afterQuoteAssetName2 == beforeQuoteAssetName2); + } + else + { + BEAST_EXPECT(afterQuoteAssetName1 != beforeQuoteAssetName1); + BEAST_EXPECT(afterQuoteAssetName2 != beforeQuoteAssetName2); + } + }; + test(env, {{"XRP", "USD", 742, 2}, {"XRP", "EUR", 711, 2}}); + } } void @@ -783,7 +838,7 @@ struct Oracle_test : public beast::unit_test::suite testcase("Amendment"); using namespace jtx; - auto const features = supported_amendments() - featurePriceOracle; + auto const features = testable_amendments() - featurePriceOracle; Account const owner("owner"); Env env(*this, features); auto const baseFee = @@ -806,7 +861,7 @@ struct Oracle_test : public beast::unit_test::suite run() override { using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); testInvalidSet(); testInvalidDelete(); testCreate(); diff --git a/src/test/app/OversizeMeta_test.cpp b/src/test/app/OversizeMeta_test.cpp index f6e4466bab3..fb6faa3ec31 100644 --- a/src/test/app/OversizeMeta_test.cpp +++ b/src/test/app/OversizeMeta_test.cpp @@ -61,7 +61,7 @@ class PlumpBook_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(PlumpBook, tx, ripple, 5); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(PlumpBook, app, ripple, 5); //------------------------------------------------------------------------------ @@ -76,7 +76,7 @@ class ThinBook_test : public PlumpBook_test } }; -BEAST_DEFINE_TESTSUITE(ThinBook, tx, ripple); +BEAST_DEFINE_TESTSUITE(ThinBook, app, ripple); //------------------------------------------------------------------------------ @@ -119,7 +119,7 @@ class OversizeMeta_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(OversizeMeta, tx, ripple, 3); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(OversizeMeta, app, ripple, 3); //------------------------------------------------------------------------------ @@ -185,7 +185,7 @@ class FindOversizeCross_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(FindOversizeCross, tx, ripple, 50); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(FindOversizeCross, app, ripple, 50); } // namespace test } // namespace ripple diff --git a/src/test/app/PayChan_test.cpp b/src/test/app/PayChan_test.cpp index 7cb1542453c..3a5d3d6ff5e 100644 --- a/src/test/app/PayChan_test.cpp +++ b/src/test/app/PayChan_test.cpp @@ -1035,7 +1035,7 @@ struct PayChan_test : public beast::unit_test::suite { // Credentials amendment not enabled - Env env(*this, supported_amendments() - featureCredentials); + Env env(*this, testable_amendments() - featureCredentials); env.fund(XRP(5000), "alice", "bob"); env.close(); @@ -2344,7 +2344,7 @@ struct PayChan_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testWithFeats(all - disallowIncoming); testWithFeats(all); testDepositAuthCreds(); diff --git a/src/test/app/PayStrand_test.cpp b/src/test/app/PayStrand_test.cpp index 9188da62ac4..936fe403d4e 100644 --- a/src/test/app/PayStrand_test.cpp +++ b/src/test/app/PayStrand_test.cpp @@ -1267,16 +1267,13 @@ struct PayStrand_test : public beast::unit_test::suite run() override { using namespace jtx; - auto const sa = supported_amendments(); - testToStrand(sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); testToStrand(sa - featurePermissionedDEX); testToStrand(sa); - testRIPD1373(sa - featureFlowCross - featurePermissionedDEX); testRIPD1373(sa - featurePermissionedDEX); testRIPD1373(sa); - testLoop(sa - featureFlowCross - featurePermissionedDEX); testLoop(sa - featurePermissionedDEX); testLoop(sa); diff --git a/src/test/app/PermissionedDEX_test.cpp b/src/test/app/PermissionedDEX_test.cpp index 693381debfc..3fd3a35f45e 100644 --- a/src/test/app/PermissionedDEX_test.cpp +++ b/src/test/app/PermissionedDEX_test.cpp @@ -207,24 +207,6 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); } - // test preflight: permissioned dex cannot be used without enable - // flowcross - { - Env env(*this, features - featureFlowCross); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); - - env(offer(bob, XRP(10), USD(10)), - domain(domainID), - ter(temDISABLED)); - env.close(); - - env.enableFeature(featureFlowCross); - env.close(); - env(offer(bob, XRP(10), USD(10)), domain(domainID)); - env.close(); - } - // preclaim - someone outside of the domain cannot create domain offer { Env env(*this, features); @@ -1569,7 +1551,7 @@ class PermissionedDEX_test : public beast::unit_test::suite void run() override { - FeatureBitset const all{jtx::supported_amendments()}; + FeatureBitset const all{jtx::testable_amendments()}; // Test domain offer (w/o hyrbid) testOfferCreate(all); diff --git a/src/test/app/PermissionedDomains_test.cpp b/src/test/app/PermissionedDomains_test.cpp index e33a88fa082..31e34ccf170 100644 --- a/src/test/app/PermissionedDomains_test.cpp +++ b/src/test/app/PermissionedDomains_test.cpp @@ -53,9 +53,9 @@ exceptionExpected(Env& env, Json::Value const& jv) class PermissionedDomains_test : public beast::unit_test::suite { FeatureBitset withoutFeature_{ - supported_amendments() - featurePermissionedDomains}; + testable_amendments() - featurePermissionedDomains}; FeatureBitset withFeature_{ - supported_amendments() // + testable_amendments() // | featurePermissionedDomains | featureCredentials}; // Verify that each tx type can execute if the feature is enabled. @@ -81,7 +81,7 @@ class PermissionedDomains_test : public beast::unit_test::suite void testCredentialsDisabled() { - auto amendments = supported_amendments(); + auto amendments = testable_amendments(); amendments.set(featurePermissionedDomains); amendments.reset(featureCredentials); testcase("Credentials disabled"); diff --git a/src/test/app/PseudoTx_test.cpp b/src/test/app/PseudoTx_test.cpp index d96828a50b4..53adf795c25 100644 --- a/src/test/app/PseudoTx_test.cpp +++ b/src/test/app/PseudoTx_test.cpp @@ -115,7 +115,7 @@ struct PseudoTx_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; FeatureBitset const xrpFees{featureXRPFees}; testPrevented(all - featureXRPFees); diff --git a/src/test/app/RCLValidations_test.cpp b/src/test/app/RCLValidations_test.cpp index 31c38f23b1c..fce4e94048d 100644 --- a/src/test/app/RCLValidations_test.cpp +++ b/src/test/app/RCLValidations_test.cpp @@ -229,7 +229,6 @@ class RCLValidations_test : public beast::unit_test::suite // support for a ledger hash which is already in the trie. using Seq = RCLValidatedLedger::Seq; - using ID = RCLValidatedLedger::ID; // Max known ancestors for each ledger Seq const maxAncestors = 256; diff --git a/src/test/app/ReducedOffer_test.cpp b/src/test/app/ReducedOffer_test.cpp index 546a07d93e6..fa2be451fa7 100644 --- a/src/test/app/ReducedOffer_test.cpp +++ b/src/test/app/ReducedOffer_test.cpp @@ -82,8 +82,8 @@ class ReducedOffer_test : public beast::unit_test::suite // Make one test run without fixReducedOffersV1 and one with. for (FeatureBitset features : - {supported_amendments() - fixReducedOffersV1, - supported_amendments() | fixReducedOffersV1}) + {testable_amendments() - fixReducedOffersV1, + testable_amendments() | fixReducedOffersV1}) { Env env{*this, features}; @@ -238,8 +238,8 @@ class ReducedOffer_test : public beast::unit_test::suite // Make one test run without fixReducedOffersV1 and one with. for (FeatureBitset features : - {supported_amendments() - fixReducedOffersV1, - supported_amendments() | fixReducedOffersV1}) + {testable_amendments() - fixReducedOffersV1, + testable_amendments() | fixReducedOffersV1}) { // Make sure none of the offers we generate are under funded. Env env{*this, features}; @@ -401,8 +401,8 @@ class ReducedOffer_test : public beast::unit_test::suite // Make one test run without fixReducedOffersV1 and one with. for (FeatureBitset features : - {supported_amendments() - fixReducedOffersV1, - supported_amendments() | fixReducedOffersV1}) + {testable_amendments() - fixReducedOffersV1, + testable_amendments() | fixReducedOffersV1}) { Env env{*this, features}; @@ -509,8 +509,8 @@ class ReducedOffer_test : public beast::unit_test::suite // Make one test run without fixReducedOffersV1 and one with. for (FeatureBitset features : - {supported_amendments() - fixReducedOffersV1, - supported_amendments() | fixReducedOffersV1}) + {testable_amendments() - fixReducedOffersV1, + testable_amendments() | fixReducedOffersV1}) { Env env{*this, features}; @@ -639,8 +639,8 @@ class ReducedOffer_test : public beast::unit_test::suite // Make one test run without fixReducedOffersV2 and one with. for (FeatureBitset features : - {supported_amendments() - fixReducedOffersV2, - supported_amendments() | fixReducedOffersV2}) + {testable_amendments() - fixReducedOffersV2, + testable_amendments() | fixReducedOffersV2}) { // Make sure none of the offers we generate are under funded. Env env{*this, features}; @@ -800,7 +800,7 @@ class ReducedOffer_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(ReducedOffer, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(ReducedOffer, app, ripple, 2); } // namespace test } // namespace ripple diff --git a/src/test/app/SetAuth_test.cpp b/src/test/app/SetAuth_test.cpp index a4c2df6228b..dfa831a72e7 100644 --- a/src/test/app/SetAuth_test.cpp +++ b/src/test/app/SetAuth_test.cpp @@ -74,14 +74,13 @@ struct SetAuth_test : public beast::unit_test::suite run() override { using namespace jtx; - auto const sa = supported_amendments(); - testAuth(sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); testAuth(sa - featurePermissionedDEX); testAuth(sa); } }; -BEAST_DEFINE_TESTSUITE(SetAuth, test, ripple); +BEAST_DEFINE_TESTSUITE(SetAuth, app, ripple); } // namespace test } // namespace ripple diff --git a/src/test/app/SetRegularKey_test.cpp b/src/test/app/SetRegularKey_test.cpp index 6a3a5ff2a95..78b75fc458f 100644 --- a/src/test/app/SetRegularKey_test.cpp +++ b/src/test/app/SetRegularKey_test.cpp @@ -32,7 +32,7 @@ class SetRegularKey_test : public beast::unit_test::suite using namespace test::jtx; testcase("Set regular key"); - Env env{*this, supported_amendments() - fixMasterKeyAsRegularKey}; + Env env{*this, testable_amendments() - fixMasterKeyAsRegularKey}; Account const alice("alice"); Account const bob("bob"); env.fund(XRP(10000), alice, bob); @@ -72,7 +72,7 @@ class SetRegularKey_test : public beast::unit_test::suite using namespace test::jtx; testcase("Set regular key"); - Env env{*this, supported_amendments() | fixMasterKeyAsRegularKey}; + Env env{*this, testable_amendments() | fixMasterKeyAsRegularKey}; Account const alice("alice"); Account const bob("bob"); env.fund(XRP(10000), alice, bob); @@ -109,7 +109,7 @@ class SetRegularKey_test : public beast::unit_test::suite // See https://ripplelabs.atlassian.net/browse/RIPD-1721. testcase( "Set regular key to master key (before fixMasterKeyAsRegularKey)"); - Env env{*this, supported_amendments() - fixMasterKeyAsRegularKey}; + Env env{*this, testable_amendments() - fixMasterKeyAsRegularKey}; Account const alice("alice"); env.fund(XRP(10000), alice); @@ -139,7 +139,7 @@ class SetRegularKey_test : public beast::unit_test::suite testcase( "Set regular key to master key (after fixMasterKeyAsRegularKey)"); - Env env{*this, supported_amendments() | fixMasterKeyAsRegularKey}; + Env env{*this, testable_amendments() | fixMasterKeyAsRegularKey}; Account const alice("alice"); env.fund(XRP(10000), alice); diff --git a/src/test/app/SetTrust_test.cpp b/src/test/app/SetTrust_test.cpp index 9b4048bf9c2..18457b5fafe 100644 --- a/src/test/app/SetTrust_test.cpp +++ b/src/test/app/SetTrust_test.cpp @@ -648,7 +648,7 @@ class SetTrust_test : public beast::unit_test::suite run() override { using namespace test::jtx; - auto const sa = supported_amendments(); + auto const sa = testable_amendments(); testWithFeats(sa - disallowIncoming); testWithFeats(sa); } diff --git a/src/test/app/Taker_test.cpp b/src/test/app/Taker_test.cpp deleted file mode 100644 index 3b3f338625c..00000000000 --- a/src/test/app/Taker_test.cpp +++ /dev/null @@ -1,1394 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include - -#include - -namespace ripple { - -class Taker_test : public beast::unit_test::suite -{ - static bool const Buy = false; - static bool const Sell = true; - - class TestTaker : public BasicTaker - { - STAmount funds_; - STAmount cross_funds; - - public: - TestTaker( - CrossType cross_type, - Amounts const& amount, - Quality const& quality, - STAmount const& funds, - std::uint32_t flags, - Rate const& rate_in, - Rate const& rate_out) - : BasicTaker( - cross_type, - AccountID(0x4701), - amount, - quality, - flags, - rate_in, - rate_out) - , funds_(funds) - { - } - - void - set_funds(STAmount const& funds) - { - cross_funds = funds; - } - - STAmount - get_funds(AccountID const& owner, STAmount const& funds) const override - { - if (owner == account()) - return funds_; - - return cross_funds; - } - - Amounts - cross(Amounts offer, Quality quality) - { - if (reject(quality)) - return Amounts(offer.in.zeroed(), offer.out.zeroed()); - - // we need to emulate "unfunded offers" behavior - if (get_funds(AccountID(0x4702), offer.out) == beast::zero) - return Amounts(offer.in.zeroed(), offer.out.zeroed()); - - if (done()) - return Amounts(offer.in.zeroed(), offer.out.zeroed()); - - auto result = do_cross(offer, quality, AccountID(0x4702)); - - funds_ -= result.order.in; - - return result.order; - } - - std::pair - cross( - Amounts offer1, - Quality quality1, - Amounts offer2, - Quality quality2) - { - /* check if composed quality should be rejected */ - Quality const quality(composed_quality(quality1, quality2)); - - if (reject(quality)) - return std::make_pair( - Amounts{offer1.in.zeroed(), offer1.out.zeroed()}, - Amounts{offer2.in.zeroed(), offer2.out.zeroed()}); - - if (done()) - return std::make_pair( - Amounts{offer1.in.zeroed(), offer1.out.zeroed()}, - Amounts{offer2.in.zeroed(), offer2.out.zeroed()}); - - auto result = do_cross( - offer1, - quality1, - AccountID(0x4703), - offer2, - quality2, - AccountID(0x4704)); - - return std::make_pair(result.first.order, result.second.order); - } - }; - -private: - Issue const& - usd() const - { - static Issue const issue( - Currency(0x5553440000000000), AccountID(0x4985601)); - return issue; - } - - Issue const& - eur() const - { - static Issue const issue( - Currency(0x4555520000000000), AccountID(0x4985602)); - return issue; - } - - Issue const& - xrp() const - { - static Issue const issue(xrpCurrency(), xrpAccount()); - return issue; - } - - STAmount - parse_amount(std::string const& amount, Issue const& issue) - { - return amountFromString(issue, amount); - } - - Amounts - parse_amounts( - std::string const& amount_in, - Issue const& issue_in, - std::string const& amount_out, - Issue const& issue_out) - { - STAmount const in(parse_amount(amount_in, issue_in)); - STAmount const out(parse_amount(amount_out, issue_out)); - - return {in, out}; - } - - struct cross_attempt_offer - { - cross_attempt_offer(std::string const& in_, std::string const& out_) - : in(in_), out(out_) - { - } - - std::string in; - std::string out; - }; - -private: - std::string - format_amount(STAmount const& amount) - { - std::string txt = amount.getText(); - txt += "/"; - txt += to_string(amount.issue().currency); - return txt; - } - - void - attempt( - bool sell, - std::string name, - Quality taker_quality, - cross_attempt_offer const offer, - std::string const funds, - Quality cross_quality, - cross_attempt_offer const cross, - std::string const cross_funds, - cross_attempt_offer const flow, - Issue const& issue_in, - Issue const& issue_out, - Rate rate_in = parityRate, - Rate rate_out = parityRate) - { - Amounts taker_offer( - parse_amounts(offer.in, issue_in, offer.out, issue_out)); - - Amounts cross_offer( - parse_amounts(cross.in, issue_in, cross.out, issue_out)); - - CrossType cross_type; - - if (isXRP(issue_out)) - cross_type = CrossType::IouToXrp; - else if (isXRP(issue_in)) - cross_type = CrossType::XrpToIou; - else - cross_type = CrossType::IouToIou; - - // FIXME: We are always invoking the IOU-to-IOU taker. We should select - // the correct type dynamically. - TestTaker taker( - cross_type, - taker_offer, - taker_quality, - parse_amount(funds, issue_in), - sell ? tfSell : 0, - rate_in, - rate_out); - - taker.set_funds(parse_amount(cross_funds, issue_out)); - - auto result = taker.cross(cross_offer, cross_quality); - - Amounts const expected( - parse_amounts(flow.in, issue_in, flow.out, issue_out)); - - BEAST_EXPECT(expected == result); - - if (expected != result) - { - log << "Expected: " << format_amount(expected.in) << " : " - << format_amount(expected.out) << '\n' - << " Actual: " << format_amount(result.in) << " : " - << format_amount(result.out) << std::endl; - } - } - - Quality - get_quality(std::string in, std::string out) - { - return Quality(parse_amounts(in, xrp(), out, xrp())); - } - -public: - // Notation for clamp scenario descriptions: - // - // IN:OUT (with the last in the list being limiting factor) - // N = Nothing - // T = Taker Offer Balance - // A = Taker Account Balance - // B = Owner Account Balance - // - // (s) = sell semantics: taker wants unlimited output - // (b) = buy semantics: taker wants a limited amount out - - // NIKB TODO: Augment TestTaker so currencies and rates can be specified - // once without need for repetition. - void - test_xrp_to_iou() - { - testcase("XRP Quantization: input"); - - Quality q1 = get_quality("1", "1"); - - for (auto NumberSwitchOver : {false, true}) - { - NumberSO stNumberSO{NumberSwitchOver}; - // TAKER OWNER - // QUAL OFFER FUNDS QUAL OFFER FUNDS - // EXPECTED - // XRP USD - attempt( - Sell, - "N:N", - q1, - {"2", "2"}, - "2", - q1, - {"2", "2"}, - "2", - {"2", "2"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Sell, - "N:B", - q1, - {"2", "2"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"2", "1.8"}, - xrp(), - usd()); - } - else - { - attempt( - Sell, - "N:B", - q1, - {"2", "2"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - } - attempt( - Buy, - "N:T", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "N:BT", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Buy, - "N:TB", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "0.8", - {"1", "0.8"}, - xrp(), - usd()); - } - else - { - attempt( - Buy, - "N:TB", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "0.8", - {"0", "0.8"}, - xrp(), - usd()); - } - attempt( - Sell, - "T:N", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Sell, - "T:B", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - } - else - { - attempt( - Sell, - "T:B", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - } - attempt( - Buy, - "T:T", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "T:BT", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Buy, - "T:TB", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "0.8", - {"1", "0.8"}, - xrp(), - usd()); - } - else - { - attempt( - Buy, - "T:TB", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "0.8", - {"0", "0.8"}, - xrp(), - usd()); - } - - attempt( - Sell, - "A:N", - q1, - {"2", "2"}, - "1", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Sell, - "A:B", - q1, - {"2", "2"}, - "1", - q1, - {"2", "2"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - } - else - { - attempt( - Sell, - "A:B", - q1, - {"2", "2"}, - "1", - q1, - {"2", "2"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - } - attempt( - Buy, - "A:T", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "3", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "A:BT", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "2.4", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Buy, - "A:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "0.8", - {"1", "0.8"}, - xrp(), - usd()); - } - else - { - attempt( - Buy, - "A:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "0.8", - {"0", "0.8"}, - xrp(), - usd()); - } - - attempt( - Sell, - "TA:N", - q1, - {"2", "2"}, - "1", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Sell, - "TA:B", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - } - else - { - attempt( - Sell, - "TA:B", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - } - attempt( - Buy, - "TA:T", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "3", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Buy, - "TA:BT", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "TA:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - } - else - { - attempt( - Buy, - "TA:BT", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "TA:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - } - - attempt( - Sell, - "AT:N", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "3", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Sell, - "AT:B", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - } - else - { - attempt( - Sell, - "AT:B", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - } - attempt( - Buy, - "AT:T", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "3", - {"1", "1"}, - xrp(), - usd()); - if (NumberSwitchOver) - { - attempt( - Buy, - "AT:BT", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "AT:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "0.8", - {"1", "0.8"}, - xrp(), - usd()); - } - else - { - attempt( - Buy, - "AT:BT", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "AT:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "0.8", - {"0", "0.8"}, - xrp(), - usd()); - } - } - } - - void - test_iou_to_xrp() - { - testcase("XRP Quantization: output"); - - for (auto NumberSwitchOver : {false, true}) - { - NumberSO stNumberSO{NumberSwitchOver}; - Quality q1 = get_quality("1", "1"); - - // TAKER OWNER - // QUAL OFFER FUNDS QUAL OFFER FUNDS - // EXPECTED - // USD XRP - attempt( - Sell, - "N:N", - q1, - {"3", "3"}, - "3", - q1, - {"3", "3"}, - "3", - {"3", "3"}, - usd(), - xrp()); - attempt( - Sell, - "N:B", - q1, - {"3", "3"}, - "3", - q1, - {"3", "3"}, - "2", - {"2", "2"}, - usd(), - xrp()); - if (NumberSwitchOver) - { - attempt( - Buy, - "N:T", - q1, - {"3", "3"}, - "2.5", - q1, - {"5", "5"}, - "5", - {"2.5", "3"}, - usd(), - xrp()); - attempt( - Buy, - "N:BT", - q1, - {"3", "3"}, - "1.5", - q1, - {"5", "5"}, - "4", - {"1.5", "2"}, - usd(), - xrp()); - } - else - { - attempt( - Buy, - "N:T", - q1, - {"3", "3"}, - "2.5", - q1, - {"5", "5"}, - "5", - {"2.5", "2"}, - usd(), - xrp()); - attempt( - Buy, - "N:BT", - q1, - {"3", "3"}, - "1.5", - q1, - {"5", "5"}, - "4", - {"1.5", "1"}, - usd(), - xrp()); - } - attempt( - Buy, - "N:TB", - q1, - {"3", "3"}, - "2.2", - q1, - {"5", "5"}, - "1", - {"1", "1"}, - usd(), - xrp()); - - attempt( - Sell, - "T:N", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - usd(), - xrp()); - attempt( - Sell, - "T:B", - q1, - {"2", "2"}, - "2", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "T:T", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "T:BT", - q1, - {"1", "1"}, - "2", - q1, - {"3", "3"}, - "2", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "T:TB", - q1, - {"2", "2"}, - "2", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - - if (NumberSwitchOver) - { - attempt( - Sell, - "A:N", - q1, - {"2", "2"}, - "1.5", - q1, - {"2", "2"}, - "2", - {"1.5", "2"}, - usd(), - xrp()); - attempt( - Sell, - "A:B", - q1, - {"2", "2"}, - "1.8", - q1, - {"3", "3"}, - "2", - {"1.8", "2"}, - usd(), - xrp()); - } - else - { - attempt( - Sell, - "A:N", - q1, - {"2", "2"}, - "1.5", - q1, - {"2", "2"}, - "2", - {"1.5", "1"}, - usd(), - xrp()); - attempt( - Sell, - "A:B", - q1, - {"2", "2"}, - "1.8", - q1, - {"3", "3"}, - "2", - {"1.8", "1"}, - usd(), - xrp()); - } - attempt( - Buy, - "A:T", - q1, - {"2", "2"}, - "1.2", - q1, - {"3", "3"}, - "3", - {"1.2", "1"}, - usd(), - xrp()); - if (NumberSwitchOver) - { - attempt( - Buy, - "A:BT", - q1, - {"2", "2"}, - "1.5", - q1, - {"4", "4"}, - "3", - {"1.5", "2"}, - usd(), - xrp()); - } - else - { - attempt( - Buy, - "A:BT", - q1, - {"2", "2"}, - "1.5", - q1, - {"4", "4"}, - "3", - {"1.5", "1"}, - usd(), - xrp()); - } - attempt( - Buy, - "A:TB", - q1, - {"2", "2"}, - "1.5", - q1, - {"4", "4"}, - "1", - {"1", "1"}, - usd(), - xrp()); - - if (NumberSwitchOver) - { - attempt( - Sell, - "TA:N", - q1, - {"2", "2"}, - "1.5", - q1, - {"2", "2"}, - "2", - {"1.5", "2"}, - usd(), - xrp()); - } - else - { - attempt( - Sell, - "TA:N", - q1, - {"2", "2"}, - "1.5", - q1, - {"2", "2"}, - "2", - {"1.5", "1"}, - usd(), - xrp()); - } - attempt( - Sell, - "TA:B", - q1, - {"2", "2"}, - "1.5", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - if (NumberSwitchOver) - { - attempt( - Buy, - "TA:T", - q1, - {"2", "2"}, - "1.5", - q1, - {"3", "3"}, - "3", - {"1.5", "2"}, - usd(), - xrp()); - attempt( - Buy, - "TA:BT", - q1, - {"2", "2"}, - "1.8", - q1, - {"4", "4"}, - "3", - {"1.8", "2"}, - usd(), - xrp()); - } - else - { - attempt( - Buy, - "TA:T", - q1, - {"2", "2"}, - "1.5", - q1, - {"3", "3"}, - "3", - {"1.5", "1"}, - usd(), - xrp()); - attempt( - Buy, - "TA:BT", - q1, - {"2", "2"}, - "1.8", - q1, - {"4", "4"}, - "3", - {"1.8", "1"}, - usd(), - xrp()); - } - attempt( - Buy, - "TA:TB", - q1, - {"2", "2"}, - "1.2", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - - attempt( - Sell, - "AT:N", - q1, - {"2", "2"}, - "2.5", - q1, - {"4", "4"}, - "4", - {"2", "2"}, - usd(), - xrp()); - attempt( - Sell, - "AT:B", - q1, - {"2", "2"}, - "2.5", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "AT:T", - q1, - {"2", "2"}, - "2.5", - q1, - {"3", "3"}, - "3", - {"2", "2"}, - usd(), - xrp()); - attempt( - Buy, - "AT:BT", - q1, - {"2", "2"}, - "2.5", - q1, - {"4", "4"}, - "3", - {"2", "2"}, - usd(), - xrp()); - attempt( - Buy, - "AT:TB", - q1, - {"2", "2"}, - "2.5", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - } - } - - void - test_iou_to_iou() - { - testcase("IOU to IOU"); - - for (auto NumberSwitchOver : {false, true}) - { - NumberSO stNumberSO{NumberSwitchOver}; - Quality q1 = get_quality("1", "1"); - - // Highly exaggerated 50% transfer rate for the input and output: - Rate const rate{parityRate.value + (parityRate.value / 2)}; - - // TAKER OWNER - // QUAL OFFER FUNDS QUAL OFFER FUNDS - // EXPECTED - // EUR USD - attempt( - Sell, - "N:N", - q1, - {"2", "2"}, - "10", - q1, - {"2", "2"}, - "10", - {"2", "2"}, - eur(), - usd(), - rate, - rate); - if (NumberSwitchOver) - { - attempt( - Sell, - "N:B", - q1, - {"4", "4"}, - "10", - q1, - {"4", "4"}, - "4", - {"2.666666666666667", "2.666666666666667"}, - eur(), - usd(), - rate, - rate); - } - else - { - attempt( - Sell, - "N:B", - q1, - {"4", "4"}, - "10", - q1, - {"4", "4"}, - "4", - {"2.666666666666666", "2.666666666666666"}, - eur(), - usd(), - rate, - rate); - } - attempt( - Buy, - "N:T", - q1, - {"1", "1"}, - "10", - q1, - {"2", "2"}, - "10", - {"1", "1"}, - eur(), - usd(), - rate, - rate); - attempt( - Buy, - "N:BT", - q1, - {"2", "2"}, - "10", - q1, - {"6", "6"}, - "5", - {"2", "2"}, - eur(), - usd(), - rate, - rate); - attempt( - Buy, - "N:TB", - q1, - {"2", "2"}, - "2", - q1, - {"6", "6"}, - "1", - {"0.6666666666666667", "0.6666666666666667"}, - eur(), - usd(), - rate, - rate); - if (NumberSwitchOver) - { - attempt( - Sell, - "A:N", - q1, - {"2", "2"}, - "2.5", - q1, - {"2", "2"}, - "10", - {"1.666666666666667", "1.666666666666667"}, - eur(), - usd(), - rate, - rate); - } - else - { - attempt( - Sell, - "A:N", - q1, - {"2", "2"}, - "2.5", - q1, - {"2", "2"}, - "10", - {"1.666666666666666", "1.666666666666666"}, - eur(), - usd(), - rate, - rate); - } - } - } - - void - run() override - { - test_xrp_to_iou(); - test_iou_to_xrp(); - test_iou_to_iou(); - } -}; - -BEAST_DEFINE_TESTSUITE(Taker, tx, ripple); - -} // namespace ripple diff --git a/src/test/app/TheoreticalQuality_test.cpp b/src/test/app/TheoreticalQuality_test.cpp index 1b3e6d9a82b..a8713ec69a3 100644 --- a/src/test/app/TheoreticalQuality_test.cpp +++ b/src/test/app/TheoreticalQuality_test.cpp @@ -264,7 +264,7 @@ class TheoreticalQuality_test : public beast::unit_test::suite sendMaxIssue, rcp.paths, /*defaultPaths*/ rcp.paths.empty(), - sb.rules().enabled(featureOwnerPaysFee), + false, OfferCrossing::no, ammContext, std::nullopt, @@ -359,7 +359,7 @@ class TheoreticalQuality_test : public beast::unit_test::suite // Tests are sped up by a factor of 2 if a new environment isn't created // on every iteration. - Env env(*this, supported_amendments()); + Env env(*this, testable_amendments()); for (int i = 0; i < numTestIterations; ++i) { auto const iterAsStr = std::to_string(i); @@ -434,7 +434,7 @@ class TheoreticalQuality_test : public beast::unit_test::suite // Speed up tests by creating the environment outside the loop // (factor of 2 speedup on the DirectStep tests) - Env env(*this, supported_amendments()); + Env env(*this, testable_amendments()); for (int i = 0; i < numTestIterations; ++i) { auto const iterAsStr = std::to_string(i); diff --git a/src/test/app/Ticket_test.cpp b/src/test/app/Ticket_test.cpp index dd83e3036ee..70a5a48adf2 100644 --- a/src/test/app/Ticket_test.cpp +++ b/src/test/app/Ticket_test.cpp @@ -385,7 +385,7 @@ class Ticket_test : public beast::unit_test::suite testcase("Feature Not Enabled"); using namespace test::jtx; - Env env{*this, supported_amendments() - featureTicketBatch}; + Env env{*this, testable_amendments() - featureTicketBatch}; env(ticket::create(env.master, 1), ter(temDISABLED)); env.close(); @@ -933,7 +933,7 @@ class Ticket_test : public beast::unit_test::suite // Try the test without featureTicketBatch enabled. using namespace test::jtx; { - Env env{*this, supported_amendments() - featureTicketBatch}; + Env env{*this, testable_amendments() - featureTicketBatch}; Account alice{"alice"}; env.fund(XRP(10000), alice); @@ -957,7 +957,7 @@ class Ticket_test : public beast::unit_test::suite } // Try the test with featureTicketBatch enabled. { - Env env{*this, supported_amendments()}; + Env env{*this, testable_amendments()}; Account alice{"alice"}; env.fund(XRP(10000), alice); @@ -1000,6 +1000,6 @@ class Ticket_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Ticket, tx, ripple); +BEAST_DEFINE_TESTSUITE(Ticket, app, ripple); } // namespace ripple diff --git a/src/test/app/TrustAndBalance_test.cpp b/src/test/app/TrustAndBalance_test.cpp index 8f092a725f5..f39d9e03134 100644 --- a/src/test/app/TrustAndBalance_test.cpp +++ b/src/test/app/TrustAndBalance_test.cpp @@ -480,8 +480,7 @@ class TrustAndBalance_test : public beast::unit_test::suite }; using namespace test::jtx; - auto const sa = supported_amendments(); - testWithFeatures(sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); testWithFeatures(sa - featurePermissionedDEX); testWithFeatures(sa); } diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index 947640495d3..d0965cc8ff8 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -99,40 +99,6 @@ class TxQPosNegFlows_test : public beast::unit_test::suite return calcMedFeeLevel(feeLevel, feeLevel); } - static std::unique_ptr - makeConfig( - std::map extraTxQ = {}, - std::map extraVoting = {}) - { - auto p = test::jtx::envconfig(); - auto& section = p->section("transaction_queue"); - section.set("ledgers_in_queue", "2"); - section.set("minimum_queue_size", "2"); - section.set("min_ledgers_to_compute_size_limit", "3"); - section.set("max_ledger_counts_to_store", "100"); - section.set("retry_sequence_percent", "25"); - section.set("normal_consensus_increase_percent", "0"); - - for (auto const& [k, v] : extraTxQ) - section.set(k, v); - - // Some tests specify different fee settings that are enabled by - // a FeeVote - if (!extraVoting.empty()) - { - auto& votingSection = p->section("voting"); - for (auto const& [k, v] : extraVoting) - { - votingSection.set(k, v); - } - - // In order for the vote to occur, we must run as a validator - p->section("validation_seed") - .legacy("shUwVw52ofnCUX5m7kPTKzJdr4HEH"); - } - return p; - } - std::size_t initFee( jtx::Env& env, diff --git a/src/test/app/Vault_test.cpp b/src/test/app/Vault_test.cpp index ccac0e2819a..7ea38db2b12 100644 --- a/src/test/app/Vault_test.cpp +++ b/src/test/app/Vault_test.cpp @@ -17,18 +17,8 @@ */ //============================================================================== -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include @@ -244,6 +234,28 @@ class Vault_test : public beast::unit_test::suite env(tx, ter{tecNO_PERMISSION}); } + { + testcase(prefix + " fail to withdraw to zero destination"); + auto tx = vault.withdraw( + {.depositor = depositor, + .id = keylet.key, + .amount = asset(1000)}); + tx[sfDestination] = "0"; + env(tx, ter(temMALFORMED)); + } + + { + testcase( + prefix + + " fail to withdraw with tag but without destination"); + auto tx = vault.withdraw( + {.depositor = depositor, + .id = keylet.key, + .amount = asset(1000)}); + tx[sfDestinationTag] = "0"; + env(tx, ter(temMALFORMED)); + } + if (!asset.raw().native()) { testcase( @@ -350,7 +362,7 @@ class Vault_test : public beast::unit_test::suite Account const& owner, Account const& depositor, Account const& charlie)> setup) { - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; Account depositor{"depositor"}; @@ -426,7 +438,7 @@ class Vault_test : public beast::unit_test::suite struct CaseArgs { FeatureBitset features = - supported_amendments() | featureSingleAssetVault; + testable_amendments() | featureSingleAssetVault; }; auto testCase = [&, this]( @@ -504,7 +516,7 @@ class Vault_test : public beast::unit_test::suite env(tx, ter{temDISABLED}); } }, - {.features = supported_amendments() - featureSingleAssetVault}); + {.features = testable_amendments() - featureSingleAssetVault}); testCase([&](Env& env, Account const& issuer, @@ -635,7 +647,7 @@ class Vault_test : public beast::unit_test::suite env(tx, ter{temDISABLED}); } }, - {.features = (supported_amendments() | featureSingleAssetVault) - + {.features = (testable_amendments() | featureSingleAssetVault) - featurePermissionedDomains}); testCase([&](Env& env, @@ -960,7 +972,7 @@ class Vault_test : public beast::unit_test::suite Account const& depositor, Asset const& asset, Vault& vault)> test) { - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; Account depositor{"depositor"}; @@ -1102,8 +1114,7 @@ class Vault_test : public beast::unit_test::suite { { testcase("IOU fail create frozen"); - Env env{ - *this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; env.fund(XRP(1000), issuer, owner); @@ -1122,8 +1133,7 @@ class Vault_test : public beast::unit_test::suite { testcase("IOU fail create no ripling"); - Env env{ - *this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; env.fund(XRP(1000), issuer, owner); @@ -1141,8 +1151,7 @@ class Vault_test : public beast::unit_test::suite { testcase("IOU no issuer"); - Env env{ - *this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; env.fund(XRP(1000), owner); @@ -1161,7 +1170,7 @@ class Vault_test : public beast::unit_test::suite { testcase("IOU fail create vault for AMM LPToken"); - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account const gw("gateway"); Account const alice("alice"); Account const carol("carol"); @@ -1212,7 +1221,7 @@ class Vault_test : public beast::unit_test::suite { using namespace test::jtx; - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; Account depositor{"depositor"}; @@ -1234,7 +1243,7 @@ class Vault_test : public beast::unit_test::suite { using namespace test::jtx; - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; Account depositor{"depositor"}; @@ -1348,6 +1357,7 @@ class Vault_test : public beast::unit_test::suite struct CaseArgs { bool enableClawback = true; + bool requireAuth = true; }; auto testCase = [this]( @@ -1360,7 +1370,7 @@ class Vault_test : public beast::unit_test::suite Vault& vault, MPTTester& mptt)> test, CaseArgs args = {}) { - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; Account depositor{"depositor"}; @@ -1369,16 +1379,20 @@ class Vault_test : public beast::unit_test::suite Vault vault{env}; MPTTester mptt{env, issuer, mptInitNoFund}; + auto const none = LedgerSpecificFlags(0); mptt.create( {.flags = tfMPTCanTransfer | tfMPTCanLock | - (args.enableClawback ? lsfMPTCanClawback - : LedgerSpecificFlags(0)) | - tfMPTRequireAuth}); + (args.enableClawback ? tfMPTCanClawback : none) | + (args.requireAuth ? tfMPTRequireAuth : none)}); PrettyAsset asset = mptt.issuanceID(); mptt.authorize({.account = owner}); - mptt.authorize({.account = issuer, .holder = owner}); mptt.authorize({.account = depositor}); - mptt.authorize({.account = issuer, .holder = depositor}); + if (args.requireAuth) + { + mptt.authorize({.account = issuer, .holder = owner}); + mptt.authorize({.account = issuer, .holder = depositor}); + } + env(pay(issuer, depositor, asset(1000))); env.close(); @@ -1527,6 +1541,100 @@ class Vault_test : public beast::unit_test::suite } }); + testCase( + [this]( + Env& env, + Account const& issuer, + Account const& owner, + Account const& depositor, + PrettyAsset const& asset, + Vault& vault, + MPTTester& mptt) { + testcase( + "MPT 3rd party without MPToken cannot be withdrawal " + "destination"); + + auto [tx, keylet] = + vault.create({.owner = owner, .asset = asset}); + env(tx); + env.close(); + + tx = vault.deposit( + {.depositor = depositor, + .id = keylet.key, + .amount = asset(100)}); + env(tx); + env.close(); + + { + // Set destination to 3rd party without MPToken + Account charlie{"charlie"}; + env.fund(XRP(1000), charlie); + env.close(); + + tx = vault.withdraw( + {.depositor = depositor, + .id = keylet.key, + .amount = asset(100)}); + tx[sfDestination] = charlie.human(); + env(tx, ter(tecNO_AUTH)); + } + }, + {.requireAuth = false}); + + testCase( + [this]( + Env& env, + Account const& issuer, + Account const& owner, + Account const& depositor, + PrettyAsset const& asset, + Vault& vault, + MPTTester& mptt) { + testcase("MPT depositor without MPToken cannot withdraw"); + + auto [tx, keylet] = + vault.create({.owner = owner, .asset = asset}); + env(tx); + env.close(); + + tx = vault.deposit( + {.depositor = depositor, + .id = keylet.key, + .amount = asset(1000)}); + env(tx); + env.close(); + + { + // Remove depositor's MPToken and withdraw will fail + mptt.authorize( + {.account = depositor, .flags = tfMPTUnauthorize}); + env.close(); + auto const mptoken = + env.le(keylet::mptoken(mptt.issuanceID(), depositor)); + BEAST_EXPECT(mptoken == nullptr); + + tx = vault.withdraw( + {.depositor = depositor, + .id = keylet.key, + .amount = asset(100)}); + env(tx, ter(tecNO_AUTH)); + } + + { + // Restore depositor's MPToken and withdraw will succeed + mptt.authorize({.account = depositor}); + env.close(); + + tx = vault.withdraw( + {.depositor = depositor, + .id = keylet.key, + .amount = asset(100)}); + env(tx); + } + }, + {.requireAuth = false}); + testCase([this]( Env& env, Account const& issuer, @@ -1756,7 +1864,7 @@ class Vault_test : public beast::unit_test::suite { testcase("MPT shares to a vault"); - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account owner{"owner"}; Account issuer{"issuer"}; env.fund(XRP(1000000), owner, issuer); @@ -1805,8 +1913,7 @@ class Vault_test : public beast::unit_test::suite std::function issuanceId, std::function vaultBalance)> test) { - Env env{ - *this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account const owner{"owner"}; Account const issuer{"issuer"}; Account const charlie{"charlie"}; @@ -1817,6 +1924,7 @@ class Vault_test : public beast::unit_test::suite PrettyAsset const asset = issuer["IOU"]; env.trust(asset(1000), owner); + env.trust(asset(1000), charlie); env(pay(issuer, owner, asset(200))); env(rate(issuer, 1.25)); env.close(); @@ -2132,6 +2240,79 @@ class Vault_test : public beast::unit_test::suite env.close(); }); + testCase([&, this]( + Env& env, + Account const& owner, + Account const& issuer, + Account const& charlie, + auto, + Vault& vault, + PrettyAsset const& asset, + auto&&...) { + testcase("IOU no trust line to 3rd party"); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); + env(tx); + env.close(); + + env(vault.deposit( + {.depositor = owner, .id = keylet.key, .amount = asset(100)})); + env.close(); + + Account const erin{"erin"}; + env.fund(XRP(1000), erin); + env.close(); + + // Withdraw to 3rd party without trust line + auto const tx1 = [&](ripple::Keylet keylet) { + auto tx = vault.withdraw( + {.depositor = owner, + .id = keylet.key, + .amount = asset(10)}); + tx[sfDestination] = erin.human(); + return tx; + }(keylet); + env(tx1, ter{tecNO_LINE}); + }); + + testCase([&, this]( + Env& env, + Account const& owner, + Account const& issuer, + Account const& charlie, + auto, + Vault& vault, + PrettyAsset const& asset, + auto&&...) { + testcase("IOU no trust line to depositor"); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); + env(tx); + env.close(); + + // reset limit, so deposit of all funds will delete the trust line + env.trust(asset(0), owner); + env.close(); + + env(vault.deposit( + {.depositor = owner, .id = keylet.key, .amount = asset(200)})); + env.close(); + + auto trustline = + env.le(keylet::line(owner, asset.raw().get())); + BEAST_EXPECT(trustline == nullptr); + + // Withdraw without trust line, will succeed + auto const tx1 = [&](ripple::Keylet keylet) { + auto tx = vault.withdraw( + {.depositor = owner, + .id = keylet.key, + .amount = asset(10)}); + return tx; + }(keylet); + env(tx1); + }); + testCase([&, this]( Env& env, Account const& owner, @@ -2251,7 +2432,7 @@ class Vault_test : public beast::unit_test::suite testcase("private vault"); - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; Account depositor{"depositor"}; @@ -2536,7 +2717,7 @@ class Vault_test : public beast::unit_test::suite testcase("private XRP vault"); - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account owner{"owner"}; Account depositor{"depositor"}; Account alice{"charlie"}; @@ -2639,7 +2820,7 @@ class Vault_test : public beast::unit_test::suite using namespace test::jtx; testcase("failed pseudo-account allocation"); - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account const owner{"owner"}; Vault vault{env}; env.fund(XRP(1000), owner); @@ -2668,7 +2849,7 @@ class Vault_test : public beast::unit_test::suite using namespace test::jtx; testcase("RPC"); - Env env{*this, supported_amendments() | featureSingleAssetVault}; + Env env{*this, testable_amendments() | featureSingleAssetVault}; Account const owner{"owner"}; Account const issuer{"issuer"}; Vault vault{env}; @@ -3161,6 +3342,6 @@ class Vault_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(Vault, tx, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(Vault, app, ripple, 1); } // namespace ripple diff --git a/src/test/app/XChain_test.cpp b/src/test/app/XChain_test.cpp index 85cd636b3d0..311ddda59be 100644 --- a/src/test/app/XChain_test.cpp +++ b/src/test/app/XChain_test.cpp @@ -192,7 +192,7 @@ struct SEnv }; // XEnv class used for XChain tests. The only difference with SEnv is that it -// funds some default accounts, and that it enables `supported_amendments() | +// funds some default accounts, and that it enables `testable_amendments() | // FeatureBitset{featureXChainBridge}` by default. // ----------------------------------------------------------------------------- template @@ -526,7 +526,7 @@ struct XChain_test : public beast::unit_test::suite, // coverage test: BridgeCreate::preflight() - create bridge when feature // disabled. { - Env env(*this, supported_amendments() - featureXChainBridge); + Env env(*this, testable_amendments() - featureXChainBridge); env(create_bridge(Account::master, jvb), ter(temDISABLED)); } diff --git a/src/test/app/tx/apply_test.cpp b/src/test/app/tx/apply_test.cpp index 44a2c10b4e5..a754866c7ff 100644 --- a/src/test/app/tx/apply_test.cpp +++ b/src/test/app/tx/apply_test.cpp @@ -55,7 +55,7 @@ class Apply_test : public beast::unit_test::suite { test::jtx::Env no_fully_canonical( *this, - test::jtx::supported_amendments() - + test::jtx::testable_amendments() - featureRequireFullyCanonicalSig); Validity valid = checkValidity( @@ -71,7 +71,7 @@ class Apply_test : public beast::unit_test::suite { test::jtx::Env fully_canonical( - *this, test::jtx::supported_amendments()); + *this, test::jtx::testable_amendments()); Validity valid = checkValidity( fully_canonical.app().getHashRouter(), @@ -87,6 +87,6 @@ class Apply_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Apply, app, ripple); +BEAST_DEFINE_TESTSUITE(Apply, tx, ripple); } // namespace ripple diff --git a/src/test/basics/Buffer_test.cpp b/src/test/basics/Buffer_test.cpp index 43ca048d7f4..065c33c12f4 100644 --- a/src/test/basics/Buffer_test.cpp +++ b/src/test/basics/Buffer_test.cpp @@ -98,8 +98,7 @@ struct Buffer_test : beast::unit_test::suite x = b0; BEAST_EXPECT(x == b0); BEAST_EXPECT(sane(x)); -#if defined(__clang__) && (!defined(__APPLE__) && (__clang_major__ >= 7)) || \ - (defined(__APPLE__) && (__apple_build_version__ >= 10010043)) +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wself-assign-overloaded" #endif @@ -111,8 +110,7 @@ struct Buffer_test : beast::unit_test::suite BEAST_EXPECT(y == b3); BEAST_EXPECT(sane(y)); -#if defined(__clang__) && (!defined(__APPLE__) && (__clang_major__ >= 7)) || \ - (defined(__APPLE__) && (__apple_build_version__ >= 10010043)) +#if defined(__clang__) #pragma clang diagnostic pop #endif } @@ -282,7 +280,7 @@ struct Buffer_test : beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Buffer, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(Buffer, basics, ripple); } // namespace test } // namespace ripple diff --git a/src/test/basics/DetectCrash_test.cpp b/src/test/basics/DetectCrash_test.cpp index 1ae761f34a4..5489ae5b26f 100644 --- a/src/test/basics/DetectCrash_test.cpp +++ b/src/test/basics/DetectCrash_test.cpp @@ -41,7 +41,7 @@ struct DetectCrash_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL(DetectCrash, unit_test, beast); +BEAST_DEFINE_TESTSUITE_MANUAL(DetectCrash, basics, beast); } // namespace test } // namespace ripple diff --git a/src/test/basics/Expected_test.cpp b/src/test/basics/Expected_test.cpp index d022d074616..faa6b98764e 100644 --- a/src/test/basics/Expected_test.cpp +++ b/src/test/basics/Expected_test.cpp @@ -243,7 +243,7 @@ struct Expected_test : beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Expected, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(Expected, basics, ripple); } // namespace test } // namespace ripple diff --git a/src/test/basics/FeeUnits_test.cpp b/src/test/basics/FeeUnits_test.cpp index 62662888960..f9be6326448 100644 --- a/src/test/basics/FeeUnits_test.cpp +++ b/src/test/basics/FeeUnits_test.cpp @@ -371,7 +371,7 @@ class feeunits_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(feeunits, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(feeunits, basics, ripple); } // namespace test } // namespace ripple diff --git a/src/test/basics/FileUtilities_test.cpp b/src/test/basics/FileUtilities_test.cpp index 4b4cbe70c80..9071ac72316 100644 --- a/src/test/basics/FileUtilities_test.cpp +++ b/src/test/basics/FileUtilities_test.cpp @@ -79,6 +79,6 @@ class FileUtilities_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(FileUtilities, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(FileUtilities, basics, ripple); } // namespace ripple diff --git a/src/test/basics/IOUAmount_test.cpp b/src/test/basics/IOUAmount_test.cpp index 6ba1cfd6f19..dfc48c9be79 100644 --- a/src/test/basics/IOUAmount_test.cpp +++ b/src/test/basics/IOUAmount_test.cpp @@ -274,6 +274,6 @@ class IOUAmount_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(IOUAmount, protocol, ripple); +BEAST_DEFINE_TESTSUITE(IOUAmount, basics, ripple); } // namespace ripple diff --git a/src/test/basics/IntrusiveShared_test.cpp b/src/test/basics/IntrusiveShared_test.cpp index 736cc473458..a3acc54d452 100644 --- a/src/test/basics/IntrusiveShared_test.cpp +++ b/src/test/basics/IntrusiveShared_test.cpp @@ -887,6 +887,6 @@ class IntrusiveShared_test : public beast::unit_test::suite } }; // namespace tests -BEAST_DEFINE_TESTSUITE(IntrusiveShared, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(IntrusiveShared, basics, ripple); } // namespace tests } // namespace ripple diff --git a/src/test/basics/KeyCache_test.cpp b/src/test/basics/KeyCache_test.cpp index d12dd59af0d..e1d57fb3e42 100644 --- a/src/test/basics/KeyCache_test.cpp +++ b/src/test/basics/KeyCache_test.cpp @@ -93,6 +93,6 @@ class KeyCache_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(KeyCache, common, ripple); +BEAST_DEFINE_TESTSUITE(KeyCache, basics, ripple); } // namespace ripple diff --git a/src/test/basics/Number_test.cpp b/src/test/basics/Number_test.cpp index 13d8b259d1d..964cfe9614c 100644 --- a/src/test/basics/Number_test.cpp +++ b/src/test/basics/Number_test.cpp @@ -743,6 +743,6 @@ class Number_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Number, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(Number, basics, ripple); } // namespace ripple diff --git a/src/test/basics/RangeSet_test.cpp b/src/test/basics/RangeSet_test.cpp deleted file mode 100644 index e0136ab8907..00000000000 --- a/src/test/basics/RangeSet_test.cpp +++ /dev/null @@ -1,144 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include - -namespace ripple { -class RangeSet_test : public beast::unit_test::suite -{ -public: - void - testPrevMissing() - { - testcase("prevMissing"); - - // Set will include: - // [ 0, 5] - // [10,15] - // [20,25] - // etc... - - RangeSet set; - for (std::uint32_t i = 0; i < 10; ++i) - set.insert(range(10 * i, 10 * i + 5)); - - for (std::uint32_t i = 1; i < 100; ++i) - { - std::optional expected; - // no prev missing in domain for i <= 6 - if (i > 6) - { - std::uint32_t const oneBelowRange = (10 * (i / 10)) - 1; - - expected = ((i % 10) > 6) ? (i - 1) : oneBelowRange; - } - BEAST_EXPECT(prevMissing(set, i) == expected); - } - } - - void - testToString() - { - testcase("toString"); - - RangeSet set; - BEAST_EXPECT(to_string(set) == "empty"); - - set.insert(1); - BEAST_EXPECT(to_string(set) == "1"); - - set.insert(range(4u, 6u)); - BEAST_EXPECT(to_string(set) == "1,4-6"); - - set.insert(2); - BEAST_EXPECT(to_string(set) == "1-2,4-6"); - - set.erase(range(4u, 5u)); - BEAST_EXPECT(to_string(set) == "1-2,6"); - } - - void - testFromString() - { - testcase("fromString"); - - RangeSet set; - - BEAST_EXPECT(!from_string(set, "")); - BEAST_EXPECT(boost::icl::length(set) == 0); - - BEAST_EXPECT(!from_string(set, "#")); - BEAST_EXPECT(boost::icl::length(set) == 0); - - BEAST_EXPECT(!from_string(set, ",")); - BEAST_EXPECT(boost::icl::length(set) == 0); - - BEAST_EXPECT(!from_string(set, ",-")); - BEAST_EXPECT(boost::icl::length(set) == 0); - - BEAST_EXPECT(!from_string(set, "1,,2")); - BEAST_EXPECT(boost::icl::length(set) == 0); - - BEAST_EXPECT(from_string(set, "1")); - BEAST_EXPECT(boost::icl::length(set) == 1); - BEAST_EXPECT(boost::icl::first(set) == 1); - - BEAST_EXPECT(from_string(set, "1,1")); - BEAST_EXPECT(boost::icl::length(set) == 1); - BEAST_EXPECT(boost::icl::first(set) == 1); - - BEAST_EXPECT(from_string(set, "1-1")); - BEAST_EXPECT(boost::icl::length(set) == 1); - BEAST_EXPECT(boost::icl::first(set) == 1); - - BEAST_EXPECT(from_string(set, "1,4-6")); - BEAST_EXPECT(boost::icl::length(set) == 4); - BEAST_EXPECT(boost::icl::first(set) == 1); - BEAST_EXPECT(!boost::icl::contains(set, 2)); - BEAST_EXPECT(!boost::icl::contains(set, 3)); - BEAST_EXPECT(boost::icl::contains(set, 4)); - BEAST_EXPECT(boost::icl::contains(set, 5)); - BEAST_EXPECT(boost::icl::last(set) == 6); - - BEAST_EXPECT(from_string(set, "1-2,4-6")); - BEAST_EXPECT(boost::icl::length(set) == 5); - BEAST_EXPECT(boost::icl::first(set) == 1); - BEAST_EXPECT(boost::icl::contains(set, 2)); - BEAST_EXPECT(boost::icl::contains(set, 4)); - BEAST_EXPECT(boost::icl::last(set) == 6); - - BEAST_EXPECT(from_string(set, "1-2,6")); - BEAST_EXPECT(boost::icl::length(set) == 3); - BEAST_EXPECT(boost::icl::first(set) == 1); - BEAST_EXPECT(boost::icl::contains(set, 2)); - BEAST_EXPECT(boost::icl::last(set) == 6); - } - void - run() override - { - testPrevMissing(); - testToString(); - testFromString(); - } -}; - -BEAST_DEFINE_TESTSUITE(RangeSet, ripple_basics, ripple); - -} // namespace ripple diff --git a/src/test/basics/Slice_test.cpp b/src/test/basics/Slice_test.cpp deleted file mode 100644 index 3d474def792..00000000000 --- a/src/test/basics/Slice_test.cpp +++ /dev/null @@ -1,116 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github0.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include - -#include -#include - -namespace ripple { -namespace test { - -struct Slice_test : beast::unit_test::suite -{ - void - run() override - { - std::uint8_t const data[] = { - 0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a, - 0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c, - 0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3}; - - { - testcase("Equality & Inequality"); - - Slice const s0{}; - - BEAST_EXPECT(s0.size() == 0); - BEAST_EXPECT(s0.data() == nullptr); - BEAST_EXPECT(s0 == s0); - - // Test slices of equal and unequal size pointing to same data: - for (std::size_t i = 0; i != sizeof(data); ++i) - { - Slice const s1{data, i}; - - BEAST_EXPECT(s1.size() == i); - BEAST_EXPECT(s1.data() != nullptr); - - if (i == 0) - BEAST_EXPECT(s1 == s0); - else - BEAST_EXPECT(s1 != s0); - - for (std::size_t j = 0; j != sizeof(data); ++j) - { - Slice const s2{data, j}; - - if (i == j) - BEAST_EXPECT(s1 == s2); - else - BEAST_EXPECT(s1 != s2); - } - } - - // Test slices of equal size but pointing to different data: - std::array a; - std::array b; - - for (std::size_t i = 0; i != sizeof(data); ++i) - a[i] = b[i] = data[i]; - - BEAST_EXPECT(makeSlice(a) == makeSlice(b)); - b[7]++; - BEAST_EXPECT(makeSlice(a) != makeSlice(b)); - a[7]++; - BEAST_EXPECT(makeSlice(a) == makeSlice(b)); - } - - { - testcase("Indexing"); - - Slice const s{data, sizeof(data)}; - - for (std::size_t i = 0; i != sizeof(data); ++i) - BEAST_EXPECT(s[i] == data[i]); - } - - { - testcase("Advancing"); - - for (std::size_t i = 0; i < sizeof(data); ++i) - { - for (std::size_t j = 0; i + j < sizeof(data); ++j) - { - Slice s(data + i, sizeof(data) - i); - s += j; - - BEAST_EXPECT(s.data() == data + i + j); - BEAST_EXPECT(s.size() == sizeof(data) - i - j); - } - } - } - } -}; - -BEAST_DEFINE_TESTSUITE(Slice, ripple_basics, ripple); - -} // namespace test -} // namespace ripple diff --git a/src/test/basics/StringUtilities_test.cpp b/src/test/basics/StringUtilities_test.cpp index cf916c62651..b3fac22b42e 100644 --- a/src/test/basics/StringUtilities_test.cpp +++ b/src/test/basics/StringUtilities_test.cpp @@ -322,6 +322,6 @@ class StringUtilities_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(StringUtilities, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(StringUtilities, basics, ripple); } // namespace ripple diff --git a/src/test/basics/TaggedCache_test.cpp b/src/test/basics/TaggedCache_test.cpp index 797838fcfac..3d3dba698da 100644 --- a/src/test/basics/TaggedCache_test.cpp +++ b/src/test/basics/TaggedCache_test.cpp @@ -151,6 +151,6 @@ class TaggedCache_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(TaggedCache, common, ripple); +BEAST_DEFINE_TESTSUITE(TaggedCache, basics, ripple); } // namespace ripple diff --git a/src/test/basics/XRPAmount_test.cpp b/src/test/basics/XRPAmount_test.cpp index 08745b61e32..452ab80ddae 100644 --- a/src/test/basics/XRPAmount_test.cpp +++ b/src/test/basics/XRPAmount_test.cpp @@ -344,6 +344,6 @@ class XRPAmount_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(XRPAmount, protocol, ripple); +BEAST_DEFINE_TESTSUITE(XRPAmount, basics, ripple); } // namespace ripple diff --git a/src/test/basics/base58_test.cpp b/src/test/basics/base58_test.cpp index 799f6537dc6..590f19a44ef 100644 --- a/src/test/basics/base58_test.cpp +++ b/src/test/basics/base58_test.cpp @@ -470,7 +470,7 @@ class base58_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(base58, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(base58, basics, ripple); } // namespace test } // namespace ripple diff --git a/src/test/basics/base64_test.cpp b/src/test/basics/base64_test.cpp deleted file mode 100644 index b6d67c7c069..00000000000 --- a/src/test/basics/base64_test.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2018 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. -*/ -//============================================================================== - -// -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/boostorg/beast -// - -#include -#include - -namespace ripple { - -class base64_test : public beast::unit_test::suite -{ -public: - void - check(std::string const& in, std::string const& out) - { - auto const encoded = base64_encode(in); - BEAST_EXPECT(encoded == out); - BEAST_EXPECT(base64_decode(encoded) == in); - } - - void - run() override - { - check("", ""); - check("f", "Zg=="); - check("fo", "Zm8="); - check("foo", "Zm9v"); - check("foob", "Zm9vYg=="); - check("fooba", "Zm9vYmE="); - check("foobar", "Zm9vYmFy"); - - check( - "Man is distinguished, not only by his reason, but by this " - "singular passion from " - "other animals, which is a lust of the mind, that by a " - "perseverance of delight " - "in the continued and indefatigable generation of knowledge, " - "exceeds the short " - "vehemence of any carnal pleasure.", - "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dC" - "BieSB0aGlz" - "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIG" - "x1c3Qgb2Yg" - "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aG" - "UgY29udGlu" - "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleG" - "NlZWRzIHRo" - "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="); - - std::string const notBase64 = "not_base64!!"; - std::string const truncated = "not"; - BEAST_EXPECT(base64_decode(notBase64) == base64_decode(truncated)); - } -}; - -BEAST_DEFINE_TESTSUITE(base64, ripple_basics, ripple); - -} // namespace ripple diff --git a/src/test/basics/base_uint_test.cpp b/src/test/basics/base_uint_test.cpp index 8058e0d6f05..6ee9f0901aa 100644 --- a/src/test/basics/base_uint_test.cpp +++ b/src/test/basics/base_uint_test.cpp @@ -366,7 +366,7 @@ struct base_uint_test : beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(base_uint, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(base_uint, basics, ripple); } // namespace test } // namespace ripple diff --git a/src/test/basics/join_test.cpp b/src/test/basics/join_test.cpp index 1b094828243..e533635bcb7 100644 --- a/src/test/basics/join_test.cpp +++ b/src/test/basics/join_test.cpp @@ -99,7 +99,7 @@ struct join_test : beast::unit_test::suite } }; // namespace test -BEAST_DEFINE_TESTSUITE(join, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(join, basics, ripple); } // namespace test } // namespace ripple diff --git a/src/test/basics/mulDiv_test.cpp b/src/test/basics/mulDiv_test.cpp deleted file mode 100644 index 61521577d94..00000000000 --- a/src/test/basics/mulDiv_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include - -namespace ripple { -namespace test { - -struct mulDiv_test : beast::unit_test::suite -{ - void - run() override - { - auto const max = std::numeric_limits::max(); - std::uint64_t const max32 = std::numeric_limits::max(); - - auto result = mulDiv(85, 20, 5); - BEAST_EXPECT(result && *result == 340); - result = mulDiv(20, 85, 5); - BEAST_EXPECT(result && *result == 340); - - result = mulDiv(0, max - 1, max - 3); - BEAST_EXPECT(result && *result == 0); - result = mulDiv(max - 1, 0, max - 3); - BEAST_EXPECT(result && *result == 0); - - result = mulDiv(max, 2, max / 2); - BEAST_EXPECT(result && *result == 4); - result = mulDiv(max, 1000, max / 1000); - BEAST_EXPECT(result && *result == 1000000); - result = mulDiv(max, 1000, max / 1001); - BEAST_EXPECT(result && *result == 1001000); - result = mulDiv(max32 + 1, max32 + 1, 5); - BEAST_EXPECT(result && *result == 3689348814741910323); - - // Overflow - result = mulDiv(max - 1, max - 2, 5); - BEAST_EXPECT(!result); - } -}; - -BEAST_DEFINE_TESTSUITE(mulDiv, ripple_basics, ripple); - -} // namespace test -} // namespace ripple diff --git a/src/test/basics/scope_test.cpp b/src/test/basics/scope_test.cpp deleted file mode 100644 index 654f7e0a11b..00000000000 --- a/src/test/basics/scope_test.cpp +++ /dev/null @@ -1,193 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github0.com/ripple/rippled - Copyright (c) 2021 Ripple Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include - -namespace ripple { -namespace test { - -struct scope_test : beast::unit_test::suite -{ - void - test_scope_exit() - { - // scope_exit always executes the functor on destruction, - // unless release() is called - int i = 0; - { - scope_exit x{[&i]() { i = 1; }}; - } - BEAST_EXPECT(i == 1); - { - scope_exit x{[&i]() { i = 2; }}; - x.release(); - } - BEAST_EXPECT(i == 1); - { - scope_exit x{[&i]() { i += 2; }}; - auto x2 = std::move(x); - } - BEAST_EXPECT(i == 3); - { - scope_exit x{[&i]() { i = 4; }}; - x.release(); - auto x2 = std::move(x); - } - BEAST_EXPECT(i == 3); - { - try - { - scope_exit x{[&i]() { i = 5; }}; - throw 1; - } - catch (...) - { - } - } - BEAST_EXPECT(i == 5); - { - try - { - scope_exit x{[&i]() { i = 6; }}; - x.release(); - throw 1; - } - catch (...) - { - } - } - BEAST_EXPECT(i == 5); - } - - void - test_scope_fail() - { - // scope_fail executes the functor on destruction only - // if an exception is unwinding, unless release() is called - int i = 0; - { - scope_fail x{[&i]() { i = 1; }}; - } - BEAST_EXPECT(i == 0); - { - scope_fail x{[&i]() { i = 2; }}; - x.release(); - } - BEAST_EXPECT(i == 0); - { - scope_fail x{[&i]() { i = 3; }}; - auto x2 = std::move(x); - } - BEAST_EXPECT(i == 0); - { - scope_fail x{[&i]() { i = 4; }}; - x.release(); - auto x2 = std::move(x); - } - BEAST_EXPECT(i == 0); - { - try - { - scope_fail x{[&i]() { i = 5; }}; - throw 1; - } - catch (...) - { - } - } - BEAST_EXPECT(i == 5); - { - try - { - scope_fail x{[&i]() { i = 6; }}; - x.release(); - throw 1; - } - catch (...) - { - } - } - BEAST_EXPECT(i == 5); - } - - void - test_scope_success() - { - // scope_success executes the functor on destruction only - // if an exception is not unwinding, unless release() is called - int i = 0; - { - scope_success x{[&i]() { i = 1; }}; - } - BEAST_EXPECT(i == 1); - { - scope_success x{[&i]() { i = 2; }}; - x.release(); - } - BEAST_EXPECT(i == 1); - { - scope_success x{[&i]() { i += 2; }}; - auto x2 = std::move(x); - } - BEAST_EXPECT(i == 3); - { - scope_success x{[&i]() { i = 4; }}; - x.release(); - auto x2 = std::move(x); - } - BEAST_EXPECT(i == 3); - { - try - { - scope_success x{[&i]() { i = 5; }}; - throw 1; - } - catch (...) - { - } - } - BEAST_EXPECT(i == 3); - { - try - { - scope_success x{[&i]() { i = 6; }}; - x.release(); - throw 1; - } - catch (...) - { - } - } - BEAST_EXPECT(i == 3); - } - - void - run() override - { - test_scope_exit(); - test_scope_fail(); - test_scope_success(); - } -}; - -BEAST_DEFINE_TESTSUITE(scope, ripple_basics, ripple); - -} // namespace test -} // namespace ripple diff --git a/src/test/basics/tagged_integer_test.cpp b/src/test/basics/tagged_integer_test.cpp deleted file mode 100644 index cb15d246a6e..00000000000 --- a/src/test/basics/tagged_integer_test.cpp +++ /dev/null @@ -1,258 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2014, Nikolaos D. Bougalis - - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include - -#include - -namespace ripple { -namespace test { - -class tagged_integer_test : public beast::unit_test::suite -{ -private: - struct Tag1 - { - }; - struct Tag2 - { - }; - - // Static checks that types are not interoperable - - using TagUInt1 = tagged_integer; - using TagUInt2 = tagged_integer; - using TagUInt3 = tagged_integer; - - // Check construction of tagged_integers - static_assert( - std::is_constructible::value, - "TagUInt1 should be constructible using a std::uint32_t"); - - static_assert( - !std::is_constructible::value, - "TagUInt1 should not be constructible using a std::uint64_t"); - - static_assert( - std::is_constructible::value, - "TagUInt3 should be constructible using a std::uint32_t"); - - static_assert( - std::is_constructible::value, - "TagUInt3 should be constructible using a std::uint64_t"); - - // Check assignment of tagged_integers - static_assert( - !std::is_assignable::value, - "TagUInt1 should not be assignable with a std::uint32_t"); - - static_assert( - !std::is_assignable::value, - "TagUInt1 should not be assignable with a std::uint64_t"); - - static_assert( - !std::is_assignable::value, - "TagUInt3 should not be assignable with a std::uint32_t"); - - static_assert( - !std::is_assignable::value, - "TagUInt3 should not be assignable with a std::uint64_t"); - - static_assert( - std::is_assignable::value, - "TagUInt1 should be assignable with a TagUInt1"); - - static_assert( - !std::is_assignable::value, - "TagUInt1 should not be assignable with a TagUInt2"); - - static_assert( - std::is_assignable::value, - "TagUInt3 should be assignable with a TagUInt1"); - - static_assert( - !std::is_assignable::value, - "TagUInt1 should not be assignable with a TagUInt3"); - - static_assert( - !std::is_assignable::value, - "TagUInt3 should not be assignable with a TagUInt1"); - - // Check convertibility of tagged_integers - static_assert( - !std::is_convertible::value, - "std::uint32_t should not be convertible to a TagUInt1"); - - static_assert( - !std::is_convertible::value, - "std::uint32_t should not be convertible to a TagUInt3"); - - static_assert( - !std::is_convertible::value, - "std::uint64_t should not be convertible to a TagUInt3"); - - static_assert( - !std::is_convertible::value, - "std::uint64_t should not be convertible to a TagUInt2"); - - static_assert( - !std::is_convertible::value, - "TagUInt1 should not be convertible to TagUInt2"); - - static_assert( - !std::is_convertible::value, - "TagUInt1 should not be convertible to TagUInt3"); - - static_assert( - !std::is_convertible::value, - "TagUInt2 should not be convertible to a TagUInt3"); - -public: - void - run() override - { - using TagInt = tagged_integer; - - { - testcase("Comparison Operators"); - - TagInt const zero(0); - TagInt const one(1); - - BEAST_EXPECT(one == one); - BEAST_EXPECT(!(one == zero)); - - BEAST_EXPECT(one != zero); - BEAST_EXPECT(!(one != one)); - - BEAST_EXPECT(zero < one); - BEAST_EXPECT(!(one < zero)); - - BEAST_EXPECT(one > zero); - BEAST_EXPECT(!(zero > one)); - - BEAST_EXPECT(one >= one); - BEAST_EXPECT(one >= zero); - BEAST_EXPECT(!(zero >= one)); - - BEAST_EXPECT(zero <= one); - BEAST_EXPECT(zero <= zero); - BEAST_EXPECT(!(one <= zero)); - } - - { - testcase("Increment/Decrement Operators"); - TagInt const zero(0); - TagInt const one(1); - TagInt a{0}; - ++a; - BEAST_EXPECT(a == one); - --a; - BEAST_EXPECT(a == zero); - a++; - BEAST_EXPECT(a == one); - a--; - BEAST_EXPECT(a == zero); - } - - { - testcase("Arithmetic Operators"); - TagInt a{-2}; - BEAST_EXPECT(+a == TagInt{-2}); - BEAST_EXPECT(-a == TagInt{2}); - BEAST_EXPECT(TagInt{-3} + TagInt{4} == TagInt{1}); - BEAST_EXPECT(TagInt{-3} - TagInt{4} == TagInt{-7}); - BEAST_EXPECT(TagInt{-3} * TagInt{4} == TagInt{-12}); - BEAST_EXPECT(TagInt{8} / TagInt{4} == TagInt{2}); - BEAST_EXPECT(TagInt{7} % TagInt{4} == TagInt{3}); - - BEAST_EXPECT(~TagInt{8} == TagInt{~TagInt::value_type{8}}); - BEAST_EXPECT((TagInt{6} & TagInt{3}) == TagInt{2}); - BEAST_EXPECT((TagInt{6} | TagInt{3}) == TagInt{7}); - BEAST_EXPECT((TagInt{6} ^ TagInt{3}) == TagInt{5}); - - BEAST_EXPECT((TagInt{4} << TagInt{2}) == TagInt{16}); - BEAST_EXPECT((TagInt{16} >> TagInt{2}) == TagInt{4}); - } - { - testcase("Assignment Operators"); - TagInt a{-2}; - TagInt b{0}; - b = a; - BEAST_EXPECT(b == TagInt{-2}); - - // -3 + 4 == 1 - a = TagInt{-3}; - a += TagInt{4}; - BEAST_EXPECT(a == TagInt{1}); - - // -3 - 4 == -7 - a = TagInt{-3}; - a -= TagInt{4}; - BEAST_EXPECT(a == TagInt{-7}); - - // -3 * 4 == -12 - a = TagInt{-3}; - a *= TagInt{4}; - BEAST_EXPECT(a == TagInt{-12}); - - // 8/4 == 2 - a = TagInt{8}; - a /= TagInt{4}; - BEAST_EXPECT(a == TagInt{2}); - - // 7 % 4 == 3 - a = TagInt{7}; - a %= TagInt{4}; - BEAST_EXPECT(a == TagInt{3}); - - // 6 & 3 == 2 - a = TagInt{6}; - a /= TagInt{3}; - BEAST_EXPECT(a == TagInt{2}); - - // 6 | 3 == 7 - a = TagInt{6}; - a |= TagInt{3}; - BEAST_EXPECT(a == TagInt{7}); - - // 6 ^ 3 == 5 - a = TagInt{6}; - a ^= TagInt{3}; - BEAST_EXPECT(a == TagInt{5}); - - // 4 << 2 == 16 - a = TagInt{4}; - a <<= TagInt{2}; - BEAST_EXPECT(a == TagInt{16}); - - // 16 >> 2 == 4 - a = TagInt{16}; - a >>= TagInt{2}; - BEAST_EXPECT(a == TagInt{4}); - } - } -}; - -BEAST_DEFINE_TESTSUITE(tagged_integer, ripple_basics, ripple); - -} // namespace test -} // namespace ripple diff --git a/src/test/beast/IPEndpoint_test.cpp b/src/test/beast/IPEndpoint_test.cpp index 7b3eba55f18..aed6d715d45 100644 --- a/src/test/beast/IPEndpoint_test.cpp +++ b/src/test/beast/IPEndpoint_test.cpp @@ -478,7 +478,7 @@ class IPEndpoint_test : public unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(IPEndpoint, net, beast); +BEAST_DEFINE_TESTSUITE(IPEndpoint, beast, beast); } // namespace IP } // namespace beast diff --git a/src/test/beast/LexicalCast_test.cpp b/src/test/beast/LexicalCast_test.cpp index 22638f27e6e..686546a4755 100644 --- a/src/test/beast/LexicalCast_test.cpp +++ b/src/test/beast/LexicalCast_test.cpp @@ -289,6 +289,6 @@ class LexicalCast_test : public unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(LexicalCast, beast_core, beast); +BEAST_DEFINE_TESTSUITE(LexicalCast, beast, beast); } // namespace beast diff --git a/src/test/beast/SemanticVersion_test.cpp b/src/test/beast/SemanticVersion_test.cpp index fb7a3e3e4fb..af9d2808fb5 100644 --- a/src/test/beast/SemanticVersion_test.cpp +++ b/src/test/beast/SemanticVersion_test.cpp @@ -280,5 +280,5 @@ class SemanticVersion_test : public unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(SemanticVersion, beast_core, beast); +BEAST_DEFINE_TESTSUITE(SemanticVersion, beast, beast); } // namespace beast diff --git a/src/test/beast/aged_associative_container_test.cpp b/src/test/beast/aged_associative_container_test.cpp index f88d5acc277..017181df229 100644 --- a/src/test/beast/aged_associative_container_test.cpp +++ b/src/test/beast/aged_associative_container_test.cpp @@ -703,10 +703,6 @@ aged_associative_container_test_base::checkContentsRefRef( Values const& v) { using Cont = typename std::remove_reference::type; - using Traits = TestTraits< - Cont::is_unordered::value, - Cont::is_multi::value, - Cont::is_map::value>; using size_type = typename Cont::size_type; BEAST_EXPECT(c.size() == v.size()); @@ -761,10 +757,6 @@ typename std::enable_if::type aged_associative_container_test_base::testConstructEmpty() { using Traits = TestTraits; - using Value = typename Traits::Value; - using Key = typename Traits::Key; - using T = typename Traits::T; - using Clock = typename Traits::Clock; using Comp = typename Traits::Comp; using Alloc = typename Traits::Alloc; using MyComp = typename Traits::MyComp; @@ -802,10 +794,6 @@ typename std::enable_if::type aged_associative_container_test_base::testConstructEmpty() { using Traits = TestTraits; - using Value = typename Traits::Value; - using Key = typename Traits::Key; - using T = typename Traits::T; - using Clock = typename Traits::Clock; using Hash = typename Traits::Hash; using Equal = typename Traits::Equal; using Alloc = typename Traits::Alloc; @@ -870,10 +858,6 @@ typename std::enable_if::type aged_associative_container_test_base::testConstructRange() { using Traits = TestTraits; - using Value = typename Traits::Value; - using Key = typename Traits::Key; - using T = typename Traits::T; - using Clock = typename Traits::Clock; using Comp = typename Traits::Comp; using Alloc = typename Traits::Alloc; using MyComp = typename Traits::MyComp; @@ -925,10 +909,6 @@ typename std::enable_if::type aged_associative_container_test_base::testConstructRange() { using Traits = TestTraits; - using Value = typename Traits::Value; - using Key = typename Traits::Key; - using T = typename Traits::T; - using Clock = typename Traits::Clock; using Hash = typename Traits::Hash; using Equal = typename Traits::Equal; using Alloc = typename Traits::Alloc; @@ -996,14 +976,6 @@ typename std::enable_if::type aged_associative_container_test_base::testConstructInitList() { using Traits = TestTraits; - using Value = typename Traits::Value; - using Key = typename Traits::Key; - using T = typename Traits::T; - using Clock = typename Traits::Clock; - using Comp = typename Traits::Comp; - using Alloc = typename Traits::Alloc; - using MyComp = typename Traits::MyComp; - using MyAlloc = typename Traits::MyAlloc; typename Traits::ManualClock clock; // testcase (Traits::name() + " init-list"); @@ -1020,16 +992,6 @@ typename std::enable_if::type aged_associative_container_test_base::testConstructInitList() { using Traits = TestTraits; - using Value = typename Traits::Value; - using Key = typename Traits::Key; - using T = typename Traits::T; - using Clock = typename Traits::Clock; - using Hash = typename Traits::Hash; - using Equal = typename Traits::Equal; - using Alloc = typename Traits::Alloc; - using MyHash = typename Traits::MyHash; - using MyEqual = typename Traits::MyEqual; - using MyAlloc = typename Traits::MyAlloc; typename Traits::ManualClock clock; // testcase (Traits::name() + " init-list"); @@ -1050,7 +1012,6 @@ void aged_associative_container_test_base::testCopyMove() { using Traits = TestTraits; - using Value = typename Traits::Value; using Alloc = typename Traits::Alloc; typename Traits::ManualClock clock; auto const v(Traits::values()); @@ -1121,8 +1082,6 @@ void aged_associative_container_test_base::testIterator() { using Traits = TestTraits; - using Value = typename Traits::Value; - using Alloc = typename Traits::Alloc; typename Traits::ManualClock clock; auto const v(Traits::values()); @@ -1179,8 +1138,6 @@ typename std::enable_if::type aged_associative_container_test_base::testReverseIterator() { using Traits = TestTraits; - using Value = typename Traits::Value; - using Alloc = typename Traits::Alloc; typename Traits::ManualClock clock; auto const v(Traits::values()); @@ -1190,7 +1147,6 @@ aged_associative_container_test_base::testReverseIterator() typename Traits::template Cont<> c{clock}; using iterator = decltype(c.begin()); - using const_iterator = decltype(c.cbegin()); using reverse_iterator = decltype(c.rbegin()); using const_reverse_iterator = decltype(c.crbegin()); @@ -1394,7 +1350,6 @@ void aged_associative_container_test_base::testChronological() { using Traits = TestTraits; - using Value = typename Traits::Value; typename Traits::ManualClock clock; auto const v(Traits::values()); @@ -1760,7 +1715,6 @@ typename std::enable_if::type aged_associative_container_test_base::testCompare() { using Traits = TestTraits; - using Value = typename Traits::Value; typename Traits::ManualClock clock; auto const v(Traits::values()); @@ -1832,8 +1786,6 @@ template void aged_associative_container_test_base::testMaybeUnorderedMultiMap() { - using Traits = TestTraits; - testConstructEmpty(); testConstructRange(); testConstructInitList(); @@ -1984,13 +1936,13 @@ class aged_unordered_multimap_test : public aged_associative_container_test_base } }; -BEAST_DEFINE_TESTSUITE(aged_set, container, beast); -BEAST_DEFINE_TESTSUITE(aged_map, container, beast); -BEAST_DEFINE_TESTSUITE(aged_multiset, container, beast); -BEAST_DEFINE_TESTSUITE(aged_multimap, container, beast); -BEAST_DEFINE_TESTSUITE(aged_unordered_set, container, beast); -BEAST_DEFINE_TESTSUITE(aged_unordered_map, container, beast); -BEAST_DEFINE_TESTSUITE(aged_unordered_multiset, container, beast); -BEAST_DEFINE_TESTSUITE(aged_unordered_multimap, container, beast); +BEAST_DEFINE_TESTSUITE(aged_set, beast, beast); +BEAST_DEFINE_TESTSUITE(aged_map, beast, beast); +BEAST_DEFINE_TESTSUITE(aged_multiset, beast, beast); +BEAST_DEFINE_TESTSUITE(aged_multimap, beast, beast); +BEAST_DEFINE_TESTSUITE(aged_unordered_set, beast, beast); +BEAST_DEFINE_TESTSUITE(aged_unordered_map, beast, beast); +BEAST_DEFINE_TESTSUITE(aged_unordered_multiset, beast, beast); +BEAST_DEFINE_TESTSUITE(aged_unordered_multimap, beast, beast); } // namespace beast diff --git a/src/test/beast/beast_CurrentThreadName_test.cpp b/src/test/beast/beast_CurrentThreadName_test.cpp index 839aaaef0ac..e1de5d9ae91 100644 --- a/src/test/beast/beast_CurrentThreadName_test.cpp +++ b/src/test/beast/beast_CurrentThreadName_test.cpp @@ -86,7 +86,7 @@ class CurrentThreadName_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(CurrentThreadName, core, beast); +BEAST_DEFINE_TESTSUITE(CurrentThreadName, beast, beast); } // namespace test } // namespace ripple diff --git a/src/test/beast/beast_Journal_test.cpp b/src/test/beast/beast_Journal_test.cpp index 99badc0fc43..13e2726c89c 100644 --- a/src/test/beast/beast_Journal_test.cpp +++ b/src/test/beast/beast_Journal_test.cpp @@ -103,6 +103,6 @@ class Journal_test : public unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Journal, utility, beast); +BEAST_DEFINE_TESTSUITE(Journal, beast, beast); } // namespace beast diff --git a/src/test/beast/beast_PropertyStream_test.cpp b/src/test/beast/beast_PropertyStream_test.cpp index bbbc2fc0e0d..585c7cfe6bf 100644 --- a/src/test/beast/beast_PropertyStream_test.cpp +++ b/src/test/beast/beast_PropertyStream_test.cpp @@ -238,5 +238,5 @@ class PropertyStream_test : public unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(PropertyStream, utility, beast); +BEAST_DEFINE_TESTSUITE(PropertyStream, beast, beast); } // namespace beast diff --git a/src/test/beast/beast_Zero_test.cpp b/src/test/beast/beast_Zero_test.cpp index 9a645334ab2..64239fbe858 100644 --- a/src/test/beast/beast_Zero_test.cpp +++ b/src/test/beast/beast_Zero_test.cpp @@ -129,6 +129,6 @@ class Zero_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Zero, types, beast); +BEAST_DEFINE_TESTSUITE(Zero, beast, beast); } // namespace beast diff --git a/src/test/beast/beast_abstract_clock_test.cpp b/src/test/beast/beast_abstract_clock_test.cpp index b86afdb1391..74ab833e9db 100644 --- a/src/test/beast/beast_abstract_clock_test.cpp +++ b/src/test/beast/beast_abstract_clock_test.cpp @@ -84,6 +84,6 @@ class abstract_clock_test : public unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL(abstract_clock, chrono, beast); +BEAST_DEFINE_TESTSUITE_MANUAL(abstract_clock, beast, beast); } // namespace beast diff --git a/src/test/beast/beast_basic_seconds_clock_test.cpp b/src/test/beast/beast_basic_seconds_clock_test.cpp index c769cde07ac..10e5e466f31 100644 --- a/src/test/beast/beast_basic_seconds_clock_test.cpp +++ b/src/test/beast/beast_basic_seconds_clock_test.cpp @@ -33,6 +33,6 @@ class basic_seconds_clock_test : public unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(basic_seconds_clock, chrono, beast); +BEAST_DEFINE_TESTSUITE(basic_seconds_clock, beast, beast); } // namespace beast diff --git a/src/test/beast/beast_io_latency_probe_test.cpp b/src/test/beast/beast_io_latency_probe_test.cpp index de3c5d1d208..c72336bf27e 100644 --- a/src/test/beast/beast_io_latency_probe_test.cpp +++ b/src/test/beast/beast_io_latency_probe_test.cpp @@ -238,4 +238,4 @@ class io_latency_probe_test : public beast::unit_test::suite, } }; -BEAST_DEFINE_TESTSUITE(io_latency_probe, asio, beast); +BEAST_DEFINE_TESTSUITE(io_latency_probe, beast, beast); diff --git a/src/test/beast/define_print.cpp b/src/test/beast/define_print.cpp index ec86d5d7d78..eca6a70c903 100644 --- a/src/test/beast/define_print.cpp +++ b/src/test/beast/define_print.cpp @@ -46,7 +46,7 @@ class print_test : public suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL(print, unit_test, beast); +BEAST_DEFINE_TESTSUITE_MANUAL(print, beast, beast); } // namespace unit_test } // namespace beast diff --git a/src/test/beast/xxhasher_test.cpp b/src/test/beast/xxhasher_test.cpp new file mode 100644 index 00000000000..6c65fea6011 --- /dev/null +++ b/src/test/beast/xxhasher_test.cpp @@ -0,0 +1,232 @@ +//------------------------------------------------------------------------------ +/* +This file is part of rippled: https://github.com/ripple/rippled +Copyright (c) 2025 Ripple Labs Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include + +namespace beast { + +class XXHasher_test : public unit_test::suite +{ +public: + void + testWithoutSeed() + { + testcase("Without seed"); + + xxhasher hasher{}; + + std::string objectToHash{"Hello, xxHash!"}; + hasher(objectToHash.data(), objectToHash.size()); + + BEAST_EXPECT( + static_cast(hasher) == + 16042857369214894119ULL); + } + + void + testWithSeed() + { + testcase("With seed"); + + xxhasher hasher{static_cast(102)}; + + std::string objectToHash{"Hello, xxHash!"}; + hasher(objectToHash.data(), objectToHash.size()); + + BEAST_EXPECT( + static_cast(hasher) == + 14440132435660934800ULL); + } + + void + testWithTwoSeeds() + { + testcase("With two seeds"); + xxhasher hasher{ + static_cast(102), static_cast(103)}; + + std::string objectToHash{"Hello, xxHash!"}; + hasher(objectToHash.data(), objectToHash.size()); + + BEAST_EXPECT( + static_cast(hasher) == + 14440132435660934800ULL); + } + + void + testBigObjectWithMultiupleSmallUpdatesWithoutSeed() + { + testcase("Big object with multiple small updates without seed"); + xxhasher hasher{}; + + std::string objectToHash{"Hello, xxHash!"}; + for (int i = 0; i < 100; i++) + { + hasher(objectToHash.data(), objectToHash.size()); + } + + BEAST_EXPECT( + static_cast(hasher) == + 15296278154063476002ULL); + } + + void + testBigObjectWithMultiupleSmallUpdatesWithSeed() + { + testcase("Big object with multiple small updates with seed"); + xxhasher hasher{static_cast(103)}; + + std::string objectToHash{"Hello, xxHash!"}; + for (int i = 0; i < 100; i++) + { + hasher(objectToHash.data(), objectToHash.size()); + } + + BEAST_EXPECT( + static_cast(hasher) == + 17285302196561698791ULL); + } + + void + testBigObjectWithSmallAndBigUpdatesWithoutSeed() + { + testcase("Big object with small and big updates without seed"); + xxhasher hasher{}; + + std::string objectToHash{"Hello, xxHash!"}; + std::string bigObject; + for (int i = 0; i < 20; i++) + { + bigObject += "Hello, xxHash!"; + } + hasher(objectToHash.data(), objectToHash.size()); + hasher(bigObject.data(), bigObject.size()); + hasher(objectToHash.data(), objectToHash.size()); + + BEAST_EXPECT( + static_cast(hasher) == + 1865045178324729219ULL); + } + + void + testBigObjectWithSmallAndBigUpdatesWithSeed() + { + testcase("Big object with small and big updates with seed"); + xxhasher hasher{static_cast(103)}; + + std::string objectToHash{"Hello, xxHash!"}; + std::string bigObject; + for (int i = 0; i < 20; i++) + { + bigObject += "Hello, xxHash!"; + } + hasher(objectToHash.data(), objectToHash.size()); + hasher(bigObject.data(), bigObject.size()); + hasher(objectToHash.data(), objectToHash.size()); + + BEAST_EXPECT( + static_cast(hasher) == + 16189862915636005281ULL); + } + + void + testBigObjectWithOneUpdateWithoutSeed() + { + testcase("Big object with one update without seed"); + xxhasher hasher{}; + + std::string objectToHash; + for (int i = 0; i < 100; i++) + { + objectToHash += "Hello, xxHash!"; + } + hasher(objectToHash.data(), objectToHash.size()); + + BEAST_EXPECT( + static_cast(hasher) == + 15296278154063476002ULL); + } + + void + testBigObjectWithOneUpdateWithSeed() + { + testcase("Big object with one update with seed"); + xxhasher hasher{static_cast(103)}; + + std::string objectToHash; + for (int i = 0; i < 100; i++) + { + objectToHash += "Hello, xxHash!"; + } + hasher(objectToHash.data(), objectToHash.size()); + + BEAST_EXPECT( + static_cast(hasher) == + 17285302196561698791ULL); + } + + void + testOperatorResultTypeDoesNotChangeInternalState() + { + testcase("Operator result type doesn't change the internal state"); + { + xxhasher hasher; + + std::string object{"Hello xxhash"}; + hasher(object.data(), object.size()); + auto xxhashResult1 = static_cast(hasher); + auto xxhashResult2 = static_cast(hasher); + + BEAST_EXPECT(xxhashResult1 == xxhashResult2); + } + { + xxhasher hasher; + + std::string object; + for (int i = 0; i < 100; i++) + { + object += "Hello, xxHash!"; + } + hasher(object.data(), object.size()); + auto xxhashResult1 = hasher.operator xxhasher::result_type(); + auto xxhashResult2 = hasher.operator xxhasher::result_type(); + + BEAST_EXPECT(xxhashResult1 == xxhashResult2); + } + } + + void + run() override + { + testWithoutSeed(); + testWithSeed(); + testWithTwoSeeds(); + testBigObjectWithMultiupleSmallUpdatesWithoutSeed(); + testBigObjectWithMultiupleSmallUpdatesWithSeed(); + testBigObjectWithSmallAndBigUpdatesWithoutSeed(); + testBigObjectWithSmallAndBigUpdatesWithSeed(); + testBigObjectWithOneUpdateWithoutSeed(); + testBigObjectWithOneUpdateWithSeed(); + testOperatorResultTypeDoesNotChangeInternalState(); + } +}; + +BEAST_DEFINE_TESTSUITE(XXHasher, beast_core, beast); +} // namespace beast diff --git a/src/test/consensus/Consensus_test.cpp b/src/test/consensus/Consensus_test.cpp index db56ab58c69..7899336a6f7 100644 --- a/src/test/consensus/Consensus_test.cpp +++ b/src/test/consensus/Consensus_test.cpp @@ -1136,6 +1136,10 @@ class Consensus_test : public beast::unit_test::suite ConsensusParms p; std::size_t peersUnchanged = 0; + auto logs = std::make_unique(beast::severities::kError); + auto j = logs->journal("Test"); + auto clog = std::make_unique(); + // Three cases: // 1 proposing, initial vote yes // 2 proposing, initial vote no @@ -1172,10 +1176,15 @@ class Consensus_test : public beast::unit_test::suite BEAST_EXPECT(proposingFalse.getOurVote() == false); BEAST_EXPECT(followingTrue.getOurVote() == true); BEAST_EXPECT(followingFalse.getOurVote() == false); - BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged)); - BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged)); + BEAST_EXPECT( + !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT( + !proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT( + !followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT( + !followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(clog->str() == ""); // I'm in the majority, my vote should not change BEAST_EXPECT(!proposingTrue.updateVote(5, true, p)); @@ -1189,10 +1198,15 @@ class Consensus_test : public beast::unit_test::suite BEAST_EXPECT(!followingFalse.updateVote(10, false, p)); peersUnchanged = 2; - BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged)); - BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged)); + BEAST_EXPECT( + !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT( + !proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT( + !followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT( + !followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(clog->str() == ""); // Right now, the vote is 51%. The requirement is about to jump to // 65% @@ -1282,10 +1296,15 @@ class Consensus_test : public beast::unit_test::suite BEAST_EXPECT(followingFalse.getOurVote() == false); peersUnchanged = 3; - BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged)); - BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged)); + BEAST_EXPECT( + !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT( + !proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT( + !followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT( + !followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(clog->str() == ""); // Threshold jumps to 95% BEAST_EXPECT(proposingTrue.updateVote(220, true, p)); @@ -1322,12 +1341,60 @@ class Consensus_test : public beast::unit_test::suite for (peersUnchanged = 0; peersUnchanged < 6; ++peersUnchanged) { - BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged)); - BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged)); + BEAST_EXPECT( + !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT( + !proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT( + !followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT( + !followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(clog->str() == ""); } + auto expectStalled = [this, &clog]( + int txid, + bool ourVote, + int ourTime, + int peerTime, + int support, + std::uint32_t line) { + using namespace std::string_literals; + + auto const s = clog->str(); + expect(s.find("stalled"), s, __FILE__, line); + expect( + s.starts_with("Transaction "s + std::to_string(txid)), + s, + __FILE__, + line); + expect( + s.find("voting "s + (ourVote ? "YES" : "NO")) != s.npos, + s, + __FILE__, + line); + expect( + s.find("for "s + std::to_string(ourTime) + " rounds."s) != + s.npos, + s, + __FILE__, + line); + expect( + s.find( + "votes in "s + std::to_string(peerTime) + " rounds.") != + s.npos, + s, + __FILE__, + line); + expect( + s.ends_with( + "has "s + std::to_string(support) + "% support. "s), + s, + __FILE__, + line); + clog = std::make_unique(); + }; + for (int i = 0; i < 1; ++i) { BEAST_EXPECT(!proposingTrue.updateVote(250 + 10 * i, true, p)); @@ -1342,22 +1409,34 @@ class Consensus_test : public beast::unit_test::suite BEAST_EXPECT(followingFalse.getOurVote() == false); // true vote has changed recently, so not stalled - BEAST_EXPECT(!proposingTrue.stalled(p, true, 0)); + BEAST_EXPECT(!proposingTrue.stalled(p, true, 0, j, clog)); + BEAST_EXPECT(clog->str() == ""); // remaining votes have been unchanged in so long that we only // need to hit the second round at 95% to be stalled, regardless // of peers - BEAST_EXPECT(proposingFalse.stalled(p, true, 0)); - BEAST_EXPECT(followingTrue.stalled(p, false, 0)); - BEAST_EXPECT(followingFalse.stalled(p, false, 0)); + BEAST_EXPECT(proposingFalse.stalled(p, true, 0, j, clog)); + expectStalled(98, false, 11, 0, 2, __LINE__); + BEAST_EXPECT(followingTrue.stalled(p, false, 0, j, clog)); + expectStalled(97, true, 11, 0, 97, __LINE__); + BEAST_EXPECT(followingFalse.stalled(p, false, 0, j, clog)); + expectStalled(96, false, 11, 0, 3, __LINE__); // true vote has changed recently, so not stalled - BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged)); + BEAST_EXPECT( + !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECTS(clog->str() == "", clog->str()); // remaining votes have been unchanged in so long that we only // need to hit the second round at 95% to be stalled, regardless // of peers - BEAST_EXPECT(proposingFalse.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(followingTrue.stalled(p, false, peersUnchanged)); - BEAST_EXPECT(followingFalse.stalled(p, false, peersUnchanged)); + BEAST_EXPECT( + proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + expectStalled(98, false, 11, 6, 2, __LINE__); + BEAST_EXPECT( + followingTrue.stalled(p, false, peersUnchanged, j, clog)); + expectStalled(97, true, 11, 6, 97, __LINE__); + BEAST_EXPECT( + followingFalse.stalled(p, false, peersUnchanged, j, clog)); + expectStalled(96, false, 11, 6, 3, __LINE__); } for (int i = 1; i < 3; ++i) { @@ -1374,19 +1453,31 @@ class Consensus_test : public beast::unit_test::suite // true vote changed 2 rounds ago, and peers are changing, so // not stalled - BEAST_EXPECT(!proposingTrue.stalled(p, true, 0)); + BEAST_EXPECT(!proposingTrue.stalled(p, true, 0, j, clog)); + BEAST_EXPECTS(clog->str() == "", clog->str()); // still stalled - BEAST_EXPECT(proposingFalse.stalled(p, true, 0)); - BEAST_EXPECT(followingTrue.stalled(p, false, 0)); - BEAST_EXPECT(followingFalse.stalled(p, false, 0)); + BEAST_EXPECT(proposingFalse.stalled(p, true, 0, j, clog)); + expectStalled(98, false, 11 + i, 0, 2, __LINE__); + BEAST_EXPECT(followingTrue.stalled(p, false, 0, j, clog)); + expectStalled(97, true, 11 + i, 0, 97, __LINE__); + BEAST_EXPECT(followingFalse.stalled(p, false, 0, j, clog)); + expectStalled(96, false, 11 + i, 0, 3, __LINE__); // true vote changed 2 rounds ago, and peers are NOT changing, // so stalled - BEAST_EXPECT(proposingTrue.stalled(p, true, peersUnchanged)); + BEAST_EXPECT( + proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + expectStalled(99, true, 1 + i, 6, 97, __LINE__); // still stalled - BEAST_EXPECT(proposingFalse.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(followingTrue.stalled(p, false, peersUnchanged)); - BEAST_EXPECT(followingFalse.stalled(p, false, peersUnchanged)); + BEAST_EXPECT( + proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + expectStalled(98, false, 11 + i, 6, 2, __LINE__); + BEAST_EXPECT( + followingTrue.stalled(p, false, peersUnchanged, j, clog)); + expectStalled(97, true, 11 + i, 6, 97, __LINE__); + BEAST_EXPECT( + followingFalse.stalled(p, false, peersUnchanged, j, clog)); + expectStalled(96, false, 11 + i, 6, 3, __LINE__); } for (int i = 3; i < 5; ++i) { @@ -1401,15 +1492,27 @@ class Consensus_test : public beast::unit_test::suite BEAST_EXPECT(followingTrue.getOurVote() == true); BEAST_EXPECT(followingFalse.getOurVote() == false); - BEAST_EXPECT(proposingTrue.stalled(p, true, 0)); - BEAST_EXPECT(proposingFalse.stalled(p, true, 0)); - BEAST_EXPECT(followingTrue.stalled(p, false, 0)); - BEAST_EXPECT(followingFalse.stalled(p, false, 0)); + BEAST_EXPECT(proposingTrue.stalled(p, true, 0, j, clog)); + expectStalled(99, true, 1 + i, 0, 97, __LINE__); + BEAST_EXPECT(proposingFalse.stalled(p, true, 0, j, clog)); + expectStalled(98, false, 11 + i, 0, 2, __LINE__); + BEAST_EXPECT(followingTrue.stalled(p, false, 0, j, clog)); + expectStalled(97, true, 11 + i, 0, 97, __LINE__); + BEAST_EXPECT(followingFalse.stalled(p, false, 0, j, clog)); + expectStalled(96, false, 11 + i, 0, 3, __LINE__); - BEAST_EXPECT(proposingTrue.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(proposingFalse.stalled(p, true, peersUnchanged)); - BEAST_EXPECT(followingTrue.stalled(p, false, peersUnchanged)); - BEAST_EXPECT(followingFalse.stalled(p, false, peersUnchanged)); + BEAST_EXPECT( + proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + expectStalled(99, true, 1 + i, 6, 97, __LINE__); + BEAST_EXPECT( + proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + expectStalled(98, false, 11 + i, 6, 2, __LINE__); + BEAST_EXPECT( + followingTrue.stalled(p, false, peersUnchanged, j, clog)); + expectStalled(97, true, 11 + i, 6, 97, __LINE__); + BEAST_EXPECT( + followingFalse.stalled(p, false, peersUnchanged, j, clog)); + expectStalled(96, false, 11 + i, 6, 3, __LINE__); } } } diff --git a/src/test/consensus/LedgerTrie_test.cpp b/src/test/consensus/LedgerTrie_test.cpp index f46fea8e6e0..6ed45777f09 100644 --- a/src/test/consensus/LedgerTrie_test.cpp +++ b/src/test/consensus/LedgerTrie_test.cpp @@ -313,7 +313,6 @@ class LedgerTrie_test : public beast::unit_test::suite testSupport() { using namespace csf; - using Seq = Ledger::Seq; LedgerTrie t; LedgerHistoryHelper h; @@ -596,7 +595,6 @@ class LedgerTrie_test : public beast::unit_test::suite testRootRelated() { using namespace csf; - using Seq = Ledger::Seq; // Since the root is a special node that breaks the no-single child // invariant, do some tests that exercise it. diff --git a/src/test/consensus/NegativeUNL_test.cpp b/src/test/consensus/NegativeUNL_test.cpp index 7eb05e68bb0..b56b8347265 100644 --- a/src/test/consensus/NegativeUNL_test.cpp +++ b/src/test/consensus/NegativeUNL_test.cpp @@ -227,7 +227,7 @@ class NegativeUNL_test : public beast::unit_test::suite testcase("Create UNLModify Tx and apply to ledgers"); - jtx::Env env(*this, jtx::supported_amendments() | featureNegativeUNL); + jtx::Env env(*this, jtx::testable_amendments() | featureNegativeUNL); std::vector publicKeys = createPublicKeys(3); // genesis ledger auto l = std::make_shared( @@ -526,7 +526,7 @@ class NegativeUNLNoAmendment_test : public beast::unit_test::suite { testcase("No negative UNL amendment"); - jtx::Env env(*this, jtx::supported_amendments() - featureNegativeUNL); + jtx::Env env(*this, jtx::testable_amendments() - featureNegativeUNL); std::vector publicKeys = createPublicKeys(1); // genesis ledger auto l = std::make_shared( @@ -582,7 +582,7 @@ struct NetworkHistory }; NetworkHistory(beast::unit_test::suite& suite, Parameter const& p) - : env(suite, jtx::supported_amendments() | featureNegativeUNL) + : env(suite, jtx::testable_amendments() | featureNegativeUNL) , param(p) , validations(env.app().getValidations()) { @@ -1885,8 +1885,8 @@ class NegativeUNLVoteFilterValidations_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(NegativeUNL, ledger, ripple); -BEAST_DEFINE_TESTSUITE(NegativeUNLNoAmendment, ledger, ripple); +BEAST_DEFINE_TESTSUITE(NegativeUNL, consensus, ripple); +BEAST_DEFINE_TESTSUITE(NegativeUNLNoAmendment, consensus, ripple); BEAST_DEFINE_TESTSUITE(NegativeUNLVoteInternal, consensus, ripple); BEAST_DEFINE_TESTSUITE_MANUAL(NegativeUNLVoteScoreTable, consensus, ripple); diff --git a/src/test/app/RCLCensorshipDetector_test.cpp b/src/test/consensus/RCLCensorshipDetector_test.cpp similarity index 98% rename from src/test/app/RCLCensorshipDetector_test.cpp rename to src/test/consensus/RCLCensorshipDetector_test.cpp index 85ba0ab78d7..1581dc81c4c 100644 --- a/src/test/app/RCLCensorshipDetector_test.cpp +++ b/src/test/consensus/RCLCensorshipDetector_test.cpp @@ -98,6 +98,6 @@ class RCLCensorshipDetector_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(RCLCensorshipDetector, app, ripple); +BEAST_DEFINE_TESTSUITE(RCLCensorshipDetector, consensus, ripple); } // namespace test } // namespace ripple diff --git a/src/test/consensus/Validations_test.cpp b/src/test/consensus/Validations_test.cpp index 4424d7619d2..a04e62b7235 100644 --- a/src/test/consensus/Validations_test.cpp +++ b/src/test/consensus/Validations_test.cpp @@ -805,7 +805,6 @@ class Validations_test : public beast::unit_test::suite Ledger ledgerACD = h["acd"]; using Seq = Ledger::Seq; - using ID = Ledger::ID; auto pref = [](Ledger ledger) { return std::make_pair(ledger.seq(), ledger.id()); diff --git a/src/test/csf/BasicNetwork_test.cpp b/src/test/csf/BasicNetwork_test.cpp index 4173db65022..4580dab4683 100644 --- a/src/test/csf/BasicNetwork_test.cpp +++ b/src/test/csf/BasicNetwork_test.cpp @@ -146,7 +146,7 @@ class BasicNetwork_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(BasicNetwork, test, ripple); +BEAST_DEFINE_TESTSUITE(BasicNetwork, csf, ripple); } // namespace test } // namespace ripple diff --git a/src/test/csf/Digraph_test.cpp b/src/test/csf/Digraph_test.cpp index 0cc4be19762..df78a10733b 100644 --- a/src/test/csf/Digraph_test.cpp +++ b/src/test/csf/Digraph_test.cpp @@ -92,7 +92,7 @@ class Digraph_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Digraph, test, ripple); +BEAST_DEFINE_TESTSUITE(Digraph, csf, ripple); } // namespace test } // namespace ripple diff --git a/src/test/csf/Histogram_test.cpp b/src/test/csf/Histogram_test.cpp index 40274c9046d..60f12e9a669 100644 --- a/src/test/csf/Histogram_test.cpp +++ b/src/test/csf/Histogram_test.cpp @@ -81,7 +81,7 @@ class Histogram_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Histogram, test, ripple); +BEAST_DEFINE_TESTSUITE(Histogram, csf, ripple); } // namespace test } // namespace ripple diff --git a/src/test/csf/README.md b/src/test/csf/README.md index a4b69abab57..30d5abb0422 100644 --- a/src/test/csf/README.md +++ b/src/test/csf/README.md @@ -26,7 +26,7 @@ collect when running the simulation. The specification includes: - A collection of [`Peer`s](./Peer.h) that represent the participants in the network, with each independently running the consensus algorithm. - The `Peer` trust relationships as a `TrustGraph`. This is a directed graph - whose edges define what other `Peer`s a given `Peer` trusts. In other words, + whose edges define what other `Peer`s a given `Peer` trusts. In other words, the set of out edges for a `Peer` in the graph correspond to the UNL of that `Peer`. - The network communication layer as a `BasicNetwork`. This models the overlay @@ -45,6 +45,7 @@ eventually fully validating the consensus history of accepted transactions. Each the registered `Collector`s. ## Example Simulation + Below is a basic simulation we can walk through to get an understanding of the framework. This simulation is for a set of 5 validators that aren't directly connected but rely on a single hub node for communication. @@ -98,12 +99,12 @@ center[0]->runAsValidator = false; The simulation code starts by creating a single instance of the [`Sim` class](./Sim.h). This class is used to manage the overall simulation and internally owns most other components, including the `Peer`s, `Scheduler`, -`BasicNetwork` and `TrustGraph`. The next two lines create two differ +`BasicNetwork` and `TrustGraph`. The next two lines create two differ `PeerGroup`s of size 5 and 1 . A [`PeerGroup`](./PeerGroup.h) is a convenient way for configuring a set of related peers together and internally has a vector of pointers to the `Peer`s which are owned by the `Sim`. `PeerGroup`s can be combined using `+/-` operators to configure more complex relationships of nodes -as shown by `PeerGroup network`. Note that each call to `createGroup` adds that +as shown by `PeerGroup network`. Note that each call to `createGroup` adds that many new `Peer`s to the simulation, but does not specify any trust or network relationships for the new `Peer`s. @@ -125,14 +126,14 @@ validators.connect(center, delay); Although the `sim` object has accessible instances of [TrustGraph](./TrustGraph.h) and [BasicNetwork](./BasicNetwork.h), it is more -convenient to manage the graphs via the `PeerGroup`s. The first two lines -create a trust topology in which all `Peer`s trust the 5 validating `Peer`s. Or +convenient to manage the graphs via the `PeerGroup`s. The first two lines +create a trust topology in which all `Peer`s trust the 5 validating `Peer`s. Or in the UNL perspective, all `Peer`s are configured with the same UNL listing the 5 validating `Peer`s. The two lines could've been rewritten as `network.trust(validators)`. The next lines create the network communication topology. Each of the validating -`Peer`s connects to the central hub `Peer` with a fixed delay of 200ms. Note +`Peer`s connects to the central hub `Peer` with a fixed delay of 200ms. Note that the network connections are really undirected, but are represented internally in a directed graph using edge pairs of inbound and outbound connections. @@ -143,11 +144,11 @@ SimDurationCollector simDur; sim.collectors.add(simDur); ``` -The next lines add a single collector to the simulation. The +The next lines add a single collector to the simulation. The `SimDurationCollector` is a simple example collector which tracks the total -duration of the simulation. More generally, a collector is any class that +duration of the simulation. More generally, a collector is any class that implements `void on(NodeID, SimTime, Event)` for all [Events](./events.h) -emitted by a Peer. Events are arbitrary types used to indicate some action or +emitted by a Peer. Events are arbitrary types used to indicate some action or change of state of a `Peer`. Other [existing collectors](./collectors.h) measure latencies of transaction submission to validation or the rate of ledger closing and monitor any jumps in ledger history. @@ -176,9 +177,9 @@ to send transactions in at fixed or random intervals to fixed or random `Peer`s. ## Run -The example has two calls to `sim.run(1)`. This call runs the simulation until -each `Peer` has closed one additional ledger. After closing the additional -ledger, the `Peer` stops participating in consensus. The first call is used to +The example has two calls to `sim.run(1)`. This call runs the simulation until +each `Peer` has closed one additional ledger. After closing the additional +ledger, the `Peer` stops participating in consensus. The first call is used to ensure a more useful prior state of all `Peer`s. After the transaction submission, the second call to `run` results in one additional ledger that accepts those transactions. @@ -188,4 +189,4 @@ Alternatively, you can specify a duration to run the simulation, e.g. scheduler has elapsed 10 additional seconds. The `sim.scheduler.in` or `sim.scheduler.at` methods can schedule arbitrary code to execute at a later time in the simulation, for example removing a network connection or modifying -the trust graph. \ No newline at end of file +the trust graph. diff --git a/src/test/csf/Scheduler_test.cpp b/src/test/csf/Scheduler_test.cpp index 1935e40236e..c31b881b03f 100644 --- a/src/test/csf/Scheduler_test.cpp +++ b/src/test/csf/Scheduler_test.cpp @@ -83,7 +83,7 @@ class Scheduler_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Scheduler, test, ripple); +BEAST_DEFINE_TESTSUITE(Scheduler, csf, ripple); } // namespace test } // namespace ripple diff --git a/src/test/json/Object_test.cpp b/src/test/json/Object_test.cpp index 94a9e96cf68..0ad5f76307f 100644 --- a/src/test/json/Object_test.cpp +++ b/src/test/json/Object_test.cpp @@ -253,6 +253,6 @@ class JsonObject_test : public ripple::test::TestOutputSuite } }; -BEAST_DEFINE_TESTSUITE(JsonObject, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(JsonObject, json, ripple); } // namespace Json diff --git a/src/test/json/Output_test.cpp b/src/test/json/Output_test.cpp index 2343843fe3d..6421682b019 100644 --- a/src/test/json/Output_test.cpp +++ b/src/test/json/Output_test.cpp @@ -61,6 +61,6 @@ struct Output_test : ripple::test::TestOutputSuite } }; -BEAST_DEFINE_TESTSUITE(Output, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(Output, json, ripple); } // namespace Json diff --git a/src/test/json/Writer_test.cpp b/src/test/json/Writer_test.cpp index c5305876ffb..3739af07e16 100644 --- a/src/test/json/Writer_test.cpp +++ b/src/test/json/Writer_test.cpp @@ -212,6 +212,6 @@ class JsonWriter_test : public ripple::test::TestOutputSuite } }; -BEAST_DEFINE_TESTSUITE(JsonWriter, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(JsonWriter, json, ripple); } // namespace Json diff --git a/src/test/jtx.h b/src/test/jtx.h index 41889100856..6347b9dcf98 100644 --- a/src/test/jtx.h +++ b/src/test/jtx.h @@ -22,6 +22,7 @@ // Convenience header that includes everything +#include #include #include #include diff --git a/src/test/jtx/AMMTest.h b/src/test/jtx/AMMTest.h index 28b9affa8f8..17011d76337 100644 --- a/src/test/jtx/AMMTest.h +++ b/src/test/jtx/AMMTest.h @@ -40,7 +40,7 @@ struct TestAMMArg std::optional> pool = std::nullopt; std::uint16_t tfee = 0; std::optional ter = std::nullopt; - std::vector features = {supported_amendments()}; + std::vector features = {testable_amendments()}; bool noLog = false; }; @@ -95,7 +95,7 @@ class AMMTestBase : public beast::unit_test::suite std::optional> const& pool = std::nullopt, std::uint16_t tfee = 0, std::optional const& ter = std::nullopt, - std::vector const& features = {supported_amendments()}); + std::vector const& features = {testable_amendments()}); void testAMM( diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index 53417a6079d..21a239e3d76 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -71,10 +71,10 @@ noripple(Account const& account, Args const&... args) } inline FeatureBitset -supported_amendments() +testable_amendments() { static FeatureBitset const ids = [] { - auto const& sa = ripple::detail::supportedAmendments(); + auto const& sa = allAmendments(); std::vector feats; feats.reserve(sa.size()); for (auto const& [s, vote] : sa) @@ -84,7 +84,7 @@ supported_amendments() feats.push_back(*f); else Throw( - "Unknown feature: " + s + " in supportedAmendments."); + "Unknown feature: " + s + " in allAmendments."); } return FeatureBitset(feats); }(); @@ -236,7 +236,7 @@ class Env beast::severities::Severity thresh = beast::severities::kError) : Env(suite_, std::move(config), - supported_amendments(), + testable_amendments(), std::move(logs), thresh) { diff --git a/src/test/jtx/Env_test.cpp b/src/test/jtx/Env_test.cpp index f32343d6dd7..34d9f6c0e83 100644 --- a/src/test/jtx/Env_test.cpp +++ b/src/test/jtx/Env_test.cpp @@ -265,7 +265,7 @@ class Env_test : public beast::unit_test::suite { using namespace jtx; - Env env{*this, supported_amendments() | fixMasterKeyAsRegularKey}; + Env env{*this, testable_amendments() | fixMasterKeyAsRegularKey}; Account const alice("alice", KeyType::ed25519); Account const bob("bob", KeyType::secp256k1); Account const carol("carol"); @@ -776,7 +776,7 @@ class Env_test : public beast::unit_test::suite { testcase("Env features"); using namespace jtx; - auto const supported = supported_amendments(); + auto const supported = testable_amendments(); // this finds a feature that is not in // the supported amendments list and tests that it can be @@ -827,7 +827,7 @@ class Env_test : public beast::unit_test::suite } auto const missingSomeFeatures = - supported_amendments() - featureMultiSignReserve - featureFlow; + testable_amendments() - featureMultiSignReserve - featureFlow; BEAST_EXPECT(missingSomeFeatures.count() == (supported.count() - 2)); { // a Env supported_features_except is missing *only* those features @@ -887,7 +887,7 @@ class Env_test : public beast::unit_test::suite // add a feature that is NOT in the supported amendments list // along with all supported amendments // the unsupported features should be enabled - Env env{*this, supported_amendments().set(*neverSupportedFeat)}; + Env env{*this, testable_amendments().set(*neverSupportedFeat)}; // this app will have all supported amendments and then the // one additional never supported feature flag @@ -944,7 +944,7 @@ class Env_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Env, app, ripple); +BEAST_DEFINE_TESTSUITE(Env, jtx, ripple); } // namespace test } // namespace ripple diff --git a/src/test/jtx/TrustedPublisherServer.h b/src/test/jtx/TrustedPublisherServer.h index 54538032f52..7bc092cbe31 100644 --- a/src/test/jtx/TrustedPublisherServer.h +++ b/src/test/jtx/TrustedPublisherServer.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -220,9 +221,8 @@ class TrustedPublisherServer getList_ = [blob = blob, sig, manifest, version](int interval) { // Build the contents of a version 1 format UNL file std::stringstream l; - l << "{\"blob\":\"" << blob << "\"" - << ",\"signature\":\"" << sig << "\"" - << ",\"manifest\":\"" << manifest << "\"" + l << "{\"blob\":\"" << blob << "\"" << ",\"signature\":\"" << sig + << "\"" << ",\"manifest\":\"" << manifest << "\"" << ",\"refresh_interval\": " << interval << ",\"version\":" << version << '}'; return l.str(); @@ -257,15 +257,14 @@ class TrustedPublisherServer std::stringstream l; for (auto const& info : blobInfo) { - l << "{\"blob\":\"" << info.blob << "\"" - << ",\"signature\":\"" << info.signature << "\"},"; + l << "{\"blob\":\"" << info.blob << "\"" << ",\"signature\":\"" + << info.signature << "\"},"; } std::string blobs = l.str(); blobs.pop_back(); l.str(std::string()); l << "{\"blobs_v2\": [ " << blobs << "],\"manifest\":\"" << manifest - << "\"" - << ",\"refresh_interval\": " << interval + << "\"" << ",\"refresh_interval\": " << interval << ",\"version\":" << (version + 1) << '}'; return l.str(); }; diff --git a/src/test/jtx/WSClient_test.cpp b/src/test/jtx/WSClient_test.cpp index 471e6ff31be..431c57558a1 100644 --- a/src/test/jtx/WSClient_test.cpp +++ b/src/test/jtx/WSClient_test.cpp @@ -46,7 +46,7 @@ class WSClient_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(WSClient, test, ripple); +BEAST_DEFINE_TESTSUITE(WSClient, jtx, ripple); } // namespace test } // namespace ripple diff --git a/src/test/jtx/envconfig.h b/src/test/jtx/envconfig.h index f22c5743e72..432ef28ff6b 100644 --- a/src/test/jtx/envconfig.h +++ b/src/test/jtx/envconfig.h @@ -127,6 +127,11 @@ addGrpcConfigWithSecureGateway( std::unique_ptr, std::string const& secureGateway); +std::unique_ptr +makeConfig( + std::map extraTxQ = {}, + std::map extraVoting = {}); + } // namespace jtx } // namespace test } // namespace ripple diff --git a/src/test/jtx/impl/envconfig.cpp b/src/test/jtx/impl/envconfig.cpp index dd9c7354653..624036196d5 100644 --- a/src/test/jtx/impl/envconfig.cpp +++ b/src/test/jtx/impl/envconfig.cpp @@ -140,6 +140,39 @@ addGrpcConfigWithSecureGateway( return cfg; } +std::unique_ptr +makeConfig( + std::map extraTxQ, + std::map extraVoting) +{ + auto p = test::jtx::envconfig(); + auto& section = p->section("transaction_queue"); + section.set("ledgers_in_queue", "2"); + section.set("minimum_queue_size", "2"); + section.set("min_ledgers_to_compute_size_limit", "3"); + section.set("max_ledger_counts_to_store", "100"); + section.set("retry_sequence_percent", "25"); + section.set("normal_consensus_increase_percent", "0"); + + for (auto const& [k, v] : extraTxQ) + section.set(k, v); + + // Some tests specify different fee settings that are enabled by + // a FeeVote + if (!extraVoting.empty()) + { + auto& votingSection = p->section("voting"); + for (auto const& [k, v] : extraVoting) + { + votingSection.set(k, v); + } + + // In order for the vote to occur, we must run as a validator + p->section("validation_seed").legacy("shUwVw52ofnCUX5m7kPTKzJdr4HEH"); + } + return p; +} + } // namespace jtx } // namespace test } // namespace ripple diff --git a/src/test/jtx/impl/mpt.cpp b/src/test/jtx/impl/mpt.cpp index c8ff167221a..9f7a611feba 100644 --- a/src/test/jtx/impl/mpt.cpp +++ b/src/test/jtx/impl/mpt.cpp @@ -17,8 +17,9 @@ */ //============================================================================== -#include +#include +#include #include namespace ripple { @@ -99,6 +100,8 @@ MPTTester::create(MPTCreate const& arg) jv[sfMPTokenMetadata] = strHex(*arg.metadata); if (arg.maxAmt) jv[sfMaximumAmount] = std::to_string(*arg.maxAmt); + if (arg.domainID) + jv[sfDomainID] = to_string(*arg.domainID); if (submit(arg, jv) != tesSUCCESS) { // Verify issuance doesn't exist @@ -235,6 +238,8 @@ MPTTester::set(MPTSet const& arg) jv[sfHolder] = arg.holder->human(); if (arg.delegate) jv[sfDelegate] = arg.delegate->human(); + if (arg.domainID) + jv[sfDomainID] = to_string(*arg.domainID); if (submit(arg, jv) == tesSUCCESS && arg.flags.value_or(0)) { auto require = [&](std::optional const& holder, @@ -272,6 +277,16 @@ MPTTester::forObject( return false; } +[[nodiscard]] bool +MPTTester::checkDomainID(std::optional expected) const +{ + return forObject([&](SLEP const& sle) -> bool { + if (sle->isFieldPresent(sfDomainID)) + return expected == sle->getFieldH256(sfDomainID); + return (!expected.has_value()); + }); +} + [[nodiscard]] bool MPTTester::checkMPTokenAmount( Account const& holder_, diff --git a/src/test/jtx/impl/permissioned_dex.cpp b/src/test/jtx/impl/permissioned_dex.cpp index 04497ebbdcf..4b09a11880e 100644 --- a/src/test/jtx/impl/permissioned_dex.cpp +++ b/src/test/jtx/impl/permissioned_dex.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include diff --git a/src/test/jtx/impl/permissioned_domains.cpp b/src/test/jtx/impl/permissioned_domains.cpp index 866ca3bb7e7..441ee325c85 100644 --- a/src/test/jtx/impl/permissioned_domains.cpp +++ b/src/test/jtx/impl/permissioned_domains.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/xchain_bridge.cpp b/src/test/jtx/impl/xchain_bridge.cpp index 86e9deda7c1..6f167d75082 100644 --- a/src/test/jtx/impl/xchain_bridge.cpp +++ b/src/test/jtx/impl/xchain_bridge.cpp @@ -389,7 +389,7 @@ XChainBridgeObjects::XChainBridgeObjects() bridge_rpc(mcDoor, xrpIssue(), Account::master, xrpIssue())) , jvb(bridge(mcDoor, xrpIssue(), Account::master, xrpIssue())) , jvub(bridge(mcuDoor, xrpIssue(), Account::master, xrpIssue())) - , features(supported_amendments() | FeatureBitset{featureXChainBridge}) + , features(testable_amendments() | FeatureBitset{featureXChainBridge}) , signers([] { constexpr int numSigners = UT_XCHAIN_DEFAULT_NUM_SIGNERS; std::vector result; diff --git a/src/test/jtx/mpt.h b/src/test/jtx/mpt.h index 52ade923233..4756ca723d7 100644 --- a/src/test/jtx/mpt.h +++ b/src/test/jtx/mpt.h @@ -20,7 +20,8 @@ #ifndef RIPPLE_TEST_JTX_MPT_H_INCLUDED #define RIPPLE_TEST_JTX_MPT_H_INCLUDED -#include +#include +#include #include #include @@ -105,6 +106,7 @@ struct MPTCreate std::optional holderCount = std::nullopt; bool fund = true; std::optional flags = {0}; + std::optional domainID = std::nullopt; std::optional err = std::nullopt; }; @@ -138,6 +140,7 @@ struct MPTSet std::optional holderCount = std::nullopt; std::optional flags = std::nullopt; std::optional delegate = std::nullopt; + std::optional domainID = std::nullopt; std::optional err = std::nullopt; }; @@ -164,6 +167,9 @@ class MPTTester void set(MPTSet const& set = {}); + [[nodiscard]] bool + checkDomainID(std::optional expected) const; + [[nodiscard]] bool checkMPTokenAmount(Account const& holder, std::int64_t expectedAmount) const; diff --git a/src/test/jtx/permissioned_dex.h b/src/test/jtx/permissioned_dex.h index fb32e1c1be7..b95574d94de 100644 --- a/src/test/jtx/permissioned_dex.h +++ b/src/test/jtx/permissioned_dex.h @@ -19,7 +19,9 @@ #pragma once -#include +#include +#include + namespace ripple { namespace test { namespace jtx { diff --git a/src/test/jtx/permissioned_domains.h b/src/test/jtx/permissioned_domains.h index ee80c6a69f5..ed086e366d8 100644 --- a/src/test/jtx/permissioned_domains.h +++ b/src/test/jtx/permissioned_domains.h @@ -20,7 +20,8 @@ #ifndef RIPPLE_TEST_JTX_PERMISSIONED_DOMAINS_H_INCLUDED #define RIPPLE_TEST_JTX_PERMISSIONED_DOMAINS_H_INCLUDED -#include +#include +#include #include namespace ripple { diff --git a/src/test/ledger/BookDirs_test.cpp b/src/test/ledger/BookDirs_test.cpp index 28d9d2c1028..52b618e9a02 100644 --- a/src/test/ledger/BookDirs_test.cpp +++ b/src/test/ledger/BookDirs_test.cpp @@ -103,8 +103,7 @@ struct BookDirs_test : public beast::unit_test::suite run() override { using namespace jtx; - auto const sa = supported_amendments(); - test_bookdir(sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); test_bookdir(sa - featurePermissionedDEX); test_bookdir(sa); } diff --git a/src/test/ledger/Directory_test.cpp b/src/test/ledger/Directory_test.cpp index 7aa6f149b8a..9e8d40e0ccf 100644 --- a/src/test/ledger/Directory_test.cpp +++ b/src/test/ledger/Directory_test.cpp @@ -421,7 +421,7 @@ struct Directory_test : public beast::unit_test::suite }; // fixPreviousTxnID is disabled. - Env env(*this, supported_amendments() - fixPreviousTxnID); + Env env(*this, testable_amendments() - fixPreviousTxnID); env.fund(XRP(10000), alice, gw); env.close(); env.trust(USD(1000), alice); diff --git a/src/test/ledger/PaymentSandbox_test.cpp b/src/test/ledger/PaymentSandbox_test.cpp index 8bb0666e062..26b06a0034b 100644 --- a/src/test/ledger/PaymentSandbox_test.cpp +++ b/src/test/ledger/PaymentSandbox_test.cpp @@ -420,8 +420,7 @@ class PaymentSandbox_test : public beast::unit_test::suite testBalanceHook(features); }; using namespace jtx; - auto const sa = supported_amendments(); - testAll(sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); testAll(sa - featurePermissionedDEX); testAll(sa); } diff --git a/src/test/nodestore/Backend_test.cpp b/src/test/nodestore/Backend_test.cpp index 488370fbe97..f161f7a0c0a 100644 --- a/src/test/nodestore/Backend_test.cpp +++ b/src/test/nodestore/Backend_test.cpp @@ -121,7 +121,7 @@ class Backend_test : public TestBase } }; -BEAST_DEFINE_TESTSUITE(Backend, ripple_core, ripple); +BEAST_DEFINE_TESTSUITE(Backend, nodestore, ripple); } // namespace NodeStore } // namespace ripple diff --git a/src/test/nodestore/Basics_test.cpp b/src/test/nodestore/Basics_test.cpp index 62a66c9dce0..d781bb0c783 100644 --- a/src/test/nodestore/Basics_test.cpp +++ b/src/test/nodestore/Basics_test.cpp @@ -85,7 +85,7 @@ class NodeStoreBasic_test : public TestBase } }; -BEAST_DEFINE_TESTSUITE(NodeStoreBasic, ripple_core, ripple); +BEAST_DEFINE_TESTSUITE(NodeStoreBasic, nodestore, ripple); } // namespace NodeStore } // namespace ripple diff --git a/src/test/nodestore/Database_test.cpp b/src/test/nodestore/Database_test.cpp index bbf6381ee50..5ecb5b94e8a 100644 --- a/src/test/nodestore/Database_test.cpp +++ b/src/test/nodestore/Database_test.cpp @@ -765,7 +765,7 @@ class Database_test : public TestBase } }; -BEAST_DEFINE_TESTSUITE(Database, NodeStore, ripple); +BEAST_DEFINE_TESTSUITE(Database, nodestore, ripple); } // namespace NodeStore } // namespace ripple diff --git a/src/test/nodestore/Timing_test.cpp b/src/test/nodestore/Timing_test.cpp index 3df18eee66a..1ba5903cbe8 100644 --- a/src/test/nodestore/Timing_test.cpp +++ b/src/test/nodestore/Timing_test.cpp @@ -779,7 +779,7 @@ class Timing_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Timing, NodeStore, ripple, 1); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Timing, nodestore, ripple, 1); } // namespace NodeStore } // namespace ripple diff --git a/src/test/nodestore/import_test.cpp b/src/test/nodestore/import_test.cpp index d7865a20fc0..11009ec5bed 100644 --- a/src/test/nodestore/import_test.cpp +++ b/src/test/nodestore/import_test.cpp @@ -549,7 +549,7 @@ class import_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL(import, NodeStore, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(import, nodestore, ripple); #endif diff --git a/src/test/nodestore/varint_test.cpp b/src/test/nodestore/varint_test.cpp index 4f6d3c141cc..f047616d79e 100644 --- a/src/test/nodestore/varint_test.cpp +++ b/src/test/nodestore/varint_test.cpp @@ -72,7 +72,7 @@ class varint_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(varint, NodeStore, ripple); +BEAST_DEFINE_TESTSUITE(varint, nodestore, ripple); } // namespace tests } // namespace NodeStore diff --git a/src/test/overlay/compression_test.cpp b/src/test/overlay/compression_test.cpp index 4ecbe7f2328..01be43d58b3 100644 --- a/src/test/overlay/compression_test.cpp +++ b/src/test/overlay/compression_test.cpp @@ -537,7 +537,7 @@ class compression_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL(compression, ripple_data, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(compression, overlay, ripple); } // namespace test } // namespace ripple diff --git a/src/test/overlay/handshake_test.cpp b/src/test/overlay/handshake_test.cpp index 2d5155aaee6..936b6e5fff1 100644 --- a/src/test/overlay/handshake_test.cpp +++ b/src/test/overlay/handshake_test.cpp @@ -59,7 +59,7 @@ class handshake_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(handshake, ripple_data, ripple); +BEAST_DEFINE_TESTSUITE(handshake, overlay, ripple); } // namespace test } // namespace ripple diff --git a/src/test/overlay/reduce_relay_test.cpp b/src/test/overlay/reduce_relay_test.cpp index a8aafcfa065..0047454cf9f 100644 --- a/src/test/overlay/reduce_relay_test.cpp +++ b/src/test/overlay/reduce_relay_test.cpp @@ -1748,8 +1748,8 @@ class reduce_relay_simulate_test : public reduce_relay_test } }; -BEAST_DEFINE_TESTSUITE(reduce_relay, ripple_data, ripple); -BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, ripple_data, ripple); +BEAST_DEFINE_TESTSUITE(reduce_relay, overlay, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, overlay, ripple); } // namespace test diff --git a/src/test/overlay/tx_reduce_relay_test.cpp b/src/test/overlay/tx_reduce_relay_test.cpp index 7a6b36ecd2b..0024f2b98ed 100644 --- a/src/test/overlay/tx_reduce_relay_test.cpp +++ b/src/test/overlay/tx_reduce_relay_test.cpp @@ -284,6 +284,6 @@ class tx_reduce_relay_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(tx_reduce_relay, ripple_data, ripple); +BEAST_DEFINE_TESTSUITE(tx_reduce_relay, overlay, ripple); } // namespace test } // namespace ripple diff --git a/src/test/peerfinder/PeerFinder_test.cpp b/src/test/peerfinder/PeerFinder_test.cpp index 9006b8c1c7f..f35cbbdaae5 100644 --- a/src/test/peerfinder/PeerFinder_test.cpp +++ b/src/test/peerfinder/PeerFinder_test.cpp @@ -367,7 +367,7 @@ class PeerFinder_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(PeerFinder, PeerFinder, ripple); +BEAST_DEFINE_TESTSUITE(PeerFinder, peerfinder, ripple); } // namespace PeerFinder } // namespace ripple diff --git a/src/test/protocol/InnerObjectFormats_test.cpp b/src/test/protocol/InnerObjectFormats_test.cpp index f4d9722392c..daf9548b8b7 100644 --- a/src/test/protocol/InnerObjectFormats_test.cpp +++ b/src/test/protocol/InnerObjectFormats_test.cpp @@ -201,6 +201,6 @@ class InnerObjectFormatsParsedJSON_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(InnerObjectFormatsParsedJSON, ripple_app, ripple); +BEAST_DEFINE_TESTSUITE(InnerObjectFormatsParsedJSON, protocol, ripple); } // namespace ripple diff --git a/src/test/protocol/Memo_test.cpp b/src/test/protocol/Memo_test.cpp index a7fa846a4d2..3b36cfc3684 100644 --- a/src/test/protocol/Memo_test.cpp +++ b/src/test/protocol/Memo_test.cpp @@ -135,6 +135,6 @@ class Memo_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Memo, ripple_data, ripple); +BEAST_DEFINE_TESTSUITE(Memo, protocol, ripple); } // namespace ripple diff --git a/src/test/protocol/STAmount_test.cpp b/src/test/protocol/STAmount_test.cpp index d62241f2f46..5d3fdfb28aa 100644 --- a/src/test/protocol/STAmount_test.cpp +++ b/src/test/protocol/STAmount_test.cpp @@ -1052,6 +1052,6 @@ class STAmount_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(STAmount, ripple_data, ripple); +BEAST_DEFINE_TESTSUITE(STAmount, protocol, ripple); } // namespace ripple diff --git a/src/test/protocol/STIssue_test.cpp b/src/test/protocol/STIssue_test.cpp index 6e8d37331b1..6ef80cd3792 100644 --- a/src/test/protocol/STIssue_test.cpp +++ b/src/test/protocol/STIssue_test.cpp @@ -159,7 +159,7 @@ class STIssue_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(STIssue, ripple_data, ripple); +BEAST_DEFINE_TESTSUITE(STIssue, protocol, ripple); } // namespace test } // namespace ripple diff --git a/src/test/protocol/STTx_test.cpp b/src/test/protocol/STTx_test.cpp index f48bea11aa0..eaa7a15212a 100644 --- a/src/test/protocol/STTx_test.cpp +++ b/src/test/protocol/STTx_test.cpp @@ -1857,7 +1857,7 @@ class InnerObjectFormatsSerializer_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(STTx, ripple_app, ripple); -BEAST_DEFINE_TESTSUITE(InnerObjectFormatsSerializer, ripple_app, ripple); +BEAST_DEFINE_TESTSUITE(STTx, protocol, ripple); +BEAST_DEFINE_TESTSUITE(InnerObjectFormatsSerializer, protocol, ripple); } // namespace ripple diff --git a/src/test/rpc/AMMInfo_test.cpp b/src/test/rpc/AMMInfo_test.cpp index 1c54580aa70..d5bfc8e83d8 100644 --- a/src/test/rpc/AMMInfo_test.cpp +++ b/src/test/rpc/AMMInfo_test.cpp @@ -359,7 +359,7 @@ class AMMInfo_test : public jtx::AMMTestBase run() override { using namespace jtx; - auto const all = supported_amendments(); + auto const all = testable_amendments(); testErrors(); testSimpleRpc(); testVoteAndBid(all); @@ -369,7 +369,7 @@ class AMMInfo_test : public jtx::AMMTestBase } }; -BEAST_DEFINE_TESTSUITE(AMMInfo, app, ripple); +BEAST_DEFINE_TESTSUITE(AMMInfo, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/AccountInfo_test.cpp b/src/test/rpc/AccountInfo_test.cpp index 238b7396118..18c8bf5a1c0 100644 --- a/src/test/rpc/AccountInfo_test.cpp +++ b/src/test/rpc/AccountInfo_test.cpp @@ -675,6 +675,30 @@ class AccountInfo_test : public beast::unit_test::suite BEAST_EXPECT( !getAccountFlag(allowTrustLineClawbackFlag.first, bob)); } + + static constexpr std::pair + allowTrustLineLockingFlag{ + "allowTrustLineLocking", asfAllowTrustLineLocking}; + + if (features[featureTokenEscrow]) + { + auto const f1 = + getAccountFlag(allowTrustLineLockingFlag.first, bob); + BEAST_EXPECT(f1.has_value()); + BEAST_EXPECT(!f1.value()); + + // Set allowTrustLineLocking + env(fset(bob, allowTrustLineLockingFlag.second)); + env.close(); + auto const f2 = + getAccountFlag(allowTrustLineLockingFlag.first, bob); + BEAST_EXPECT(f2.has_value()); + BEAST_EXPECT(f2.value()); + } + else + { + BEAST_EXPECT(!getAccountFlag(allowTrustLineLockingFlag.first, bob)); + } } void @@ -686,11 +710,14 @@ class AccountInfo_test : public beast::unit_test::suite testSignerListsV2(); FeatureBitset const allFeatures{ - ripple::test::jtx::supported_amendments()}; + ripple::test::jtx::testable_amendments()}; testAccountFlags(allFeatures); testAccountFlags(allFeatures - featureDisallowIncoming); testAccountFlags( allFeatures - featureDisallowIncoming - featureClawback); + testAccountFlags( + allFeatures - featureDisallowIncoming - featureClawback - + featureTokenEscrow); } }; diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 7a48db73bdf..546bbe87156 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -577,7 +577,7 @@ class AccountObjects_test : public beast::unit_test::suite Account const gw{"gateway"}; auto const USD = gw["USD"]; - auto const features = supported_amendments() | featureXChainBridge | + auto const features = testable_amendments() | featureXChainBridge | featurePermissionedDomains; Env env(*this, features); diff --git a/src/test/rpc/AccountSet_test.cpp b/src/test/rpc/AccountSet_test.cpp index c056279bf16..3615a715cd4 100644 --- a/src/test/rpc/AccountSet_test.cpp +++ b/src/test/rpc/AccountSet_test.cpp @@ -53,7 +53,7 @@ class AccountSet_test : public beast::unit_test::suite Account const alice("alice"); // Test without DepositAuth enabled initially. - Env env(*this, supported_amendments() - featureDepositAuth); + Env env(*this, testable_amendments() - featureDepositAuth); env.fund(XRP(10000), noripple(alice)); // Give alice a regular key so she can legally set and clear @@ -357,7 +357,7 @@ class AccountSet_test : public beast::unit_test::suite }; doTests( - supported_amendments(), + testable_amendments(), {{1.0, tesSUCCESS, 1.0}, {1.1, tesSUCCESS, 1.1}, {2.0, tesSUCCESS, 2.0}, @@ -597,6 +597,6 @@ class AccountSet_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(AccountSet, app, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(AccountSet, rpc, ripple, 1); } // namespace ripple diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index 6e25c26e589..82809b5c5b5 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -18,9 +18,12 @@ //============================================================================== #include +#include #include +#include #include +#include #include #include @@ -753,6 +756,85 @@ class AccountTx_test : public beast::unit_test::suite } } + void + testMPT() + { + testcase("MPT"); + + using namespace test::jtx; + using namespace std::chrono_literals; + + auto cfg = makeConfig(); + cfg->FEES.reference_fee = 10; + Env env(*this, std::move(cfg)); + + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const carol{"carol"}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + // check the latest mpt-related txn is in alice's account history + auto const checkAliceAcctTx = [&](size_t size, + Json::StaticString txType) { + Json::Value params; + params[jss::account] = alice.human(); + params[jss::limit] = 100; + auto const jv = + env.rpc("json", "account_tx", to_string(params))[jss::result]; + + BEAST_EXPECT(jv[jss::transactions].size() == size); + auto const& tx0(jv[jss::transactions][0u][jss::tx]); + BEAST_EXPECT(tx0[jss::TransactionType] == txType); + + std::string const txHash{ + env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + BEAST_EXPECT(tx0[jss::hash] == txHash); + }; + + // alice creates issuance + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanClawback | tfMPTRequireAuth | tfMPTCanTransfer}); + + checkAliceAcctTx(3, jss::MPTokenIssuanceCreate); + + // bob creates a MPToken; + mptAlice.authorize({.account = bob}); + checkAliceAcctTx(4, jss::MPTokenAuthorize); + env.close(); + + // TODO: windows pipeline fails validation for the hardcoded ledger hash + // due to having different test config, it can be uncommented after + // figuring out what happened + // + // ledger hash should be fixed regardless any change to account history + // BEAST_EXPECT( + // to_string(env.closed()->info().hash) == + // "0BD507BB87D3C0E73B462485E6E381798A8C82FC49BF17FE39C60E08A1AF035D"); + + // alice authorizes bob + mptAlice.authorize({.account = alice, .holder = bob}); + checkAliceAcctTx(5, jss::MPTokenAuthorize); + + // carol creates a MPToken; + mptAlice.authorize({.account = carol}); + checkAliceAcctTx(6, jss::MPTokenAuthorize); + + // alice authorizes carol + mptAlice.authorize({.account = alice, .holder = carol}); + checkAliceAcctTx(7, jss::MPTokenAuthorize); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + checkAliceAcctTx(8, jss::Payment); + + // bob pays carol 10 tokens + mptAlice.pay(bob, carol, 10); + checkAliceAcctTx(9, jss::Payment); + } + public: void run() override @@ -761,6 +843,7 @@ class AccountTx_test : public beast::unit_test::suite std::bind_front(&AccountTx_test::testParameters, this)); testContents(); testAccountDelete(); + testMPT(); } }; BEAST_DEFINE_TESTSUITE(AccountTx, rpc, ripple); diff --git a/src/test/rpc/AmendmentBlocked_test.cpp b/src/test/rpc/AmendmentBlocked_test.cpp index bea9cdf57d1..4708a873f69 100644 --- a/src/test/rpc/AmendmentBlocked_test.cpp +++ b/src/test/rpc/AmendmentBlocked_test.cpp @@ -255,6 +255,6 @@ class AmendmentBlocked_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(AmendmentBlocked, app, ripple); +BEAST_DEFINE_TESTSUITE(AmendmentBlocked, rpc, ripple); } // namespace ripple diff --git a/src/test/rpc/BookChanges_test.cpp b/src/test/rpc/BookChanges_test.cpp index 1f059c2bf73..41b26415aff 100644 --- a/src/test/rpc/BookChanges_test.cpp +++ b/src/test/rpc/BookChanges_test.cpp @@ -94,7 +94,7 @@ class BookChanges_test : public beast::unit_test::suite using namespace jtx; FeatureBitset const all{ - jtx::supported_amendments() | featurePermissionedDomains | + jtx::testable_amendments() | featurePermissionedDomains | featureCredentials | featurePermissionedDEX}; Env env(*this, all); @@ -143,7 +143,7 @@ class BookChanges_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(BookChanges, app, ripple); +BEAST_DEFINE_TESTSUITE(BookChanges, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/Book_test.cpp b/src/test/rpc/Book_test.cpp index 0ec36eca532..7177ab847c0 100644 --- a/src/test/rpc/Book_test.cpp +++ b/src/test/rpc/Book_test.cpp @@ -1737,7 +1737,7 @@ class Book_test : public beast::unit_test::suite using namespace jtx; FeatureBitset const all{ - jtx::supported_amendments() | featurePermissionedDomains | + jtx::testable_amendments() | featurePermissionedDomains | featureCredentials | featurePermissionedDEX}; Env env(*this, all); @@ -1868,7 +1868,7 @@ class Book_test : public beast::unit_test::suite using namespace jtx; FeatureBitset const all{ - jtx::supported_amendments() | featurePermissionedDomains | + jtx::testable_amendments() | featurePermissionedDomains | featureCredentials | featurePermissionedDEX}; Env env(*this, all); @@ -2019,7 +2019,7 @@ class Book_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(Book, app, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(Book, rpc, ripple, 1); } // namespace test } // namespace ripple diff --git a/src/test/rpc/DeliveredAmount_test.cpp b/src/test/rpc/DeliveredAmount_test.cpp index 17763790e84..c1aa77695d5 100644 --- a/src/test/rpc/DeliveredAmount_test.cpp +++ b/src/test/rpc/DeliveredAmount_test.cpp @@ -21,6 +21,7 @@ #include #include +#include #include namespace ripple { @@ -329,16 +330,99 @@ class DeliveredAmount_test : public beast::unit_test::suite } } + void + testMPTDeliveredAmountRPC(FeatureBitset features) + { + testcase("MPT DeliveredAmount"); + + using namespace jtx; + Account const alice("alice"); + Account const carol("carol"); + Account const bob("bob"); + Env env{*this, features}; + + MPTTester mptAlice( + env, alice, {.holders = {bob, carol}, .close = false}); + + mptAlice.create( + {.transferFee = 25000, + .ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanTransfer}); + auto const MPT = mptAlice["MPT"]; + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + // issuer to holder + mptAlice.pay(alice, bob, 10000); + + // holder to holder + env(pay(bob, carol, mptAlice.mpt(1000)), txflags(tfPartialPayment)); + env.close(); + + // Get the hash for the most recent transaction. + std::string txHash{ + env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + Json::Value meta = env.rpc("tx", txHash)[jss::result][jss::meta]; + + if (features[fixMPTDeliveredAmount]) + { + BEAST_EXPECT( + meta[sfDeliveredAmount.jsonName] == + STAmount{MPT(800)}.getJson(JsonOptions::none)); + BEAST_EXPECT( + meta[jss::delivered_amount] == + STAmount{MPT(800)}.getJson(JsonOptions::none)); + } + else + { + BEAST_EXPECT(!meta.isMember(sfDeliveredAmount.jsonName)); + BEAST_EXPECT( + meta[jss::delivered_amount] = Json::Value("unavailable")); + } + + env(pay(bob, carol, MPT(1000)), + sendmax(MPT(1200)), + txflags(tfPartialPayment)); + env.close(); + + txHash = env.tx()->getJson(JsonOptions::none)[jss::hash].asString(); + meta = env.rpc("tx", txHash)[jss::result][jss::meta]; + + if (features[fixMPTDeliveredAmount]) + { + BEAST_EXPECT( + meta[sfDeliveredAmount.jsonName] == + STAmount{MPT(960)}.getJson(JsonOptions::none)); + BEAST_EXPECT( + meta[jss::delivered_amount] == + STAmount{MPT(960)}.getJson(JsonOptions::none)); + } + else + { + BEAST_EXPECT(!meta.isMember(sfDeliveredAmount.jsonName)); + BEAST_EXPECT( + meta[jss::delivered_amount] = Json::Value("unavailable")); + } + } + public: void run() override { + using namespace test::jtx; + FeatureBitset const all{testable_amendments()}; + testTxDeliveredAmountRPC(); testAccountDeliveredAmountSubscribe(); + + testMPTDeliveredAmountRPC(all - fixMPTDeliveredAmount); + testMPTDeliveredAmountRPC(all); } }; -BEAST_DEFINE_TESTSUITE(DeliveredAmount, app, ripple); +BEAST_DEFINE_TESTSUITE(DeliveredAmount, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/DepositAuthorized_test.cpp b/src/test/rpc/DepositAuthorized_test.cpp index 647f9e25ed4..326766221af 100644 --- a/src/test/rpc/DepositAuthorized_test.cpp +++ b/src/test/rpc/DepositAuthorized_test.cpp @@ -638,7 +638,7 @@ class DepositAuthorized_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(DepositAuthorized, app, ripple); +BEAST_DEFINE_TESTSUITE(DepositAuthorized, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/Feature_test.cpp b/src/test/rpc/Feature_test.cpp index 40de395a71f..06697f80c17 100644 --- a/src/test/rpc/Feature_test.cpp +++ b/src/test/rpc/Feature_test.cpp @@ -139,7 +139,8 @@ class Feature_test : public beast::unit_test::suite // Test a random sampling of the variables. If any of these get retired // or removed, swap out for any other feature. - BEAST_EXPECT(featureToName(featureOwnerPaysFee) == "OwnerPaysFee"); + BEAST_EXPECT( + featureToName(fixTrustLinesToSelf) == "fixTrustLinesToSelf"); BEAST_EXPECT(featureToName(featureFlow) == "Flow"); BEAST_EXPECT(featureToName(featureNegativeUNL) == "NegativeUNL"); BEAST_EXPECT(featureToName(fix1578) == "fix1578"); diff --git a/src/test/rpc/GatewayBalances_test.cpp b/src/test/rpc/GatewayBalances_test.cpp index 7e9273d25ee..a13e5bc20c6 100644 --- a/src/test/rpc/GatewayBalances_test.cpp +++ b/src/test/rpc/GatewayBalances_test.cpp @@ -251,11 +251,8 @@ class GatewayBalances_test : public beast::unit_test::suite run() override { using namespace jtx; - auto const sa = supported_amendments(); - for (auto feature : - {sa - featureFlowCross - featurePermissionedDEX, - sa - featurePermissionedDEX, - sa}) + auto const sa = testable_amendments(); + for (auto feature : {sa - featurePermissionedDEX, sa}) { testGWB(feature); testGWBApiVersions(feature); @@ -265,7 +262,7 @@ class GatewayBalances_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(GatewayBalances, app, ripple); +BEAST_DEFINE_TESTSUITE(GatewayBalances, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/GetAggregatePrice_test.cpp b/src/test/rpc/GetAggregatePrice_test.cpp index 4e9b9506904..9d007f7f521 100644 --- a/src/test/rpc/GetAggregatePrice_test.cpp +++ b/src/test/rpc/GetAggregatePrice_test.cpp @@ -346,7 +346,7 @@ class GetAggregatePrice_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(GetAggregatePrice, app, ripple); +BEAST_DEFINE_TESTSUITE(GetAggregatePrice, rpc, ripple); } // namespace oracle } // namespace jtx diff --git a/src/test/rpc/Handler_test.cpp b/src/test/rpc/Handler_test.cpp index 8eb0c8d01db..c58d29252be 100644 --- a/src/test/rpc/Handler_test.cpp +++ b/src/test/rpc/Handler_test.cpp @@ -128,6 +128,6 @@ class Handler_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL(Handler, test, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(Handler, rpc, ripple); } // namespace ripple::test diff --git a/src/test/rpc/JSONRPC_test.cpp b/src/test/rpc/JSONRPC_test.cpp index 1612d1b455e..31bdacfb9cb 100644 --- a/src/test/rpc/JSONRPC_test.cpp +++ b/src/test/rpc/JSONRPC_test.cpp @@ -2936,7 +2936,7 @@ class JSONRPC_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(JSONRPC, ripple_app, ripple); +BEAST_DEFINE_TESTSUITE(JSONRPC, rpc, ripple); } // namespace RPC } // namespace ripple diff --git a/src/test/rpc/KeyGeneration_test.cpp b/src/test/rpc/KeyGeneration_test.cpp index 07ebd93dd36..3ea6a07e948 100644 --- a/src/test/rpc/KeyGeneration_test.cpp +++ b/src/test/rpc/KeyGeneration_test.cpp @@ -894,7 +894,7 @@ class WalletPropose_test : public ripple::TestSuite } }; -BEAST_DEFINE_TESTSUITE(WalletPropose, ripple_basics, ripple); +BEAST_DEFINE_TESTSUITE(WalletPropose, rpc, ripple); } // namespace RPC } // namespace ripple diff --git a/src/test/rpc/LedgerClosed_test.cpp b/src/test/rpc/LedgerClosed_test.cpp index fc7b3a7dac2..37d6b1e3930 100644 --- a/src/test/rpc/LedgerClosed_test.cpp +++ b/src/test/rpc/LedgerClosed_test.cpp @@ -68,6 +68,6 @@ class LedgerClosed_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(LedgerClosed, app, ripple); +BEAST_DEFINE_TESTSUITE(LedgerClosed, rpc, ripple); } // namespace ripple diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index c2b22efc00a..d57b33013a2 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -304,8 +304,8 @@ class LedgerData_test : public beast::unit_test::suite // Make sure fixInnerObjTemplate2 doesn't break amendments. for (FeatureBitset const& features : - {supported_amendments() - fixInnerObjTemplate2, - supported_amendments() | fixInnerObjTemplate2}) + {testable_amendments() - fixInnerObjTemplate2, + testable_amendments() | fixInnerObjTemplate2}) { using namespace std::chrono; Env env{*this, envconfig(validator, ""), features}; @@ -523,6 +523,6 @@ class LedgerData_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(LedgerData, app, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(LedgerData, rpc, ripple, 1); } // namespace ripple diff --git a/src/test/rpc/LedgerEntry_test.cpp b/src/test/rpc/LedgerEntry_test.cpp index 83232f79c8a..89cb7b72eb4 100644 --- a/src/test/rpc/LedgerEntry_test.cpp +++ b/src/test/rpc/LedgerEntry_test.cpp @@ -2221,7 +2221,7 @@ class LedgerEntry_test : public beast::unit_test::suite using namespace test::jtx; - Env env(*this, supported_amendments() | featurePermissionedDomains); + Env env(*this, testable_amendments() | featurePermissionedDomains); Account const issuer{"issuer"}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -2711,8 +2711,8 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, } }; -BEAST_DEFINE_TESTSUITE(LedgerEntry, app, ripple); -BEAST_DEFINE_TESTSUITE(LedgerEntry_XChain, app, ripple); +BEAST_DEFINE_TESTSUITE(LedgerEntry, rpc, ripple); +BEAST_DEFINE_TESTSUITE(LedgerEntry_XChain, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 5b26f431619..9309fbdd6c9 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -711,6 +711,7 @@ class LedgerRPC_test : public beast::unit_test::suite env.close(); std::string index; + int hashesLedgerEntryIndex = -1; { Json::Value jvParams; jvParams[jss::ledger_index] = 3u; @@ -721,11 +722,27 @@ class LedgerRPC_test : public beast::unit_test::suite env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState)); BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray()); - BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u); + + for (auto i = 0; i < jrr[jss::ledger][jss::accountState].size(); + i++) + if (jrr[jss::ledger][jss::accountState][i]["LedgerEntryType"] == + jss::LedgerHashes) + { + index = jrr[jss::ledger][jss::accountState][i]["index"] + .asString(); + hashesLedgerEntryIndex = i; + } + + for (auto const& object : jrr[jss::ledger][jss::accountState]) + if (object["LedgerEntryType"] == jss::LedgerHashes) + index = object["index"].asString(); + + // jss::type is a deprecated field BEAST_EXPECT( - jrr[jss::ledger][jss::accountState][0u]["LedgerEntryType"] == - jss::LedgerHashes); - index = jrr[jss::ledger][jss::accountState][0u]["index"].asString(); + jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() && + jrr[jss::warnings].size() == 1 && + jrr[jss::warnings][0u][jss::id].asInt() == + warnRPC_FIELDS_DEPRECATED); } { Json::Value jvParams; @@ -737,8 +754,17 @@ class LedgerRPC_test : public beast::unit_test::suite env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState)); BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray()); - BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u); - BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index); + BEAST_EXPECT( + hashesLedgerEntryIndex > 0 && + jrr[jss::ledger][jss::accountState][hashesLedgerEntryIndex] == + index); + + // jss::type is a deprecated field + BEAST_EXPECT( + jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() && + jrr[jss::warnings].size() == 1 && + jrr[jss::warnings][0u][jss::id].asInt() == + warnRPC_FIELDS_DEPRECATED); } } @@ -759,7 +785,7 @@ class LedgerRPC_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(LedgerRPC, app, ripple); +BEAST_DEFINE_TESTSUITE(LedgerRPC, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/LedgerRequestRPC_test.cpp b/src/test/rpc/LedgerRequestRPC_test.cpp index b34233991e3..03be9fb29be 100644 --- a/src/test/rpc/LedgerRequestRPC_test.cpp +++ b/src/test/rpc/LedgerRequestRPC_test.cpp @@ -376,7 +376,7 @@ class LedgerRequestRPC_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(LedgerRequestRPC, app, ripple); +BEAST_DEFINE_TESTSUITE(LedgerRequestRPC, rpc, ripple); } // namespace RPC } // namespace ripple diff --git a/src/test/rpc/NoRipple_test.cpp b/src/test/rpc/NoRipple_test.cpp index 42c86b34bb3..93457ada8cd 100644 --- a/src/test/rpc/NoRipple_test.cpp +++ b/src/test/rpc/NoRipple_test.cpp @@ -293,14 +293,13 @@ class NoRipple_test : public beast::unit_test::suite testPairwise(features); }; using namespace jtx; - auto const sa = supported_amendments(); - withFeatsTests(sa - featureFlowCross - featurePermissionedDEX); + auto const sa = testable_amendments(); withFeatsTests(sa - featurePermissionedDEX); withFeatsTests(sa); } }; -BEAST_DEFINE_TESTSUITE(NoRipple, app, ripple); +BEAST_DEFINE_TESTSUITE(NoRipple, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/OwnerInfo_test.cpp b/src/test/rpc/OwnerInfo_test.cpp index 15bbad42e34..0c517058ca3 100644 --- a/src/test/rpc/OwnerInfo_test.cpp +++ b/src/test/rpc/OwnerInfo_test.cpp @@ -219,6 +219,6 @@ class OwnerInfo_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(OwnerInfo, app, ripple); +BEAST_DEFINE_TESTSUITE(OwnerInfo, rpc, ripple); } // namespace ripple diff --git a/src/test/rpc/RPCCall_test.cpp b/src/test/rpc/RPCCall_test.cpp index be0f32b5ce2..b73f2e11a04 100644 --- a/src/test/rpc/RPCCall_test.cpp +++ b/src/test/rpc/RPCCall_test.cpp @@ -5948,7 +5948,7 @@ class RPCCall_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(RPCCall, app, ripple); +BEAST_DEFINE_TESTSUITE(RPCCall, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/RPCHelpers_test.cpp b/src/test/rpc/RPCHelpers_test.cpp index 531649b8afe..1716301dae7 100644 --- a/src/test/rpc/RPCHelpers_test.cpp +++ b/src/test/rpc/RPCHelpers_test.cpp @@ -87,7 +87,7 @@ class RPCHelpers_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(RPCHelpers, app, ripple); +BEAST_DEFINE_TESTSUITE(RPCHelpers, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/RPCOverload_test.cpp b/src/test/rpc/RPCOverload_test.cpp index efe69496fbf..35755eff207 100644 --- a/src/test/rpc/RPCOverload_test.cpp +++ b/src/test/rpc/RPCOverload_test.cpp @@ -87,7 +87,7 @@ class RPCOverload_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(RPCOverload, app, ripple); +BEAST_DEFINE_TESTSUITE(RPCOverload, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/RobustTransaction_test.cpp b/src/test/rpc/RobustTransaction_test.cpp index aa53bd6e0a9..bfd9e6251b7 100644 --- a/src/test/rpc/RobustTransaction_test.cpp +++ b/src/test/rpc/RobustTransaction_test.cpp @@ -510,7 +510,7 @@ class RobustTransaction_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(RobustTransaction, app, ripple); +BEAST_DEFINE_TESTSUITE(RobustTransaction, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/Roles_test.cpp b/src/test/rpc/Roles_test.cpp index 5ac86543304..949d84c1e56 100644 --- a/src/test/rpc/Roles_test.cpp +++ b/src/test/rpc/Roles_test.cpp @@ -389,7 +389,7 @@ class Roles_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Roles, app, ripple); +BEAST_DEFINE_TESTSUITE(Roles, rpc, ripple); } // namespace test diff --git a/src/test/rpc/ServerInfo_test.cpp b/src/test/rpc/ServerInfo_test.cpp index 21312ef8fff..b5780635cde 100644 --- a/src/test/rpc/ServerInfo_test.cpp +++ b/src/test/rpc/ServerInfo_test.cpp @@ -308,7 +308,7 @@ admin = 127.0.0.1 } }; -BEAST_DEFINE_TESTSUITE(ServerInfo, app, ripple); +BEAST_DEFINE_TESTSUITE(ServerInfo, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/Status_test.cpp b/src/test/rpc/Status_test.cpp index e37fe2dabde..884e684fb31 100644 --- a/src/test/rpc/Status_test.cpp +++ b/src/test/rpc/Status_test.cpp @@ -94,7 +94,7 @@ class codeString_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(codeString, Status, RPC); +BEAST_DEFINE_TESTSUITE(codeString, rpc, RPC); class fillJson_test : public beast::unit_test::suite { @@ -218,7 +218,7 @@ class fillJson_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(fillJson, Status, RPC); +BEAST_DEFINE_TESTSUITE(fillJson, rpc, RPC); } // namespace RPC } // namespace ripple diff --git a/src/test/rpc/Subscribe_test.cpp b/src/test/rpc/Subscribe_test.cpp index 32296c5d0a2..9ed02fa532b 100644 --- a/src/test/rpc/Subscribe_test.cpp +++ b/src/test/rpc/Subscribe_test.cpp @@ -131,6 +131,9 @@ class Subscribe_test : public beast::unit_test::suite BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 2); + BEAST_EXPECT( + jv[jss::result][jss::network_id] == + env.app().config().NETWORK_ID); } { @@ -139,7 +142,8 @@ class Subscribe_test : public beast::unit_test::suite // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::ledger_index] == 3; + return jv[jss::ledger_index] == 3 && + jv[jss::network_id] == env.app().config().NETWORK_ID; })); } @@ -149,7 +153,8 @@ class Subscribe_test : public beast::unit_test::suite // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::ledger_index] == 4; + return jv[jss::ledger_index] == 4 && + jv[jss::network_id] == env.app().config().NETWORK_ID; })); } @@ -509,6 +514,11 @@ class Subscribe_test : public beast::unit_test::suite if (!jv.isMember(jss::validated_hash)) return false; + uint32_t netID = env.app().config().NETWORK_ID; + if (!jv.isMember(jss::network_id) || + jv[jss::network_id] != netID) + return false; + // Certain fields are only added on a flag ledger. bool const isFlagLedger = (env.closed()->info().seq + 1) % 256 == 0; @@ -567,6 +577,7 @@ class Subscribe_test : public beast::unit_test::suite jv[jss::streams][0u] = "ledger"; jr = env.rpc("json", "subscribe", to_string(jv))[jss::result]; BEAST_EXPECT(jr[jss::status] == "success"); + BEAST_EXPECT(jr[jss::network_id] == env.app().config().NETWORK_ID); jr = env.rpc("json", "unsubscribe", to_string(jv))[jss::result]; BEAST_EXPECT(jr[jss::status] == "success"); @@ -1307,7 +1318,7 @@ class Subscribe_test : public beast::unit_test::suite using namespace jtx; using namespace std::chrono_literals; FeatureBitset const all{ - jtx::supported_amendments() | featurePermissionedDomains | + jtx::testable_amendments() | featurePermissionedDomains | featureCredentials | featurePermissionedDEX}; Env env(*this, all); @@ -1354,11 +1365,230 @@ class Subscribe_test : public beast::unit_test::suite })); } + void + testNFToken(FeatureBitset features) + { + // `nftoken_id` is added for `transaction` stream in the `subscribe` + // response for NFTokenMint and NFTokenAcceptOffer. + // + // `nftoken_ids` is added for `transaction` stream in the `subscribe` + // response for NFTokenCancelOffer + // + // `offer_id` is added for `transaction` stream in the `subscribe` + // response for NFTokenCreateOffer + // + // The values of these fields are dependent on the NFTokenID/OfferID + // changed in its corresponding transaction. We want to validate each + // response to make sure the synethic fields hold the right values. + + testcase("Test synthetic fields from Subscribe response"); + + using namespace test::jtx; + using namespace std::chrono_literals; + + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const broker{"broker"}; + + Env env{*this, features}; + env.fund(XRP(10000), alice, bob, broker); + env.close(); + + auto wsc = test::makeWSClient(env.app().config()); + Json::Value stream; + stream[jss::streams] = Json::arrayValue; + stream[jss::streams].append("transactions"); + auto jv = wsc->invoke("subscribe", stream); + + // Verify `nftoken_id` value equals to the NFTokenID that was + // changed in the most recent NFTokenMint or NFTokenAcceptOffer + // transaction + auto verifyNFTokenID = [&](uint256 const& actualNftID) { + BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { + uint256 nftID; + BEAST_EXPECT( + nftID.parseHex(jv[jss::meta][jss::nftoken_id].asString())); + return nftID == actualNftID; + })); + }; + + // Verify `nftoken_ids` value equals to the NFTokenIDs that were + // changed in the most recent NFTokenCancelOffer transaction + auto verifyNFTokenIDsInCancelOffer = + [&](std::vector actualNftIDs) { + BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { + std::vector metaIDs; + std::transform( + jv[jss::meta][jss::nftoken_ids].begin(), + jv[jss::meta][jss::nftoken_ids].end(), + std::back_inserter(metaIDs), + [this](Json::Value id) { + uint256 nftID; + BEAST_EXPECT(nftID.parseHex(id.asString())); + return nftID; + }); + // Sort both array to prepare for comparison + std::sort(metaIDs.begin(), metaIDs.end()); + std::sort(actualNftIDs.begin(), actualNftIDs.end()); + + // Make sure the expect number of NFTs is correct + BEAST_EXPECT(metaIDs.size() == actualNftIDs.size()); + + // Check the value of NFT ID in the meta with the + // actual values + for (size_t i = 0; i < metaIDs.size(); ++i) + BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]); + return true; + })); + }; + + // Verify `offer_id` value equals to the offerID that was + // changed in the most recent NFTokenCreateOffer tx + auto verifyNFTokenOfferID = [&](uint256 const& offerID) { + BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { + uint256 metaOfferID; + BEAST_EXPECT(metaOfferID.parseHex( + jv[jss::meta][jss::offer_id].asString())); + return metaOfferID == offerID; + })); + }; + + // Check new fields in tx meta when for all NFTtransactions + { + // Alice mints 2 NFTs + // Verify the NFTokenIDs are correct in the NFTokenMint tx meta + uint256 const nftId1{ + token::getNextID(env, alice, 0u, tfTransferable)}; + env(token::mint(alice, 0u), txflags(tfTransferable)); + env.close(); + verifyNFTokenID(nftId1); + + uint256 const nftId2{ + token::getNextID(env, alice, 0u, tfTransferable)}; + env(token::mint(alice, 0u), txflags(tfTransferable)); + env.close(); + verifyNFTokenID(nftId2); + + // Alice creates one sell offer for each NFT + // Verify the offer indexes are correct in the NFTokenCreateOffer tx + // meta + uint256 const aliceOfferIndex1 = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId1, drops(1)), + txflags(tfSellNFToken)); + env.close(); + verifyNFTokenOfferID(aliceOfferIndex1); + + uint256 const aliceOfferIndex2 = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId2, drops(1)), + txflags(tfSellNFToken)); + env.close(); + verifyNFTokenOfferID(aliceOfferIndex2); + + // Alice cancels two offers she created + // Verify the NFTokenIDs are correct in the NFTokenCancelOffer tx + // meta + env(token::cancelOffer( + alice, {aliceOfferIndex1, aliceOfferIndex2})); + env.close(); + verifyNFTokenIDsInCancelOffer({nftId1, nftId2}); + + // Bobs creates a buy offer for nftId1 + // Verify the offer id is correct in the NFTokenCreateOffer tx meta + auto const bobBuyOfferIndex = + keylet::nftoffer(bob, env.seq(bob)).key; + env(token::createOffer(bob, nftId1, drops(1)), token::owner(alice)); + env.close(); + verifyNFTokenOfferID(bobBuyOfferIndex); + + // Alice accepts bob's buy offer + // Verify the NFTokenID is correct in the NFTokenAcceptOffer tx meta + env(token::acceptBuyOffer(alice, bobBuyOfferIndex)); + env.close(); + verifyNFTokenID(nftId1); + } + + // Check `nftoken_ids` in brokered mode + { + // Alice mints a NFT + uint256 const nftId{ + token::getNextID(env, alice, 0u, tfTransferable)}; + env(token::mint(alice, 0u), txflags(tfTransferable)); + env.close(); + verifyNFTokenID(nftId); + + // Alice creates sell offer and set broker as destination + uint256 const offerAliceToBroker = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), + token::destination(broker), + txflags(tfSellNFToken)); + env.close(); + verifyNFTokenOfferID(offerAliceToBroker); + + // Bob creates buy offer + uint256 const offerBobToBroker = + keylet::nftoffer(bob, env.seq(bob)).key; + env(token::createOffer(bob, nftId, drops(1)), token::owner(alice)); + env.close(); + verifyNFTokenOfferID(offerBobToBroker); + + // Check NFTokenID meta for NFTokenAcceptOffer in brokered mode + env(token::brokerOffers( + broker, offerBobToBroker, offerAliceToBroker)); + env.close(); + verifyNFTokenID(nftId); + } + + // Check if there are no duplicate nft id in Cancel transactions where + // multiple offers are cancelled for the same NFT + { + // Alice mints a NFT + uint256 const nftId{ + token::getNextID(env, alice, 0u, tfTransferable)}; + env(token::mint(alice, 0u), txflags(tfTransferable)); + env.close(); + verifyNFTokenID(nftId); + + // Alice creates 2 sell offers for the same NFT + uint256 const aliceOfferIndex1 = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), + txflags(tfSellNFToken)); + env.close(); + verifyNFTokenOfferID(aliceOfferIndex1); + + uint256 const aliceOfferIndex2 = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), + txflags(tfSellNFToken)); + env.close(); + verifyNFTokenOfferID(aliceOfferIndex2); + + // Make sure the metadata only has 1 nft id, since both offers are + // for the same nft + env(token::cancelOffer( + alice, {aliceOfferIndex1, aliceOfferIndex2})); + env.close(); + verifyNFTokenIDsInCancelOffer({nftId}); + } + + if (features[featureNFTokenMintOffer]) + { + uint256 const aliceMintWithOfferIndex1 = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::mint(alice), token::amount(XRP(0))); + env.close(); + verifyNFTokenOfferID(aliceMintWithOfferIndex1); + } + } + void run() override { using namespace test::jtx; - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; FeatureBitset const xrpFees{featureXRPFees}; testServer(); @@ -1373,10 +1603,12 @@ class Subscribe_test : public beast::unit_test::suite testSubByUrl(); testHistoryTxStream(); testSubBookChanges(); + testNFToken(all); + testNFToken(all - featureNFTokenMintOffer); } }; -BEAST_DEFINE_TESTSUITE(Subscribe, app, ripple); +BEAST_DEFINE_TESTSUITE(Subscribe, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/rpc/Transaction_test.cpp b/src/test/rpc/Transaction_test.cpp index 724a3a05175..e1db4855723 100644 --- a/src/test/rpc/Transaction_test.cpp +++ b/src/test/rpc/Transaction_test.cpp @@ -941,7 +941,7 @@ class Transaction_test : public beast::unit_test::suite forAllApiVersions( std::bind_front(&Transaction_test::testBinaryRequest, this)); - FeatureBitset const all{supported_amendments()}; + FeatureBitset const all{testable_amendments()}; testWithFeats(all); } diff --git a/src/test/rpc/ValidatorRPC_test.cpp b/src/test/rpc/ValidatorRPC_test.cpp index d03cbbf8410..d139a662de3 100644 --- a/src/test/rpc/ValidatorRPC_test.cpp +++ b/src/test/rpc/ValidatorRPC_test.cpp @@ -594,7 +594,7 @@ class ValidatorRPC_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(ValidatorRPC, app, ripple); +BEAST_DEFINE_TESTSUITE(ValidatorRPC, rpc, ripple); } // namespace test } // namespace ripple diff --git a/src/test/server/ServerStatus_test.cpp b/src/test/server/ServerStatus_test.cpp index bcd355e301d..b27dee6e0a0 100644 --- a/src/test/server/ServerStatus_test.cpp +++ b/src/test/server/ServerStatus_test.cpp @@ -681,7 +681,7 @@ class ServerStatus_test : public beast::unit_test::suite, resp["Upgrade"] == "websocket"); BEAST_EXPECT( resp.find("Connection") != resp.end() && - resp["Connection"] == "upgrade"); + resp["Connection"] == "Upgrade"); } void diff --git a/src/test/server/Server_test.cpp b/src/test/server/Server_test.cpp index f8895ae7e9b..fab271ff1c0 100644 --- a/src/test/server/Server_test.cpp +++ b/src/test/server/Server_test.cpp @@ -533,7 +533,7 @@ class Server_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Server, http, ripple); +BEAST_DEFINE_TESTSUITE(Server, server, ripple); } // namespace test } // namespace ripple diff --git a/src/test/shamap/SHAMap_test.cpp b/src/test/shamap/SHAMap_test.cpp index 3197e0944d3..1a15310b583 100644 --- a/src/test/shamap/SHAMap_test.cpp +++ b/src/test/shamap/SHAMap_test.cpp @@ -402,7 +402,7 @@ class SHAMapPathProof_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(SHAMap, ripple_app, ripple); -BEAST_DEFINE_TESTSUITE(SHAMapPathProof, ripple_app, ripple); +BEAST_DEFINE_TESTSUITE(SHAMap, shamap, ripple); +BEAST_DEFINE_TESTSUITE(SHAMapPathProof, shamap, ripple); } // namespace tests } // namespace ripple diff --git a/src/test/unit_test/FileDirGuard.h b/src/test/unit_test/FileDirGuard.h index d247ae30157..091bc80d20f 100644 --- a/src/test/unit_test/FileDirGuard.h +++ b/src/test/unit_test/FileDirGuard.h @@ -26,6 +26,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include +#include + namespace ripple { namespace test { namespace detail { diff --git a/src/test/unit_test/SuiteJournal.h b/src/test/unit_test/SuiteJournal.h index b5c59f3d29e..d56c297b0a2 100644 --- a/src/test/unit_test/SuiteJournal.h +++ b/src/test/unit_test/SuiteJournal.h @@ -94,6 +94,8 @@ SuiteJournalSink::writeAlways( return "FTL:"; }(); + static std::mutex log_mutex; + std::lock_guard lock(log_mutex); suite_.log << s << partition_ << text << std::endl; } diff --git a/src/tests/README.md b/src/tests/README.md new file mode 100644 index 00000000000..7c4cc5edf85 --- /dev/null +++ b/src/tests/README.md @@ -0,0 +1,5 @@ +# Unit tests + +This directory contains unit tests for the project. The difference from existing `src/test` folder +is that we switch to 3rd party testing framework (doctest). We intend to gradually move existing tests +from our own framework to doctest and such tests will be moved to this new folder. diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt new file mode 100644 index 00000000000..68c6fa6cb30 --- /dev/null +++ b/src/tests/libxrpl/CMakeLists.txt @@ -0,0 +1,14 @@ +include(xrpl_add_test) + +# Test requirements. +find_package(doctest REQUIRED) + +# Common library dependencies for the rest of the tests. +add_library(xrpl.imports.test INTERFACE) +target_link_libraries(xrpl.imports.test INTERFACE doctest::doctest xrpl.libxrpl) + +# One test for each module. +xrpl_add_test(basics) +target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test) +xrpl_add_test(crypto) +target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test) diff --git a/src/tests/libxrpl/basics/RangeSet.cpp b/src/tests/libxrpl/basics/RangeSet.cpp new file mode 100644 index 00000000000..ac0e1d9551b --- /dev/null +++ b/src/tests/libxrpl/basics/RangeSet.cpp @@ -0,0 +1,129 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +#include + +#include +#include + +using namespace ripple; + +TEST_SUITE_BEGIN("RangeSet"); + +TEST_CASE("prevMissing") +{ + // Set will include: + // [ 0, 5] + // [10,15] + // [20,25] + // etc... + + RangeSet set; + for (std::uint32_t i = 0; i < 10; ++i) + set.insert(range(10 * i, 10 * i + 5)); + + for (std::uint32_t i = 1; i < 100; ++i) + { + std::optional expected; + // no prev missing in domain for i <= 6 + if (i > 6) + { + std::uint32_t const oneBelowRange = (10 * (i / 10)) - 1; + + expected = ((i % 10) > 6) ? (i - 1) : oneBelowRange; + } + CHECK(prevMissing(set, i) == expected); + } +} + +TEST_CASE("toString") +{ + RangeSet set; + CHECK(to_string(set) == "empty"); + + set.insert(1); + CHECK(to_string(set) == "1"); + + set.insert(range(4u, 6u)); + CHECK(to_string(set) == "1,4-6"); + + set.insert(2); + CHECK(to_string(set) == "1-2,4-6"); + + set.erase(range(4u, 5u)); + CHECK(to_string(set) == "1-2,6"); +} + +TEST_CASE("fromString") +{ + RangeSet set; + + CHECK(!from_string(set, "")); + CHECK(boost::icl::length(set) == 0); + + CHECK(!from_string(set, "#")); + CHECK(boost::icl::length(set) == 0); + + CHECK(!from_string(set, ",")); + CHECK(boost::icl::length(set) == 0); + + CHECK(!from_string(set, ",-")); + CHECK(boost::icl::length(set) == 0); + + CHECK(!from_string(set, "1,,2")); + CHECK(boost::icl::length(set) == 0); + + CHECK(from_string(set, "1")); + CHECK(boost::icl::length(set) == 1); + CHECK(boost::icl::first(set) == 1); + + CHECK(from_string(set, "1,1")); + CHECK(boost::icl::length(set) == 1); + CHECK(boost::icl::first(set) == 1); + + CHECK(from_string(set, "1-1")); + CHECK(boost::icl::length(set) == 1); + CHECK(boost::icl::first(set) == 1); + + CHECK(from_string(set, "1,4-6")); + CHECK(boost::icl::length(set) == 4); + CHECK(boost::icl::first(set) == 1); + CHECK(!boost::icl::contains(set, 2)); + CHECK(!boost::icl::contains(set, 3)); + CHECK(boost::icl::contains(set, 4)); + CHECK(boost::icl::contains(set, 5)); + CHECK(boost::icl::last(set) == 6); + + CHECK(from_string(set, "1-2,4-6")); + CHECK(boost::icl::length(set) == 5); + CHECK(boost::icl::first(set) == 1); + CHECK(boost::icl::contains(set, 2)); + CHECK(boost::icl::contains(set, 4)); + CHECK(boost::icl::last(set) == 6); + + CHECK(from_string(set, "1-2,6")); + CHECK(boost::icl::length(set) == 3); + CHECK(boost::icl::first(set) == 1); + CHECK(boost::icl::contains(set, 2)); + CHECK(boost::icl::last(set) == 6); +} + +TEST_SUITE_END(); diff --git a/src/tests/libxrpl/basics/Slice.cpp b/src/tests/libxrpl/basics/Slice.cpp new file mode 100644 index 00000000000..eabd9b7dc78 --- /dev/null +++ b/src/tests/libxrpl/basics/Slice.cpp @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +#include + +#include +#include + +using namespace ripple; + +static std::uint8_t const data[] = { + 0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a, + 0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c, + 0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3}; + +TEST_SUITE_BEGIN("Slice"); + +TEST_CASE("equality & inequality") +{ + Slice const s0{}; + + CHECK(s0.size() == 0); + CHECK(s0.data() == nullptr); + CHECK(s0 == s0); + + // Test slices of equal and unequal size pointing to same data: + for (std::size_t i = 0; i != sizeof(data); ++i) + { + Slice const s1{data, i}; + + CHECK(s1.size() == i); + CHECK(s1.data() != nullptr); + + if (i == 0) + CHECK(s1 == s0); + else + CHECK(s1 != s0); + + for (std::size_t j = 0; j != sizeof(data); ++j) + { + Slice const s2{data, j}; + + if (i == j) + CHECK(s1 == s2); + else + CHECK(s1 != s2); + } + } + + // Test slices of equal size but pointing to different data: + std::array a; + std::array b; + + for (std::size_t i = 0; i != sizeof(data); ++i) + a[i] = b[i] = data[i]; + + CHECK(makeSlice(a) == makeSlice(b)); + b[7]++; + CHECK(makeSlice(a) != makeSlice(b)); + a[7]++; + CHECK(makeSlice(a) == makeSlice(b)); +} + +TEST_CASE("indexing") +{ + Slice const s{data, sizeof(data)}; + + for (std::size_t i = 0; i != sizeof(data); ++i) + CHECK(s[i] == data[i]); +} + +TEST_CASE("advancing") +{ + for (std::size_t i = 0; i < sizeof(data); ++i) + { + for (std::size_t j = 0; i + j < sizeof(data); ++j) + { + Slice s(data + i, sizeof(data) - i); + s += j; + + CHECK(s.data() == data + i + j); + CHECK(s.size() == sizeof(data) - i - j); + } + } +} + +TEST_SUITE_END(); diff --git a/src/tests/libxrpl/basics/base64.cpp b/src/tests/libxrpl/basics/base64.cpp new file mode 100644 index 00000000000..fe9b86abb10 --- /dev/null +++ b/src/tests/libxrpl/basics/base64.cpp @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +#include + +#include + +using namespace ripple; + +static void +check(std::string const& in, std::string const& out) +{ + auto const encoded = base64_encode(in); + CHECK(encoded == out); + CHECK(base64_decode(encoded) == in); +} + +TEST_CASE("base64") +{ + check("", ""); + check("f", "Zg=="); + check("fo", "Zm8="); + check("foo", "Zm9v"); + check("foob", "Zm9vYg=="); + check("fooba", "Zm9vYmE="); + check("foobar", "Zm9vYmFy"); + + check( + "Man is distinguished, not only by his reason, but by this " + "singular passion from " + "other animals, which is a lust of the mind, that by a " + "perseverance of delight " + "in the continued and indefatigable generation of knowledge, " + "exceeds the short " + "vehemence of any carnal pleasure.", + "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dC" + "BieSB0aGlz" + "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIG" + "x1c3Qgb2Yg" + "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aG" + "UgY29udGlu" + "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleG" + "NlZWRzIHRo" + "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="); + + std::string const notBase64 = "not_base64!!"; + std::string const truncated = "not"; + CHECK(base64_decode(notBase64) == base64_decode(truncated)); +} diff --git a/src/test/basics/contract_test.cpp b/src/tests/libxrpl/basics/contract.cpp similarity index 60% rename from src/test/basics/contract_test.cpp rename to src/tests/libxrpl/basics/contract.cpp index 9595dbabcce..9ddf044f171 100644 --- a/src/test/basics/contract_test.cpp +++ b/src/tests/libxrpl/basics/contract.cpp @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. + Copyright (c) 2012 Ripple Labs Inc. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -18,46 +18,39 @@ //============================================================================== #include -#include +#include + +#include #include -namespace ripple { +using namespace ripple; -class contract_test : public beast::unit_test::suite +TEST_CASE("contract") { -public: - void - run() override + try + { + Throw("Throw test"); + } + catch (std::runtime_error const& e1) { + CHECK(std::string(e1.what()) == "Throw test"); + try { - Throw("Throw test"); + Rethrow(); } - catch (std::runtime_error const& e1) + catch (std::runtime_error const& e2) { - BEAST_EXPECT(std::string(e1.what()) == "Throw test"); - - try - { - Rethrow(); - } - catch (std::runtime_error const& e2) - { - BEAST_EXPECT(std::string(e2.what()) == "Throw test"); - } - catch (...) - { - BEAST_EXPECT(false); - } + CHECK(std::string(e2.what()) == "Throw test"); } catch (...) { - BEAST_EXPECT(false); + CHECK(false); } } -}; - -BEAST_DEFINE_TESTSUITE(contract, basics, ripple); - -} // namespace ripple + catch (...) + { + CHECK(false); + } +} diff --git a/src/tests/libxrpl/basics/main.cpp b/src/tests/libxrpl/basics/main.cpp new file mode 100644 index 00000000000..0a3f254ea87 --- /dev/null +++ b/src/tests/libxrpl/basics/main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include diff --git a/src/tests/libxrpl/basics/mulDiv.cpp b/src/tests/libxrpl/basics/mulDiv.cpp new file mode 100644 index 00000000000..bdbbfdc7415 --- /dev/null +++ b/src/tests/libxrpl/basics/mulDiv.cpp @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +#include + +#include +#include + +using namespace ripple; + +TEST_CASE("mulDiv") +{ + auto const max = std::numeric_limits::max(); + std::uint64_t const max32 = std::numeric_limits::max(); + + auto result = mulDiv(85, 20, 5); + REQUIRE(result); + CHECK(*result == 340); + result = mulDiv(20, 85, 5); + REQUIRE(result); + CHECK(*result == 340); + + result = mulDiv(0, max - 1, max - 3); + REQUIRE(result); + CHECK(*result == 0); + result = mulDiv(max - 1, 0, max - 3); + REQUIRE(result); + CHECK(*result == 0); + + result = mulDiv(max, 2, max / 2); + REQUIRE(result); + CHECK(*result == 4); + result = mulDiv(max, 1000, max / 1000); + REQUIRE(result); + CHECK(*result == 1000000); + result = mulDiv(max, 1000, max / 1001); + REQUIRE(result); + CHECK(*result == 1001000); + result = mulDiv(max32 + 1, max32 + 1, 5); + REQUIRE(result); + CHECK(*result == 3689348814741910323); + + // Overflow + result = mulDiv(max - 1, max - 2, 5); + CHECK(!result); +} diff --git a/src/tests/libxrpl/basics/scope.cpp b/src/tests/libxrpl/basics/scope.cpp new file mode 100644 index 00000000000..c9cfc1e7f85 --- /dev/null +++ b/src/tests/libxrpl/basics/scope.cpp @@ -0,0 +1,174 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2021 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +#include + +using namespace ripple; + +TEST_CASE("scope_exit") +{ + // scope_exit always executes the functor on destruction, + // unless release() is called + int i = 0; + { + scope_exit x{[&i]() { i = 1; }}; + } + CHECK(i == 1); + { + scope_exit x{[&i]() { i = 2; }}; + x.release(); + } + CHECK(i == 1); + { + scope_exit x{[&i]() { i += 2; }}; + auto x2 = std::move(x); + } + CHECK(i == 3); + { + scope_exit x{[&i]() { i = 4; }}; + x.release(); + auto x2 = std::move(x); + } + CHECK(i == 3); + { + try + { + scope_exit x{[&i]() { i = 5; }}; + throw 1; + } + catch (...) + { + } + } + CHECK(i == 5); + { + try + { + scope_exit x{[&i]() { i = 6; }}; + x.release(); + throw 1; + } + catch (...) + { + } + } + CHECK(i == 5); +} + +TEST_CASE("scope_fail") +{ + // scope_fail executes the functor on destruction only + // if an exception is unwinding, unless release() is called + int i = 0; + { + scope_fail x{[&i]() { i = 1; }}; + } + CHECK(i == 0); + { + scope_fail x{[&i]() { i = 2; }}; + x.release(); + } + CHECK(i == 0); + { + scope_fail x{[&i]() { i = 3; }}; + auto x2 = std::move(x); + } + CHECK(i == 0); + { + scope_fail x{[&i]() { i = 4; }}; + x.release(); + auto x2 = std::move(x); + } + CHECK(i == 0); + { + try + { + scope_fail x{[&i]() { i = 5; }}; + throw 1; + } + catch (...) + { + } + } + CHECK(i == 5); + { + try + { + scope_fail x{[&i]() { i = 6; }}; + x.release(); + throw 1; + } + catch (...) + { + } + } + CHECK(i == 5); +} + +TEST_CASE("scope_success") +{ + // scope_success executes the functor on destruction only + // if an exception is not unwinding, unless release() is called + int i = 0; + { + scope_success x{[&i]() { i = 1; }}; + } + CHECK(i == 1); + { + scope_success x{[&i]() { i = 2; }}; + x.release(); + } + CHECK(i == 1); + { + scope_success x{[&i]() { i += 2; }}; + auto x2 = std::move(x); + } + CHECK(i == 3); + { + scope_success x{[&i]() { i = 4; }}; + x.release(); + auto x2 = std::move(x); + } + CHECK(i == 3); + { + try + { + scope_success x{[&i]() { i = 5; }}; + throw 1; + } + catch (...) + { + } + } + CHECK(i == 3); + { + try + { + scope_success x{[&i]() { i = 6; }}; + x.release(); + throw 1; + } + catch (...) + { + } + } + CHECK(i == 3); +} diff --git a/src/tests/libxrpl/basics/tagged_integer.cpp b/src/tests/libxrpl/basics/tagged_integer.cpp new file mode 100644 index 00000000000..d699b64a702 --- /dev/null +++ b/src/tests/libxrpl/basics/tagged_integer.cpp @@ -0,0 +1,247 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2014 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +#include + +#include + +using namespace ripple; + +struct Tag1 +{ +}; +struct Tag2 +{ +}; + +// Static checks that types are not interoperable + +using TagUInt1 = tagged_integer; +using TagUInt2 = tagged_integer; +using TagUInt3 = tagged_integer; + +// Check construction of tagged_integers +static_assert( + std::is_constructible::value, + "TagUInt1 should be constructible using a std::uint32_t"); + +static_assert( + !std::is_constructible::value, + "TagUInt1 should not be constructible using a std::uint64_t"); + +static_assert( + std::is_constructible::value, + "TagUInt3 should be constructible using a std::uint32_t"); + +static_assert( + std::is_constructible::value, + "TagUInt3 should be constructible using a std::uint64_t"); + +// Check assignment of tagged_integers +static_assert( + !std::is_assignable::value, + "TagUInt1 should not be assignable with a std::uint32_t"); + +static_assert( + !std::is_assignable::value, + "TagUInt1 should not be assignable with a std::uint64_t"); + +static_assert( + !std::is_assignable::value, + "TagUInt3 should not be assignable with a std::uint32_t"); + +static_assert( + !std::is_assignable::value, + "TagUInt3 should not be assignable with a std::uint64_t"); + +static_assert( + std::is_assignable::value, + "TagUInt1 should be assignable with a TagUInt1"); + +static_assert( + !std::is_assignable::value, + "TagUInt1 should not be assignable with a TagUInt2"); + +static_assert( + std::is_assignable::value, + "TagUInt3 should be assignable with a TagUInt1"); + +static_assert( + !std::is_assignable::value, + "TagUInt1 should not be assignable with a TagUInt3"); + +static_assert( + !std::is_assignable::value, + "TagUInt3 should not be assignable with a TagUInt1"); + +// Check convertibility of tagged_integers +static_assert( + !std::is_convertible::value, + "std::uint32_t should not be convertible to a TagUInt1"); + +static_assert( + !std::is_convertible::value, + "std::uint32_t should not be convertible to a TagUInt3"); + +static_assert( + !std::is_convertible::value, + "std::uint64_t should not be convertible to a TagUInt3"); + +static_assert( + !std::is_convertible::value, + "std::uint64_t should not be convertible to a TagUInt2"); + +static_assert( + !std::is_convertible::value, + "TagUInt1 should not be convertible to TagUInt2"); + +static_assert( + !std::is_convertible::value, + "TagUInt1 should not be convertible to TagUInt3"); + +static_assert( + !std::is_convertible::value, + "TagUInt2 should not be convertible to a TagUInt3"); + +TEST_SUITE_BEGIN("tagged_integer"); + +using TagInt = tagged_integer; + +TEST_CASE("comparison operators") +{ + TagInt const zero(0); + TagInt const one(1); + + CHECK(one == one); + CHECK(!(one == zero)); + + CHECK(one != zero); + CHECK(!(one != one)); + + CHECK(zero < one); + CHECK(!(one < zero)); + + CHECK(one > zero); + CHECK(!(zero > one)); + + CHECK(one >= one); + CHECK(one >= zero); + CHECK(!(zero >= one)); + + CHECK(zero <= one); + CHECK(zero <= zero); + CHECK(!(one <= zero)); +} + +TEST_CASE("increment / decrement operators") +{ + TagInt const zero(0); + TagInt const one(1); + TagInt a{0}; + ++a; + CHECK(a == one); + --a; + CHECK(a == zero); + a++; + CHECK(a == one); + a--; + CHECK(a == zero); +} + +TEST_CASE("arithmetic operators") +{ + TagInt a{-2}; + CHECK(+a == TagInt{-2}); + CHECK(-a == TagInt{2}); + CHECK(TagInt{-3} + TagInt{4} == TagInt{1}); + CHECK(TagInt{-3} - TagInt{4} == TagInt{-7}); + CHECK(TagInt{-3} * TagInt{4} == TagInt{-12}); + CHECK(TagInt{8} / TagInt{4} == TagInt{2}); + CHECK(TagInt{7} % TagInt{4} == TagInt{3}); + + CHECK(~TagInt{8} == TagInt{~TagInt::value_type{8}}); + CHECK((TagInt{6} & TagInt{3}) == TagInt{2}); + CHECK((TagInt{6} | TagInt{3}) == TagInt{7}); + CHECK((TagInt{6} ^ TagInt{3}) == TagInt{5}); + + CHECK((TagInt{4} << TagInt{2}) == TagInt{16}); + CHECK((TagInt{16} >> TagInt{2}) == TagInt{4}); +} + +TEST_CASE("assignment operators") +{ + TagInt a{-2}; + TagInt b{0}; + b = a; + CHECK(b == TagInt{-2}); + + // -3 + 4 == 1 + a = TagInt{-3}; + a += TagInt{4}; + CHECK(a == TagInt{1}); + + // -3 - 4 == -7 + a = TagInt{-3}; + a -= TagInt{4}; + CHECK(a == TagInt{-7}); + + // -3 * 4 == -12 + a = TagInt{-3}; + a *= TagInt{4}; + CHECK(a == TagInt{-12}); + + // 8/4 == 2 + a = TagInt{8}; + a /= TagInt{4}; + CHECK(a == TagInt{2}); + + // 7 % 4 == 3 + a = TagInt{7}; + a %= TagInt{4}; + CHECK(a == TagInt{3}); + + // 6 & 3 == 2 + a = TagInt{6}; + a /= TagInt{3}; + CHECK(a == TagInt{2}); + + // 6 | 3 == 7 + a = TagInt{6}; + a |= TagInt{3}; + CHECK(a == TagInt{7}); + + // 6 ^ 3 == 5 + a = TagInt{6}; + a ^= TagInt{3}; + CHECK(a == TagInt{5}); + + // 4 << 2 == 16 + a = TagInt{4}; + a <<= TagInt{2}; + CHECK(a == TagInt{16}); + + // 16 >> 2 == 4 + a = TagInt{16}; + a >>= TagInt{2}; + CHECK(a == TagInt{4}); +} + +TEST_SUITE_END(); diff --git a/src/test/core/CryptoPRNG_test.cpp b/src/tests/libxrpl/crypto/csprng.cpp similarity index 58% rename from src/test/core/CryptoPRNG_test.cpp rename to src/tests/libxrpl/crypto/csprng.cpp index 21924e582c0..a55d49b67cf 100644 --- a/src/test/core/CryptoPRNG_test.cpp +++ b/src/tests/libxrpl/crypto/csprng.cpp @@ -17,44 +17,18 @@ */ //============================================================================== -#include - -#include #include -namespace ripple { - -class CryptoPRNG_test : public beast::unit_test::suite -{ - void - testGetValues() - { - testcase("Get Values"); - try - { - auto& engine = crypto_prng(); - auto rand_val = engine(); - BEAST_EXPECT(rand_val >= engine.min()); - BEAST_EXPECT(rand_val <= engine.max()); - - uint16_t twoByte{0}; - engine(&twoByte, sizeof(uint16_t)); - pass(); - } - catch (std::exception&) - { - fail(); - } - } - -public: - void - run() override - { - testGetValues(); - } -}; +#include -BEAST_DEFINE_TESTSUITE(CryptoPRNG, core, ripple); +using namespace ripple; -} // namespace ripple +TEST_CASE("get values") +{ + auto& engine = crypto_prng(); + auto rand_val = engine(); + CHECK(rand_val >= engine.min()); + CHECK(rand_val <= engine.max()); + uint16_t twoByte{0}; + engine(&twoByte, sizeof(uint16_t)); +} diff --git a/src/tests/libxrpl/crypto/main.cpp b/src/tests/libxrpl/crypto/main.cpp new file mode 100644 index 00000000000..0a3f254ea87 --- /dev/null +++ b/src/tests/libxrpl/crypto/main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include diff --git a/src/xrpld/app/consensus/RCLValidations.cpp b/src/xrpld/app/consensus/RCLValidations.cpp index a04047c78a1..5305c953571 100644 --- a/src/xrpld/app/consensus/RCLValidations.cpp +++ b/src/xrpld/app/consensus/RCLValidations.cpp @@ -136,7 +136,7 @@ RCLValidationsAdaptor::acquire(LedgerHash const& hash) if (!ledger) { - JLOG(j_.debug()) + JLOG(j_.warn()) << "Need validated ledger for preferred ledger analysis " << hash; Application* pApp = &app_; diff --git a/src/xrpld/app/consensus/README.md b/src/xrpld/app/consensus/README.md index 00502731383..bdf5afe87c0 100644 --- a/src/xrpld/app/consensus/README.md +++ b/src/xrpld/app/consensus/README.md @@ -1,13 +1,12 @@ -# RCL Consensus +# RCL Consensus This directory holds the types and classes needed to connect the generic consensus algorithm to the rippled-specific instance of consensus. - * `RCLCxTx` adapts a `SHAMapItem` transaction. - * `RCLCxTxSet` adapts a `SHAMap` to represent a set of transactions. - * `RCLCxLedger` adapts a `Ledger`. - * `RCLConsensus` is implements the requirements of the generic - `Consensus` class by connecting to the rest of the `rippled` - application. - +- `RCLCxTx` adapts a `SHAMapItem` transaction. +- `RCLCxTxSet` adapts a `SHAMap` to represent a set of transactions. +- `RCLCxLedger` adapts a `Ledger`. +- `RCLConsensus` is implements the requirements of the generic + `Consensus` class by connecting to the rest of the `rippled` + application. diff --git a/src/xrpld/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp index 3cdf0ab1a7f..6de4f2cbdef 100644 --- a/src/xrpld/app/ledger/Ledger.cpp +++ b/src/xrpld/app/ledger/Ledger.cpp @@ -996,7 +996,8 @@ pendSaveValidated( bool isSynchronous, bool isCurrent) { - if (!app.getHashRouter().setFlags(ledger->info().hash, SF_SAVED)) + if (!app.getHashRouter().setFlags( + ledger->info().hash, HashRouterFlags::SAVED)) { // We have tried to save this ledger recently auto stream = app.journal("Ledger").debug(); diff --git a/src/xrpld/app/ledger/LedgerToJson.h b/src/xrpld/app/ledger/LedgerToJson.h index 40be57fc9c4..be017bca86a 100644 --- a/src/xrpld/app/ledger/LedgerToJson.h +++ b/src/xrpld/app/ledger/LedgerToJson.h @@ -37,9 +37,8 @@ struct LedgerFill ReadView const& l, RPC::Context* ctx, int o = 0, - std::vector q = {}, - LedgerEntryType t = ltANY) - : ledger(l), options(o), txQueue(std::move(q)), type(t), context(ctx) + std::vector q = {}) + : ledger(l), options(o), txQueue(std::move(q)), context(ctx) { if (context) closeTime = context->ledgerMaster.getCloseTimeBySeq(ledger.seq()); @@ -58,7 +57,6 @@ struct LedgerFill ReadView const& ledger; int options; std::vector txQueue; - LedgerEntryType type; RPC::Context* context; std::optional closeTime; }; diff --git a/src/xrpld/app/ledger/README.md b/src/xrpld/app/ledger/README.md index cf7844856b5..d2afe01e714 100644 --- a/src/xrpld/app/ledger/README.md +++ b/src/xrpld/app/ledger/README.md @@ -1,9 +1,8 @@ +# Ledger Process -# Ledger Process # +## Introduction -## Introduction ## - -## Life Cycle ## +## Life Cycle Every server always has an open ledger. All received new transactions are applied to the open ledger. The open ledger can't close until we reach @@ -37,10 +36,11 @@ round. This is a "rebase": now that we know the real history, the current open ledger is rebased against the last closed ledger. The purpose of the open ledger is as follows: + - Forms the basis of the initial proposal during consensus - Used to decide if we can reject the transaction without relaying it -## Byzantine Failures ## +## Byzantine Failures Byzantine failures are resolved as follows. If there is a supermajority ledger, then a minority of validators will discover that the consensus round is @@ -52,167 +52,169 @@ If there is no majority ledger, then starting on the next consensus round there will not be a consensus on the last closed ledger. Another avalanche process is started. -## Validators ## +## Validators The only meaningful difference between a validator and a 'regular' server is that the validator sends its proposals and validations to the network. --- -# The Ledger Stream # +# The Ledger Stream -## Ledger Priorities ## +## Ledger Priorities There are two ledgers that are the most important for a rippled server to have: - - The consensus ledger and - - The last validated ledger. +- The consensus ledger and +- The last validated ledger. If we need either of those two ledgers they are fetched with the highest -priority. Also, when they arrive, they replace their earlier counterparts +priority. Also, when they arrive, they replace their earlier counterparts (if they exist). The `LedgerMaster` object tracks - - the last published ledger, - - the last validated ledger, and - - ledger history. -So the `LedgerMaster` is at the center of fetching historical ledger data. + +- the last published ledger, +- the last validated ledger, and +- ledger history. + So the `LedgerMaster` is at the center of fetching historical ledger data. In specific, the `LedgerMaster::doAdvance()` method triggers the code that fetches historical data and controls the state machine for ledger acquisition. The server tries to publish an on-going stream of consecutive ledgers to its -clients. After the server has started and caught up with network +clients. After the server has started and caught up with network activity, say when ledger 500 is being settled, then the server puts its best effort into publishing validated ledger 500 followed by validated ledger 501 -and then 502. This effort continues until the server is shut down. +and then 502. This effort continues until the server is shut down. But loading or network connectivity may sometimes interfere with that ledger -stream. So suppose the server publishes validated ledger 600 and then -receives validated ledger 603. Then the server wants to back fill its ledger +stream. So suppose the server publishes validated ledger 600 and then +receives validated ledger 603. Then the server wants to back fill its ledger history with ledgers 601 and 602. -The server prioritizes keeping up with current ledgers. But if it is caught +The server prioritizes keeping up with current ledgers. But if it is caught up on the current ledger, and there are no higher priority demands on the -server, then it will attempt to back fill its historical ledgers. It fills +server, then it will attempt to back fill its historical ledgers. It fills in the historical ledger data first by attempting to retrieve it from the -local database. If the local database does not have all of the necessary data +local database. If the local database does not have all of the necessary data then the server requests the remaining information from network peers. -Suppose the server is missing multiple historical ledgers. Take the previous -example where we have ledgers 603 and 600, but we're missing 601 and 602. In +Suppose the server is missing multiple historical ledgers. Take the previous +example where we have ledgers 603 and 600, but we're missing 601 and 602. In that case the server requests information for ledger 602 first, before -back-filling ledger 601. We want to expand the contiguous range of -most-recent ledgers that the server has locally. There's also a limit to -how much historical ledger data is useful. So if we're on ledger 603, but +back-filling ledger 601. We want to expand the contiguous range of +most-recent ledgers that the server has locally. There's also a limit to +how much historical ledger data is useful. So if we're on ledger 603, but we're missing ledger 4 we may not bother asking for ledger 4. -## Assembling a Ledger ## +## Assembling a Ledger When data for a ledger arrives from a peer, it may take a while before the -server can apply that data. So when ledger data arrives we schedule a job -thread to apply that data. If more data arrives before the job starts we add -that data to the job. We defer requesting more ledger data until all of the -data we have for that ledger has been processed. Once all of that data is +server can apply that data. So when ledger data arrives we schedule a job +thread to apply that data. If more data arrives before the job starts we add +that data to the job. We defer requesting more ledger data until all of the +data we have for that ledger has been processed. Once all of that data is processed we can intelligently request only the additional data that we need -to fill in the ledger. This reduces network traffic and minimizes the load +to fill in the ledger. This reduces network traffic and minimizes the load on peers supplying the data. If we receive data for a ledger that is not currently under construction, -we don't just throw the data away. In particular the AccountStateNodes -may be useful, since they can be re-used across ledgers. This data is +we don't just throw the data away. In particular the AccountStateNodes +may be useful, since they can be re-used across ledgers. This data is stashed in memory (not the database) where the acquire process can find it. Peers deliver ledger data in the order in which the data can be validated. Data arrives in the following order: - 1. The hash of the ledger header - 2. The ledger header - 3. The root nodes of the transaction tree and state tree - 4. The lower (non-root) nodes of the state tree - 5. The lower (non-root) nodes of the transaction tree +1. The hash of the ledger header +2. The ledger header +3. The root nodes of the transaction tree and state tree +4. The lower (non-root) nodes of the state tree +5. The lower (non-root) nodes of the transaction tree -Inner-most nodes are supplied before outer nodes. This allows the +Inner-most nodes are supplied before outer nodes. This allows the requesting server to hook things up (and validate) in the order in which data arrives. If this process fails, then a server can also ask for ledger data by hash, -rather than by asking for specific nodes in a ledger. Asking for information +rather than by asking for specific nodes in a ledger. Asking for information by hash is less efficient, but it allows a peer to return the information -even if the information is not assembled into a tree. All the peer needs is +even if the information is not assembled into a tree. All the peer needs is the raw data. -## Which Peer To Ask ## +## Which Peer To Ask Peers go though state transitions as the network goes through its state -transitions. Peer's provide their state to their directly connected peers. +transitions. Peer's provide their state to their directly connected peers. By monitoring the state of each connected peer a server can tell which of its peers has the information that it needs. Therefore if a server suffers a byzantine failure the server can tell which -of its peers did not suffer that same failure. So the server knows which +of its peers did not suffer that same failure. So the server knows which peer(s) to ask for the missing information. -Peers also report their contiguous range of ledgers. This is another way that +Peers also report their contiguous range of ledgers. This is another way that a server can determine which peer to ask for a particular ledger or piece of a ledger. -There are also indirect peer queries. If there have been timeouts while -acquiring ledger data then a server may issue indirect queries. In that +There are also indirect peer queries. If there have been timeouts while +acquiring ledger data then a server may issue indirect queries. In that case the server receiving the indirect query passes the query along to any -of its peers that may have the requested data. This is important if the -network has a byzantine failure. It also helps protect the validation -network. A validator may need to get a peer set from one of the other +of its peers that may have the requested data. This is important if the +network has a byzantine failure. It also helps protect the validation +network. A validator may need to get a peer set from one of the other validators, and indirect queries improve the likelihood of success with that. -## Kinds of Fetch Packs ## +## Kinds of Fetch Packs A FetchPack is the way that peers send partial ledger data to other peers so the receiving peer can reconstruct a ledger. -A 'normal' FetchPack is a bucket of nodes indexed by hash. The server +A 'normal' FetchPack is a bucket of nodes indexed by hash. The server building the FetchPack puts information into the FetchPack that the -destination server is likely to need. Normally they contain all of the +destination server is likely to need. Normally they contain all of the missing nodes needed to fill in a ledger. A 'compact' FetchPack, on the other hand, contains only leaf nodes, no -inner nodes. Because there are no inner nodes, the ledger information that -it contains cannot be validated as the ledger is assembled. We have to, +inner nodes. Because there are no inner nodes, the ledger information that +it contains cannot be validated as the ledger is assembled. We have to, initially, take the accuracy of the FetchPack for granted and assemble the -ledger. Once the entire ledger is assembled the entire ledger can be -validated. But if the ledger does not validate then there's nothing to be +ledger. Once the entire ledger is assembled the entire ledger can be +validated. But if the ledger does not validate then there's nothing to be done but throw the entire FetchPack away; there's no way to save a portion of the FetchPack. -The FetchPacks just described could be termed 'reverse FetchPacks.' They -only provide historical data. There may be a use for what could be called a -'forward FetchPack.' A forward FetchPack would contain the information that +The FetchPacks just described could be termed 'reverse FetchPacks.' They +only provide historical data. There may be a use for what could be called a +'forward FetchPack.' A forward FetchPack would contain the information that is needed to build a new ledger out of the preceding ledger. A forward compact FetchPack would need to contain: - - The header for the new ledger, - - The leaf nodes of the transaction tree (if there is one), - - The index of deleted nodes in the state tree, - - The index and data for new nodes in the state tree, and - - The index and new data of modified nodes in the state tree. + +- The header for the new ledger, +- The leaf nodes of the transaction tree (if there is one), +- The index of deleted nodes in the state tree, +- The index and data for new nodes in the state tree, and +- The index and new data of modified nodes in the state tree. --- -# Definitions # +# Definitions -## Open Ledger ## +## Open Ledger The open ledger is the ledger that the server applies all new incoming transactions to. -## Last Validated Ledger ## +## Last Validated Ledger The most recent ledger that the server is certain will always remain part of the permanent, public history. -## Last Closed Ledger ## +## Last Closed Ledger The most recent ledger that the server believes the network reached consensus on. Different servers can arrive at a different conclusion about the last @@ -220,29 +222,29 @@ closed ledger. This is a consequence of Byzantanine failure. The purpose of validations is to resolve the differences between servers and come to a common conclusion about which last closed ledger is authoritative. -## Consensus ## +## Consensus A distributed agreement protocol. Ripple uses the consensus process to solve the problem of double-spending. -## Validation ## +## Validation A signed statement indicating that it built a particular ledger as a result of the consensus process. -## Proposal ## +## Proposal A signed statement of which transactions it believes should be included in the next consensus ledger. -## Ledger Header ## +## Ledger Header The "ledger header" is the chunk of data that hashes to the ledger's hash. It contains the sequence number, parent hash, hash of the previous ledger, hash of the root node of the state tree, and so on. -## Ledger Base ## +## Ledger Base The term "ledger base" refers to a particular type of query and response used in the ledger fetch process that includes @@ -251,9 +253,9 @@ such as the root node of the state tree. --- -# Ledger Structures # +# Ledger Structures -## Account Root ## +## Account Root **Account:** A 160-bit account ID. @@ -264,8 +266,8 @@ such as the root node of the state tree. **LedgerEntryType:** "AccountRoot" **OwnerCount:** The number of items the account owns that are charged to the -account. Offers are charged to the account. Trust lines may be charged to -the account (but not necessarily). The OwnerCount determines the reserve on +account. Offers are charged to the account. Trust lines may be charged to +the account (but not necessarily). The OwnerCount determines the reserve on the account. **PreviousTxnID:** 256-bit index of the previous transaction on this account. @@ -274,43 +276,45 @@ the account. transaction on this account. **Sequence:** Must be a value of 1 for the account to process a valid -transaction. The value initially matches the sequence number of the state -tree of the account that signed the transaction. The process of executing -the transaction increments the sequence number. This is how ripple prevents +transaction. The value initially matches the sequence number of the state +tree of the account that signed the transaction. The process of executing +the transaction increments the sequence number. This is how ripple prevents a transaction from executing more than once. **index:** 256-bit hash of this AccountRoot. - -## Trust Line ## +## Trust Line The trust line acts as an edge connecting two accounts: the accounts -represented by the HighNode and the LowNode. Which account is "high" and -"low" is determined by the values of the two 160-bit account IDs. The -account with the smaller 160-bit ID is always the low account. This +represented by the HighNode and the LowNode. Which account is "high" and +"low" is determined by the values of the two 160-bit account IDs. The +account with the smaller 160-bit ID is always the low account. This ordering makes the hash of a trust line between accounts A and B have the same value as a trust line between accounts B and A. **Balance:** - - **currency:** String identifying a valid currency, e.g., "BTC". - - **issuer:** There is no issuer, really, this entry is "NoAccount". - - **value:** + +- **currency:** String identifying a valid currency, e.g., "BTC". +- **issuer:** There is no issuer, really, this entry is "NoAccount". +- **value:** **Flags:** ??? **HighLimit:** - - **currency:** Same as for Balance. - - **issuer:** A 160-bit account ID. - - **value:** The largest amount this issuer will accept of the currency. + +- **currency:** Same as for Balance. +- **issuer:** A 160-bit account ID. +- **value:** The largest amount this issuer will accept of the currency. **HighNode:** A deletion hint. **LedgerEntryType:** "RippleState". **LowLimit:** - - **currency:** Same as for Balance. - - **issuer:** A 160-bit account ID. - - **value:** The largest amount of the currency this issuer will accept. + +- **currency:** Same as for Balance. +- **issuer:** A 160-bit account ID. +- **value:** The largest amount of the currency this issuer will accept. **LowNode:** A deletion hint @@ -321,8 +325,7 @@ transaction on this account. **index:** 256-bit hash of this RippleState. - -## Ledger Hashes ## +## Ledger Hashes **Flags:** ??? @@ -334,8 +337,7 @@ transaction on this account. **index:** 256-bit hash of this LedgerHashes. - -## Owner Directory ## +## Owner Directory Lists all of the offers and trust lines that are associated with an account. @@ -351,8 +353,7 @@ Lists all of the offers and trust lines that are associated with an account. **index:** A hash of the owner account. - -## Book Directory ## +## Book Directory Lists one or more offers that have the same quality. @@ -360,18 +361,18 @@ If a pair of Currency and Issuer fields are all zeros, then that pair is dealing in XRP. The code, at the moment, does not recognize that the Currency and Issuer -fields are currencies and issuers. So those values are presented in hex, -rather than as accounts and currencies. That's a bug and should be fixed +fields are currencies and issuers. So those values are presented in hex, +rather than as accounts and currencies. That's a bug and should be fixed at some point. -**ExchangeRate:** A 64-bit value. The first 8-bits is the exponent and the -remaining bits are the mantissa. The format is such that a bigger 64-bit +**ExchangeRate:** A 64-bit value. The first 8-bits is the exponent and the +remaining bits are the mantissa. The format is such that a bigger 64-bit value always represents a higher exchange rate. -Each type can compute its own hash. The hash of a book directory contains, -as its lowest 64 bits, the exchange rate. This means that if there are -multiple *almost* identical book directories, but with different exchange -rates, then these book directories will sit together in the ledger. The best +Each type can compute its own hash. The hash of a book directory contains, +as its lowest 64 bits, the exchange rate. This means that if there are +multiple _almost_ identical book directories, but with different exchange +rates, then these book directories will sit together in the ledger. The best exchange rate will be the first in the sequence of Book Directories. **Flags:** ??? @@ -392,14 +393,14 @@ currencies described by this BookDirectory. **TakerPaysIssuer:** Issuer of the PaysCurrency. **index:** A 256-bit hash computed using the TakerGetsCurrency, TakerGetsIssuer, -TakerPaysCurrency, and TakerPaysIssuer in the top 192 bits. The lower 64-bits +TakerPaysCurrency, and TakerPaysIssuer in the top 192 bits. The lower 64-bits are occupied by the exchange rate. --- -# Ledger Publication # +# Ledger Publication -## Overview ## +## Overview The Ripple server permits clients to subscribe to a continuous stream of fully-validated ledgers. The publication code maintains this stream. @@ -408,7 +409,7 @@ The server attempts to maintain this continuous stream unless it falls too far behind, in which case it jumps to the current fully-validated ledger and then attempts to resume a continuous stream. -## Implementation ## +## Implementation `LedgerMaster::doAdvance` is invoked when work may need to be done to publish ledgers to clients. This code loops until it cannot make further @@ -430,17 +431,17 @@ the list of resident ledgers. --- -# The Ledger Cleaner # +# The Ledger Cleaner -## Overview ## +## Overview The ledger cleaner checks and, if necessary, repairs the SQLite ledger and -transaction databases. It can also check for pieces of a ledger that should -be in the node back end but are missing. If it detects this case, it -triggers a fetch of the ledger. The ledger cleaner only operates by manual +transaction databases. It can also check for pieces of a ledger that should +be in the node back end but are missing. If it detects this case, it +triggers a fetch of the ledger. The ledger cleaner only operates by manual request. It is never started automatically. -## Operations ## +## Operations The ledger cleaner can operate on a single ledger or a range of ledgers. It always validates the ledger chain itself, ensuring that the SQLite database @@ -448,7 +449,7 @@ contains a consistent chain of ledgers from the last validated ledger as far back as the database goes. If requested, it can additionally repair the SQLite entries for transactions -in each checked ledger. This was primarily intended to repair incorrect +in each checked ledger. This was primarily intended to repair incorrect entries created by a bug (since fixed) that could cause transasctions from a ledger other than the fully-validated ledger to appear in the SQLite databases in addition to the transactions from the correct ledger. @@ -460,7 +461,7 @@ To prevent the ledger cleaner from saturating the available I/O bandwidth and excessively polluting caches with ancient information, the ledger cleaner paces itself and does not attempt to get its work done quickly. -## Commands ## +## Commands The ledger cleaner can be controlled and monitored with the **ledger_cleaner** RPC command. With no parameters, this command reports on the status of the @@ -486,4 +487,4 @@ ledger(s) for missing nodes in the back end node store --- -# References # +# References diff --git a/src/xrpld/app/ledger/detail/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp index 3e4f4b8f0a7..0e6f81dfbc7 100644 --- a/src/xrpld/app/ledger/detail/LedgerToJson.cpp +++ b/src/xrpld/app/ledger/detail/LedgerToJson.cpp @@ -268,19 +268,16 @@ fillJsonState(Object& json, LedgerFill const& fill) for (auto const& sle : ledger.sles) { - if (fill.type == ltANY || sle->getType() == fill.type) + if (binary) { - if (binary) - { - auto&& obj = appendObject(array); - obj[jss::hash] = to_string(sle->key()); - obj[jss::tx_blob] = serializeHex(*sle); - } - else if (expanded) - array.append(sle->getJson(JsonOptions::none)); - else - array.append(to_string(sle->key())); + auto&& obj = appendObject(array); + obj[jss::hash] = to_string(sle->key()); + obj[jss::tx_blob] = serializeHex(*sle); } + else if (expanded) + array.append(sle->getJson(JsonOptions::none)); + else + array.append(to_string(sle->key())); } } diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index ea0b794116d..c824eccfba6 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -79,7 +79,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index e926a38563e..19c8c9910d5 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/src/xrpld/app/misc/AMMUtils.h b/src/xrpld/app/misc/AMMUtils.h index b2c0007dc77..2a9f82ae605 100644 --- a/src/xrpld/app/misc/AMMUtils.h +++ b/src/xrpld/app/misc/AMMUtils.h @@ -125,6 +125,17 @@ isOnlyLiquidityProvider( Issue const& ammIssue, AccountID const& lpAccount); +/** Due to rounding, the LPTokenBalance of the last LP might + * not match the LP's trustline balance. If it's within the tolerance, + * update LPTokenBalance to match the LP's trustline balance. + */ +Expected +verifyAndAdjustLPTokenBalance( + Sandbox& sb, + STAmount const& lpTokens, + std::shared_ptr& ammSle, + AccountID const& account); + } // namespace ripple #endif // RIPPLE_APP_MISC_AMMUTILS_H_INCLUDED diff --git a/src/xrpld/app/misc/CredentialHelpers.cpp b/src/xrpld/app/misc/CredentialHelpers.cpp index 81355f17920..6d1f9f78c56 100644 --- a/src/xrpld/app/misc/CredentialHelpers.cpp +++ b/src/xrpld/app/misc/CredentialHelpers.cpp @@ -120,15 +120,15 @@ deleteSLE( } NotTEC -checkFields(PreflightContext const& ctx) +checkFields(STTx const& tx, beast::Journal j) { - if (!ctx.tx.isFieldPresent(sfCredentialIDs)) + if (!tx.isFieldPresent(sfCredentialIDs)) return tesSUCCESS; - auto const& credentials = ctx.tx.getFieldV256(sfCredentialIDs); + auto const& credentials = tx.getFieldV256(sfCredentialIDs); if (credentials.empty() || (credentials.size() > maxCredentialsArraySize)) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "Malformed transaction: Credentials array size is invalid: " << credentials.size(); return temMALFORMED; @@ -140,7 +140,7 @@ checkFields(PreflightContext const& ctx) auto [it, ins] = duplicates.insert(cred); if (!ins) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "Malformed transaction: duplicates in credentials."; return temMALFORMED; } @@ -150,24 +150,28 @@ checkFields(PreflightContext const& ctx) } TER -valid(PreclaimContext const& ctx, AccountID const& src) +valid( + STTx const& tx, + ReadView const& view, + AccountID const& src, + beast::Journal j) { - if (!ctx.tx.isFieldPresent(sfCredentialIDs)) + if (!tx.isFieldPresent(sfCredentialIDs)) return tesSUCCESS; - auto const& credIDs(ctx.tx.getFieldV256(sfCredentialIDs)); + auto const& credIDs(tx.getFieldV256(sfCredentialIDs)); for (auto const& h : credIDs) { - auto const sleCred = ctx.view.read(keylet::credential(h)); + auto const sleCred = view.read(keylet::credential(h)); if (!sleCred) { - JLOG(ctx.j.trace()) << "Credential doesn't exist. Cred: " << h; + JLOG(j.trace()) << "Credential doesn't exist. Cred: " << h; return tecBAD_CREDENTIALS; } if (sleCred->getAccountID(sfSubject) != src) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "Credential doesn't belong to the source account. Cred: " << h; return tecBAD_CREDENTIALS; @@ -175,7 +179,7 @@ valid(PreclaimContext const& ctx, AccountID const& src) if (!(sleCred->getFlags() & lsfAccepted)) { - JLOG(ctx.j.trace()) << "Credential isn't accepted. Cred: " << h; + JLOG(j.trace()) << "Credential isn't accepted. Cred: " << h; return tecBAD_CREDENTIALS; } @@ -352,10 +356,12 @@ verifyValidDomain( TER verifyDepositPreauth( - ApplyContext& ctx, + STTx const& tx, + ApplyView& view, AccountID const& src, AccountID const& dst, - std::shared_ptr const& sleDst) + std::shared_ptr const& sleDst, + beast::Journal j) { // If depositPreauth is enabled, then an account that requires // authorization has at least two ways to get a payment in: @@ -363,24 +369,21 @@ verifyDepositPreauth( // 2. If src is deposit preauthorized by dst (either by account or by // credentials). - bool const credentialsPresent = ctx.tx.isFieldPresent(sfCredentialIDs); + bool const credentialsPresent = tx.isFieldPresent(sfCredentialIDs); if (credentialsPresent && - credentials::removeExpired( - ctx.view(), ctx.tx.getFieldV256(sfCredentialIDs), ctx.journal)) + credentials::removeExpired(view, tx.getFieldV256(sfCredentialIDs), j)) return tecEXPIRED; if (sleDst && (sleDst->getFlags() & lsfDepositAuth)) { if (src != dst) { - if (!ctx.view().exists(keylet::depositPreauth(dst, src))) + if (!view.exists(keylet::depositPreauth(dst, src))) return !credentialsPresent ? tecNO_PERMISSION : credentials::authorizedDepositPreauth( - ctx.view(), - ctx.tx.getFieldV256(sfCredentialIDs), - dst); + view, tx.getFieldV256(sfCredentialIDs), dst); } } diff --git a/src/xrpld/app/misc/CredentialHelpers.h b/src/xrpld/app/misc/CredentialHelpers.h index 162ddd6515d..84938180ce2 100644 --- a/src/xrpld/app/misc/CredentialHelpers.h +++ b/src/xrpld/app/misc/CredentialHelpers.h @@ -20,7 +20,16 @@ #ifndef RIPPLE_APP_MISC_CREDENTIALHELPERS_H_INCLUDED #define RIPPLE_APP_MISC_CREDENTIALHELPERS_H_INCLUDED -#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace credentials { @@ -48,13 +57,17 @@ deleteSLE( // Amendment and parameters checks for sfCredentialIDs field NotTEC -checkFields(PreflightContext const& ctx); +checkFields(STTx const& tx, beast::Journal j); // Accessing the ledger to check if provided credentials are valid. Do not use // in doApply (only in preclaim) since it does not remove expired credentials. // If you call it in prelaim, you also must call verifyDepositPreauth in doApply TER -valid(PreclaimContext const& ctx, AccountID const& src); +valid( + STTx const& tx, + ReadView const& view, + AccountID const& src, + beast::Journal j); // Check if subject has any credential maching the given domain. If you call it // in preclaim and it returns tecEXPIRED, you should call verifyValidDomain in @@ -93,10 +106,12 @@ verifyValidDomain( // Check expired credentials and for existing DepositPreauth ledger object TER verifyDepositPreauth( - ApplyContext& ctx, + STTx const& tx, + ApplyView& view, AccountID const& src, AccountID const& dst, - std::shared_ptr const& sleDst); + std::shared_ptr const& sleDst, + beast::Journal j); } // namespace ripple diff --git a/src/xrpld/app/misc/FeeEscalation.md b/src/xrpld/app/misc/FeeEscalation.md index b86f8dab945..468ab2b5282 100644 --- a/src/xrpld/app/misc/FeeEscalation.md +++ b/src/xrpld/app/misc/FeeEscalation.md @@ -17,15 +17,16 @@ transactions into the open ledger, even during unfavorable conditions. How fees escalate: 1. There is a base [fee level](#fee-level) of 256, -which is the minimum that a typical transaction -is required to pay. For a [reference -transaction](#reference-transaction), that corresponds to the -network base fee, which is currently 10 drops. + which is the minimum that a typical transaction + is required to pay. For a [reference + transaction](#reference-transaction), that corresponds to the + network base fee, which is currently 10 drops. 2. However, there is a limit on the number of transactions that -can get into an open ledger for that base fee level. The limit -will vary based on the [health](#consensus-health) of the -consensus process, but will be at least [5](#other-constants). - * If consensus stays [healthy](#consensus-health), the limit will + can get into an open ledger for that base fee level. The limit + will vary based on the [health](#consensus-health) of the + consensus process, but will be at least [5](#other-constants). + +- If consensus stays [healthy](#consensus-health), the limit will be the max of the number of transactions in the validated ledger plus [20%](#other-constants) or the current limit until it gets to [50](#other-constants), at which point, the limit will be the @@ -35,50 +36,56 @@ consensus process, but will be at least [5](#other-constants). decreases (i.e. a large ledger is no longer recent), the limit will decrease to the new largest value by 10% each time the ledger has more than 50 transactions. - * If consensus does not stay [healthy](#consensus-health), +- If consensus does not stay [healthy](#consensus-health), the limit will clamp down to the smaller of the number of transactions in the validated ledger minus [50%](#other-constants) or the previous limit minus [50%](#other-constants). - * The intended effect of these mechanisms is to allow as many base fee +- The intended effect of these mechanisms is to allow as many base fee level transactions to get into the ledger as possible while the network is [healthy](#consensus-health), but to respond quickly to any condition that makes it [unhealthy](#consensus-health), including, but not limited to, malicious attacks. + 3. Once there are more transactions in the open ledger than indicated -by the limit, the required fee level jumps drastically. - * The formula is `( lastLedgerMedianFeeLevel * - TransactionsInOpenLedger^2 / limit^2 )`, + by the limit, the required fee level jumps drastically. + +- The formula is `( lastLedgerMedianFeeLevel * +TransactionsInOpenLedger^2 / limit^2 )`, and returns a [fee level](#fee-level). + 4. That may still be pretty small, but as more transactions get -into the ledger, the fee level increases exponentially. - * For example, if the limit is 6, and the median fee is minimal, + into the ledger, the fee level increases exponentially. + +- For example, if the limit is 6, and the median fee is minimal, and assuming all [reference transactions](#reference-transaction), the 8th transaction only requires a [level](#fee-level) of about 174,000 or about 6800 drops, but the 20th transaction requires a [level](#fee-level) of about 1,283,000 or about 50,000 drops. + 5. Finally, as each ledger closes, the median fee level of that ledger is -computed and used as `lastLedgerMedianFeeLevel` (with a -[minimum value of 128,000](#other-constants)) -in the fee escalation formula for the next open ledger. - * Continuing the example above, if ledger consensus completes with + computed and used as `lastLedgerMedianFeeLevel` (with a + [minimum value of 128,000](#other-constants)) + in the fee escalation formula for the next open ledger. + +- Continuing the example above, if ledger consensus completes with only those 20 transactions, and all of those transactions paid the minimum required fee at each step, the limit will be adjusted from 6 to 24, and the `lastLedgerMedianFeeLevel` will be about 322,000, which is 12,600 drops for a [reference transaction](#reference-transaction). - * This will only require 10 drops for the first 25 transactions, +- This will only require 10 drops for the first 25 transactions, but the 26th transaction will require a level of about 349,150 or about 13,649 drops. -* This example assumes a cold-start scenario, with a single, possibly -malicious, user willing to pay arbitrary amounts to get transactions -into the open ledger. It ignores the effects of the [Transaction -Queue](#transaction-queue). Any lower fee level transactions submitted -by other users at the same time as this user's transactions will go into -the transaction queue, and will have the first opportunity to be applied -to the _next_ open ledger. The next section describes how that works in -more detail. +- This example assumes a cold-start scenario, with a single, possibly + malicious, user willing to pay arbitrary amounts to get transactions + into the open ledger. It ignores the effects of the [Transaction + Queue](#transaction-queue). Any lower fee level transactions submitted + by other users at the same time as this user's transactions will go into + the transaction queue, and will have the first opportunity to be applied + to the _next_ open ledger. The next section describes how that works in + more detail. ## Transaction Queue @@ -92,33 +99,34 @@ traffic periods, and give those transactions a much better chance to succeed. 1. If an incoming transaction meets both the base [fee -level](#fee-level) and the [load fee](#load-fee) minimum, but does not have a high -enough [fee level](#fee-level) to immediately go into the open ledger, -it is instead put into the queue and broadcast to peers. Each peer will -then make an independent decision about whether to put the transaction -into its open ledger or the queue. In principle, peers with identical -open ledgers will come to identical decisions. Any discrepancies will be -resolved as usual during consensus. + level](#fee-level) and the [load fee](#load-fee) minimum, but does not have a high + enough [fee level](#fee-level) to immediately go into the open ledger, + it is instead put into the queue and broadcast to peers. Each peer will + then make an independent decision about whether to put the transaction + into its open ledger or the queue. In principle, peers with identical + open ledgers will come to identical decisions. Any discrepancies will be + resolved as usual during consensus. 2. When consensus completes, the open ledger limit is adjusted, and -the required [fee level](#fee-level) drops back to the base -[fee level](#fee-level). Before the ledger is made available to -external transactions, transactions are applied from the queue to the -ledger from highest [fee level](#fee-level) to lowest. These transactions -count against the open ledger limit, so the required [fee level](#fee-level) -may start rising during this process. + the required [fee level](#fee-level) drops back to the base + [fee level](#fee-level). Before the ledger is made available to + external transactions, transactions are applied from the queue to the + ledger from highest [fee level](#fee-level) to lowest. These transactions + count against the open ledger limit, so the required [fee level](#fee-level) + may start rising during this process. 3. Once the queue is empty, or the required [fee level](#fee-level) -rises too high for the remaining transactions in the queue, the ledger -is opened up for normal transaction processing. + rises too high for the remaining transactions in the queue, the ledger + is opened up for normal transaction processing. 4. A transaction in the queue can stay there indefinitely in principle, -but in practice, either - * it will eventually get applied to the ledger, - * it will attempt to apply to the ledger and fail, - * it will attempt to apply to the ledger and retry [10 + but in practice, either + +- it will eventually get applied to the ledger, +- it will attempt to apply to the ledger and fail, +- it will attempt to apply to the ledger and retry [10 times](#other-constants), - * its last ledger sequence number will expire, - * the user will replace it by submitting another transaction with the same +- its last ledger sequence number will expire, +- the user will replace it by submitting another transaction with the same sequence number and at least a [25% higher fee](#other-constants), or - * it will get dropped when the queue fills up with more valuable transactions. +- it will get dropped when the queue fills up with more valuable transactions. The size limit is computed dynamically, and can hold transactions for the next [20 ledgers](#other-constants) (restricted to a minimum of [2000 transactions](#other-constants)). The lower the transaction's @@ -128,14 +136,15 @@ If a transaction is submitted for an account with one or more transactions already in the queue, and a sequence number that is sequential with the other transactions in the queue for that account, it will be considered for the queue if it meets these additional criteria: - * the account has fewer than [10](#other-constants) transactions + +- the account has fewer than [10](#other-constants) transactions already in the queue. - * all other queued transactions for that account, in the case where +- all other queued transactions for that account, in the case where they spend the maximum possible XRP, leave enough XRP balance to pay the fee, - * the total fees for the other queued transactions are less than both +- the total fees for the other queued transactions are less than both the network's minimum reserve and the account's XRP balance, and - * none of the prior queued transactions affect the ability of subsequent +- none of the prior queued transactions affect the ability of subsequent transactions to claim a fee. Currently, there is an additional restriction that the queue cannot work with @@ -148,7 +157,7 @@ development will make the queue aware of `sfAccountTxnID` mechanisms. ### Fee Level "Fee level" is used to allow the cost of different types of transactions -to be compared directly. For a [reference +to be compared directly. For a [reference transaction](#reference-transaction), the base fee level is 256. If a transaction is submitted with a higher `Fee` field, the fee level is scaled appropriately. @@ -157,16 +166,16 @@ Examples, assuming a [reference transaction](#reference-transaction) base fee of 10 drops: 1. A single-signed [reference transaction](#reference-transaction) -with `Fee=20` will have a fee level of -`20 drop fee * 256 fee level / 10 drop base fee = 512 fee level`. + with `Fee=20` will have a fee level of + `20 drop fee * 256 fee level / 10 drop base fee = 512 fee level`. 2. A multi-signed [reference transaction](#reference-transaction) with -3 signatures (base fee = 40 drops) and `Fee=60` will have a fee level of -`60 drop fee * 256 fee level / ((1tx + 3sigs) * 10 drop base fee) = 384 + 3 signatures (base fee = 40 drops) and `Fee=60` will have a fee level of + `60 drop fee * 256 fee level / ((1tx + 3sigs) * 10 drop base fee) = 384 fee level`. 3. A hypothetical future non-reference transaction with a base -fee of 15 drops multi-signed with 5 signatures and `Fee=90` will -have a fee level of -`90 drop fee * 256 fee level / ((1tx + 5sigs) * 15 drop base fee) = 256 + fee of 15 drops multi-signed with 5 signatures and `Fee=90` will + have a fee level of + `90 drop fee * 256 fee level / ((1tx + 5sigs) * 15 drop base fee) = 256 fee level`. This demonstrates that a simpler transaction paying less XRP can be more @@ -194,7 +203,7 @@ For consensus to be considered healthy, the peers on the network should largely remain in sync with one another. It is particularly important for the validators to remain in sync, because that is required for participation in consensus. However, the network tolerates some -validators being out of sync. Fundamentally, network health is a +validators being out of sync. Fundamentally, network health is a function of validators reaching consensus on sets of recently submitted transactions. @@ -214,61 +223,61 @@ often coincides with new ledgers with zero transactions. ### Other Constants -* *Base fee transaction limit per ledger*. The minimum value of 5 was -chosen to ensure the limit never gets so small that the ledger becomes -unusable. The "target" value of 50 was chosen so the limit never gets large -enough to invite abuse, but keeps up if the network stays healthy and -active. These exact values were chosen experimentally, and can easily -change in the future. -* *Expected ledger size growth and reduction percentages*. The growth -value of 20% was chosen to allow the limit to grow quickly as load -increases, but not so quickly as to allow bad actors to run unrestricted. -The reduction value of 50% was chosen to cause the limit to drop -significantly, but not so drastically that the limit cannot quickly -recover if the problem is temporary. These exact values were chosen -experimentally, and can easily change in the future. -* *Minimum `lastLedgerMedianFeeLevel`*. The value of 500 was chosen to -ensure that the first escalated fee was more significant and noticable -than what the default would allow. This exact value was chosen -experimentally, and can easily change in the future. -* *Transaction queue size limit*. The limit is computed based on the -base fee transaction limit per ledger, so that the queue can grow -automatically as the network's performance improves, allowing -more transactions per second, and thus more transactions per ledger -to process successfully. The limit of 20 ledgers was used to provide -a balance between resource (specifically memory) usage, and giving -transactions a realistic chance to be processed. The minimum size of -2000 transactions was chosen to allow a decent functional backlog during -network congestion conditions. These exact values were -chosen experimentally, and can easily change in the future. -* *Maximum retries*. A transaction in the queue can attempt to apply -to the open ledger, but get a retry (`ter`) code up to 10 times, at -which point, it will be removed from the queue and dropped. The -value was chosen to be large enough to allow temporary failures to clear -up, but small enough that the queue doesn't fill up with stale -transactions which prevent lower fee level, but more likely to succeed, -transactions from queuing. -* *Maximum transactions per account*. A single account can have up to 10 -transactions in the queue at any given time. This is primarily to -mitigate the lost cost of broadcasting multiple transactions if one of -the earlier ones fails or is otherwise removed from the queue without -being applied to the open ledger. The value was chosen arbitrarily, and -can easily change in the future. -* *Minimum last ledger sequence buffer*. If a transaction has a -`LastLedgerSequence` value, and cannot be processed into the open -ledger, that `LastLedgerSequence` must be at least 2 more than the -sequence number of the open ledger to be considered for the queue. The -value was chosen to provide a balance between letting the user control -the lifespan of the transaction, and giving a queued transaction a -chance to get processed out of the queue before getting discarded, -particularly since it may have dependent transactions also in the queue, -which will never succeed if this one is discarded. -* *Replaced transaction fee increase*. Any transaction in the queue can be -replaced by another transaction with the same sequence number and at -least a 25% higher fee level. The 25% increase is intended to cover the -resource cost incurred by broadcasting the original transaction to the -network. This value was chosen experimentally, and can easily change in -the future. +- _Base fee transaction limit per ledger_. The minimum value of 5 was + chosen to ensure the limit never gets so small that the ledger becomes + unusable. The "target" value of 50 was chosen so the limit never gets large + enough to invite abuse, but keeps up if the network stays healthy and + active. These exact values were chosen experimentally, and can easily + change in the future. +- _Expected ledger size growth and reduction percentages_. The growth + value of 20% was chosen to allow the limit to grow quickly as load + increases, but not so quickly as to allow bad actors to run unrestricted. + The reduction value of 50% was chosen to cause the limit to drop + significantly, but not so drastically that the limit cannot quickly + recover if the problem is temporary. These exact values were chosen + experimentally, and can easily change in the future. +- _Minimum `lastLedgerMedianFeeLevel`_. The value of 500 was chosen to + ensure that the first escalated fee was more significant and noticable + than what the default would allow. This exact value was chosen + experimentally, and can easily change in the future. +- _Transaction queue size limit_. The limit is computed based on the + base fee transaction limit per ledger, so that the queue can grow + automatically as the network's performance improves, allowing + more transactions per second, and thus more transactions per ledger + to process successfully. The limit of 20 ledgers was used to provide + a balance between resource (specifically memory) usage, and giving + transactions a realistic chance to be processed. The minimum size of + 2000 transactions was chosen to allow a decent functional backlog during + network congestion conditions. These exact values were + chosen experimentally, and can easily change in the future. +- _Maximum retries_. A transaction in the queue can attempt to apply + to the open ledger, but get a retry (`ter`) code up to 10 times, at + which point, it will be removed from the queue and dropped. The + value was chosen to be large enough to allow temporary failures to clear + up, but small enough that the queue doesn't fill up with stale + transactions which prevent lower fee level, but more likely to succeed, + transactions from queuing. +- _Maximum transactions per account_. A single account can have up to 10 + transactions in the queue at any given time. This is primarily to + mitigate the lost cost of broadcasting multiple transactions if one of + the earlier ones fails or is otherwise removed from the queue without + being applied to the open ledger. The value was chosen arbitrarily, and + can easily change in the future. +- _Minimum last ledger sequence buffer_. If a transaction has a + `LastLedgerSequence` value, and cannot be processed into the open + ledger, that `LastLedgerSequence` must be at least 2 more than the + sequence number of the open ledger to be considered for the queue. The + value was chosen to provide a balance between letting the user control + the lifespan of the transaction, and giving a queued transaction a + chance to get processed out of the queue before getting discarded, + particularly since it may have dependent transactions also in the queue, + which will never succeed if this one is discarded. +- _Replaced transaction fee increase_. Any transaction in the queue can be + replaced by another transaction with the same sequence number and at + least a 25% higher fee level. The 25% increase is intended to cover the + resource cost incurred by broadcasting the original transaction to the + network. This value was chosen experimentally, and can easily change in + the future. ### `fee` command @@ -287,6 +296,7 @@ ledger. It includes the sequence number of the current open ledger, but may not make sense if rippled is not synced to the network. Result format: + ``` { "result" : { @@ -319,13 +329,13 @@ without warning.** Up to two fields in `server_info` output are related to fee escalation. 1. `load_factor_fee_escalation`: The factor on base transaction cost -that a transaction must pay to get into the open ledger. This value can -change quickly as transactions are processed from the network and -ledgers are closed. If not escalated, the value is 1, so will not be -returned. + that a transaction must pay to get into the open ledger. This value can + change quickly as transactions are processed from the network and + ledgers are closed. If not escalated, the value is 1, so will not be + returned. 2. `load_factor_fee_queue`: If the queue is full, this is the factor on -base transaction cost that a transaction must pay to get into the queue. -If not full, the value is 1, so will not be returned. + base transaction cost that a transaction must pay to get into the queue. + If not full, the value is 1, so will not be returned. In all cases, the transaction fee must be high enough to overcome both `load_factor_fee_queue` and `load_factor` to be considered. It does not @@ -341,22 +351,21 @@ without warning.** Three fields in `server_state` output are related to fee escalation. 1. `load_factor_fee_escalation`: The factor on base transaction cost -that a transaction must pay to get into the open ledger. This value can -change quickly as transactions are processed from the network and -ledgers are closed. The ratio between this value and -`load_factor_fee_reference` determines the multiplier for transaction -fees to get into the current open ledger. + that a transaction must pay to get into the open ledger. This value can + change quickly as transactions are processed from the network and + ledgers are closed. The ratio between this value and + `load_factor_fee_reference` determines the multiplier for transaction + fees to get into the current open ledger. 2. `load_factor_fee_queue`: This is the factor on base transaction cost -that a transaction must pay to get into the queue. The ratio between -this value and `load_factor_fee_reference` determines the multiplier for -transaction fees to get into the transaction queue to be considered for -a later ledger. + that a transaction must pay to get into the queue. The ratio between + this value and `load_factor_fee_reference` determines the multiplier for + transaction fees to get into the transaction queue to be considered for + a later ledger. 3. `load_factor_fee_reference`: Like `load_base`, this is the baseline -that is used to scale fee escalation computations. + that is used to scale fee escalation computations. In all cases, the transaction fee must be high enough to overcome both `load_factor_fee_queue` and `load_factor` to be considered. It does not need to overcome `load_factor_fee_escalation`, though if it does not, it is more likely to be queued than immediately processed into the open ledger. - diff --git a/src/xrpld/app/misc/HashRouter.cpp b/src/xrpld/app/misc/HashRouter.cpp index dc87b2bce15..b241d6a98a8 100644 --- a/src/xrpld/app/misc/HashRouter.cpp +++ b/src/xrpld/app/misc/HashRouter.cpp @@ -65,7 +65,10 @@ HashRouter::addSuppressionPeerWithStatus(uint256 const& key, PeerShortID peer) } bool -HashRouter::addSuppressionPeer(uint256 const& key, PeerShortID peer, int& flags) +HashRouter::addSuppressionPeer( + uint256 const& key, + PeerShortID peer, + HashRouterFlags& flags) { std::lock_guard lock(mutex_); @@ -79,7 +82,7 @@ bool HashRouter::shouldProcess( uint256 const& key, PeerShortID peer, - int& flags, + HashRouterFlags& flags, std::chrono::seconds tx_interval) { std::lock_guard lock(mutex_); @@ -91,7 +94,7 @@ HashRouter::shouldProcess( return s.shouldProcess(suppressionMap_.clock().now(), tx_interval); } -int +HashRouterFlags HashRouter::getFlags(uint256 const& key) { std::lock_guard lock(mutex_); @@ -100,9 +103,10 @@ HashRouter::getFlags(uint256 const& key) } bool -HashRouter::setFlags(uint256 const& key, int flags) +HashRouter::setFlags(uint256 const& key, HashRouterFlags flags) { - XRPL_ASSERT(flags, "ripple::HashRouter::setFlags : valid input"); + XRPL_ASSERT( + static_cast(flags), "ripple::HashRouter::setFlags : valid input"); std::lock_guard lock(mutex_); diff --git a/src/xrpld/app/misc/HashRouter.h b/src/xrpld/app/misc/HashRouter.h index a13bcb9f8fb..60a0b011557 100644 --- a/src/xrpld/app/misc/HashRouter.h +++ b/src/xrpld/app/misc/HashRouter.h @@ -27,23 +27,63 @@ #include #include +#include namespace ripple { -// TODO convert these macros to int constants or an enum -#define SF_BAD 0x02 // Temporarily bad -#define SF_SAVED 0x04 -#define SF_HELD 0x08 // Held by LedgerMaster after potential processing failure -#define SF_TRUSTED 0x10 // comes from trusted source - -// Private flags, used internally in apply.cpp. -// Do not attempt to read, set, or reuse. -#define SF_PRIVATE1 0x0100 -#define SF_PRIVATE2 0x0200 -#define SF_PRIVATE3 0x0400 -#define SF_PRIVATE4 0x0800 -#define SF_PRIVATE5 0x1000 -#define SF_PRIVATE6 0x2000 +enum class HashRouterFlags : std::uint16_t { + // Public flags + UNDEFINED = 0x00, + BAD = 0x02, // Temporarily bad + SAVED = 0x04, + HELD = 0x08, // Held by LedgerMaster after potential processing failure + TRUSTED = 0x10, // Comes from a trusted source + + // Private flags (used internally in apply.cpp) + // Do not attempt to read, set, or reuse. + PRIVATE1 = 0x0100, + PRIVATE2 = 0x0200, + PRIVATE3 = 0x0400, + PRIVATE4 = 0x0800, + PRIVATE5 = 0x1000, + PRIVATE6 = 0x2000 +}; + +constexpr HashRouterFlags +operator|(HashRouterFlags lhs, HashRouterFlags rhs) +{ + return static_cast( + static_cast>(lhs) | + static_cast>(rhs)); +} + +constexpr HashRouterFlags& +operator|=(HashRouterFlags& lhs, HashRouterFlags rhs) +{ + lhs = lhs | rhs; + return lhs; +} + +constexpr HashRouterFlags +operator&(HashRouterFlags lhs, HashRouterFlags rhs) +{ + return static_cast( + static_cast>(lhs) & + static_cast>(rhs)); +} + +constexpr HashRouterFlags& +operator&=(HashRouterFlags& lhs, HashRouterFlags rhs) +{ + lhs = lhs & rhs; + return lhs; +} + +constexpr bool +any(HashRouterFlags flags) +{ + return static_cast>(flags) != 0; +} class Config; @@ -100,14 +140,14 @@ class HashRouter peers_.insert(peer); } - int + HashRouterFlags getFlags(void) const { return flags_; } void - setFlags(int flagsToSet) + setFlags(HashRouterFlags flagsToSet) { flags_ |= flagsToSet; } @@ -153,7 +193,7 @@ class HashRouter } private: - int flags_ = 0; + HashRouterFlags flags_ = HashRouterFlags::UNDEFINED; std::set peers_; // This could be generalized to a map, if more // than one flag needs to expire independently. @@ -189,14 +229,17 @@ class HashRouter addSuppressionPeerWithStatus(uint256 const& key, PeerShortID peer); bool - addSuppressionPeer(uint256 const& key, PeerShortID peer, int& flags); + addSuppressionPeer( + uint256 const& key, + PeerShortID peer, + HashRouterFlags& flags); // Add a peer suppression and return whether the entry should be processed bool shouldProcess( uint256 const& key, PeerShortID peer, - int& flags, + HashRouterFlags& flags, std::chrono::seconds tx_interval); /** Set the flags on a hash. @@ -204,9 +247,9 @@ class HashRouter @return `true` if the flags were changed. `false` if unchanged. */ bool - setFlags(uint256 const& key, int flags); + setFlags(uint256 const& key, HashRouterFlags flags); - int + HashRouterFlags getFlags(uint256 const& key); /** Determines whether the hashed item should be relayed. diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index 1b1bea3ad9c..3220ce99fcf 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -1206,7 +1207,7 @@ NetworkOPsImp::submitTransaction(std::shared_ptr const& iTrans) auto const txid = trans->getTransactionID(); auto const flags = app_.getHashRouter().getFlags(txid); - if ((flags & SF_BAD) != 0) + if ((flags & HashRouterFlags::BAD) != HashRouterFlags::UNDEFINED) { JLOG(m_journal.warn()) << "Submitted transaction cached bad"; return; @@ -1250,7 +1251,7 @@ NetworkOPsImp::preProcessTransaction(std::shared_ptr& transaction) { auto const newFlags = app_.getHashRouter().getFlags(transaction->getID()); - if ((newFlags & SF_BAD) != 0) + if ((newFlags & HashRouterFlags::BAD) != HashRouterFlags::UNDEFINED) { // cached bad JLOG(m_journal.warn()) << transaction->getID() << ": cached bad!\n"; @@ -1269,7 +1270,8 @@ NetworkOPsImp::preProcessTransaction(std::shared_ptr& transaction) { transaction->setStatus(INVALID); transaction->setResult(temINVALID_FLAG); - app_.getHashRouter().setFlags(transaction->getID(), SF_BAD); + app_.getHashRouter().setFlags( + transaction->getID(), HashRouterFlags::BAD); return false; } @@ -1288,7 +1290,8 @@ NetworkOPsImp::preProcessTransaction(std::shared_ptr& transaction) JLOG(m_journal.info()) << "Transaction has bad signature: " << reason; transaction->setStatus(INVALID); transaction->setResult(temBAD_SIGNATURE); - app_.getHashRouter().setFlags(transaction->getID(), SF_BAD); + app_.getHashRouter().setFlags( + transaction->getID(), HashRouterFlags::BAD); return false; } @@ -1411,7 +1414,8 @@ NetworkOPsImp::processTransactionSet(CanonicalTXSet const& set) JLOG(m_journal.trace()) << "Exception checking transaction: " << reason; } - app_.getHashRouter().setFlags(tx->getTransactionID(), SF_BAD); + app_.getHashRouter().setFlags( + tx->getTransactionID(), HashRouterFlags::BAD); continue; } @@ -1537,7 +1541,8 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) e.transaction->setResult(e.result); if (isTemMalformed(e.result)) - app_.getHashRouter().setFlags(e.transaction->getID(), SF_BAD); + app_.getHashRouter().setFlags( + e.transaction->getID(), HashRouterFlags::BAD); #ifdef DEBUG if (e.result != tesSUCCESS) @@ -1625,7 +1630,8 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) // (5) ledgers into the future. (Remember that an // unseated optional compares as less than all seated // values, so it has to be checked explicitly first.) - // 3. The SF_HELD flag is not set on the txID. (setFlags + // 3. The HashRouterFlags::BAD flag is not set on the txID. + // (setFlags // checks before setting. If the flag is set, it returns // false, which means it's been held once without one of // the other conditions, so don't hold it again. Time's @@ -1634,7 +1640,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) if (e.local || (ledgersLeft && ledgersLeft <= LocalTxs::holdLedgers) || app_.getHashRouter().setFlags( - e.transaction->getID(), SF_HELD)) + e.transaction->getID(), HashRouterFlags::HELD)) { // transaction should be held JLOG(m_journal.debug()) @@ -2409,6 +2415,7 @@ NetworkOPsImp::pubValidation(std::shared_ptr const& val) jvObj[jss::flags] = val->getFlags(); jvObj[jss::signing_time] = *(*val)[~sfSigningTime]; jvObj[jss::data] = strHex(val->getSerializer().slice()); + jvObj[jss::network_id] = app_.config().NETWORK_ID; if (auto version = (*val)[~sfServerVersion]) jvObj[jss::server_version] = std::to_string(*version); @@ -3113,6 +3120,8 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) jvObj[jss::ledger_time] = Json::Value::UInt( lpAccepted->info().closeTime.time_since_epoch().count()); + jvObj[jss::network_id] = app_.config().NETWORK_ID; + if (!lpAccepted->rules().enabled(featureXRPFees)) jvObj[jss::fee_ref] = Config::FEE_UNITS_DEPRECATED; jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped(); @@ -3258,6 +3267,7 @@ NetworkOPsImp::transJson( jvObj[jss::meta] = meta->get().getJson(JsonOptions::none); RPC::insertDeliveredAmount( jvObj[jss::meta], *ledger, transaction, meta->get()); + RPC::insertNFTSyntheticInJson(jvObj, transaction, meta->get()); RPC::insertMPTokenIssuanceID( jvObj[jss::meta], transaction, meta->get()); } @@ -4170,6 +4180,7 @@ NetworkOPsImp::subLedger(InfoSub::ref isrListener, Json::Value& jvResult) jvResult[jss::reserve_base] = lpClosed->fees().accountReserve(0).jsonClipped(); jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped(); + jvResult[jss::network_id] = app_.config().NETWORK_ID; } if ((mMode >= OperatingMode::SYNCING) && !isNeedNetworkLedger()) diff --git a/src/xrpld/app/misc/README.md b/src/xrpld/app/misc/README.md index 52e6e149342..2f9fff0ca30 100644 --- a/src/xrpld/app/misc/README.md +++ b/src/xrpld/app/misc/README.md @@ -71,18 +71,18 @@ Amendment must receive at least an 80% approval rate from validating nodes for a period of two weeks before being accepted. The following example outlines the process of an Amendment from its conception to approval and usage. -* A community member proposes to change transaction processing in some way. +- A community member proposes to change transaction processing in some way. The proposal is discussed amongst the community and receives its support creating a community or human consensus. -* Some members contribute their time and work to develop the Amendment. +- Some members contribute their time and work to develop the Amendment. -* A pull request is created and the new code is folded into a rippled build +- A pull request is created and the new code is folded into a rippled build and made available for use. -* The consensus process begins with the validating nodes. +- The consensus process begins with the validating nodes. -* If the Amendment holds an 80% majority for a two week period, nodes will begin +- If the Amendment holds an 80% majority for a two week period, nodes will begin including the transaction to enable it in their initial sets. Nodes may veto Amendments they consider undesirable by never announcing their @@ -112,7 +112,7 @@ enabled. Optional online deletion happens through the SHAMapStore. Records are deleted from disk based on ledger sequence number. These records reside in the -key-value database as well as in the SQLite ledger and transaction databases. +key-value database as well as in the SQLite ledger and transaction databases. Without online deletion storage usage grows without bounds. It can only be pruned by stopping, manually deleting data, and restarting the server. Online deletion requires less operator intervention to manage the server. @@ -142,14 +142,14 @@ server restarts. Configuration: -* In the [node_db] configuration section, an optional online_delete parameter is -set. If not set or if set to 0, online delete is disabled. Otherwise, the -setting defines number of ledgers between deletion cycles. -* Another optional parameter in [node_db] is that for advisory_delete. It is -disabled by default. If set to non-zero, requires an RPC call to activate the -deletion routine. -* online_delete must not be greater than the [ledger_history] parameter. -* [fetch_depth] will be silently set to equal the online_delete setting if -online_delete is greater than fetch_depth. -* In the [node_db] section, there is a performance tuning option, delete_batch, -which sets the maximum size in ledgers for each SQL DELETE query. +- In the [node_db] configuration section, an optional online_delete parameter is + set. If not set or if set to 0, online delete is disabled. Otherwise, the + setting defines number of ledgers between deletion cycles. +- Another optional parameter in [node_db] is that for advisory_delete. It is + disabled by default. If set to non-zero, requires an RPC call to activate the + deletion routine. +- online_delete must not be greater than the [ledger_history] parameter. +- [fetch_depth] will be silently set to equal the online_delete setting if + online_delete is greater than fetch_depth. +- In the [node_db] section, there is a performance tuning option, delete_batch, + which sets the maximum size in ledgers for each SQL DELETE query. diff --git a/src/xrpld/app/misc/ValidatorList.h b/src/xrpld/app/misc/ValidatorList.h index 4cb32282dbb..1f5d7288244 100644 --- a/src/xrpld/app/misc/ValidatorList.h +++ b/src/xrpld/app/misc/ValidatorList.h @@ -226,7 +226,7 @@ class ValidatorList TimeKeeper& timeKeeper_; boost::filesystem::path const dataPath_; beast::Journal const j_; - boost::shared_mutex mutable mutex_; + std::shared_mutex mutable mutex_; using lock_guard = std::lock_guard; using shared_lock = std::shared_lock; diff --git a/src/xrpld/app/misc/detail/AMMUtils.cpp b/src/xrpld/app/misc/detail/AMMUtils.cpp index ba4c741300a..b56ce2748e8 100644 --- a/src/xrpld/app/misc/detail/AMMUtils.cpp +++ b/src/xrpld/app/misc/detail/AMMUtils.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include #include #include @@ -464,4 +465,32 @@ isOnlyLiquidityProvider( return Unexpected(tecINTERNAL); // LCOV_EXCL_LINE } +Expected +verifyAndAdjustLPTokenBalance( + Sandbox& sb, + STAmount const& lpTokens, + std::shared_ptr& ammSle, + AccountID const& account) +{ + if (auto const res = isOnlyLiquidityProvider(sb, lpTokens.issue(), account); + !res) + return Unexpected(res.error()); + else if (res.value()) + { + if (withinRelativeDistance( + lpTokens, + ammSle->getFieldAmount(sfLPTokenBalance), + Number{1, -3})) + { + ammSle->setFieldAmount(sfLPTokenBalance, lpTokens); + sb.update(ammSle); + } + else + { + return Unexpected(tecAMM_INVALID_TOKENS); + } + } + return true; +} + } // namespace ripple diff --git a/src/xrpld/app/paths/RippleCalc.cpp b/src/xrpld/app/paths/RippleCalc.cpp index 4e472e07c83..9c438bdfa91 100644 --- a/src/xrpld/app/paths/RippleCalc.cpp +++ b/src/xrpld/app/paths/RippleCalc.cpp @@ -95,9 +95,6 @@ RippleCalc::rippleCalculate( return std::nullopt; }(); - bool const ownerPaysTransferFee = - view.rules().enabled(featureOwnerPaysFee); - try { flowOut = flow( @@ -108,7 +105,7 @@ RippleCalc::rippleCalculate( spsPaths, defaultPaths, partialPayment, - ownerPaysTransferFee, + false, OfferCrossing::no, limitQuality, sendMax, diff --git a/src/xrpld/app/paths/detail/AMMLiquidity.cpp b/src/xrpld/app/paths/detail/AMMLiquidity.cpp index 83894b2e76a..f24e67c7e1b 100644 --- a/src/xrpld/app/paths/detail/AMMLiquidity.cpp +++ b/src/xrpld/app/paths/detail/AMMLiquidity.cpp @@ -248,7 +248,7 @@ AMMLiquidity::getOffer( return offer; } - JLOG(j_.error()) << "AMMLiquidity::getOffer, failed " + JLOG(j_.debug()) << "AMMLiquidity::getOffer, no valid offer " << ammContext_.multiPath() << " " << ammContext_.curIters() << " " << (clobQuality ? clobQuality->rate() : STAmount{}) diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index 8d20a9900ca..554d2525f58 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -743,7 +743,6 @@ BookStep::forEachOffer( FlowOfferStream offers( sb, afView, book_, sb.parentCloseTime(), counter, j_); - bool const flowCross = afView.rules().enabled(featureFlowCross); bool offerAttempted = false; std::optional ofrQ; auto execOffer = [&](auto& offer) { @@ -760,8 +759,8 @@ BookStep::forEachOffer( // Make sure offer owner has authorization to own IOUs from issuer. // An account can always own XRP or their own IOUs. - if (flowCross && (!isXRP(offer.issueIn().currency)) && - (offer.owner() != offer.issueIn().account)) + if (!isXRP(offer.issueIn().currency) && + offer.owner() != offer.issueIn().account) { auto const& issuerID = offer.issueIn().account; auto const issuer = afView.read(keylet::account(issuerID)); diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index 4dc9cbf20d2..5e62a289a3d 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -423,7 +423,7 @@ DirectIPaymentStep::check( !((*sleLine)[sfFlags] & authField) && (*sleLine)[sfBalance] == beast::zero) { - JLOG(j_.warn()) + JLOG(j_.debug()) << "DirectStepI: can't receive IOUs from issuer without auth." << " src: " << src_; return terNO_AUTH; diff --git a/src/xrpld/app/rdb/README.md b/src/xrpld/app/rdb/README.md index 81aaa32f2cf..a50bb395c15 100644 --- a/src/xrpld/app/rdb/README.md +++ b/src/xrpld/app/rdb/README.md @@ -2,8 +2,8 @@ The guiding principles of the Relational Database Interface are summarized below: -* All hard-coded SQL statements should be stored in the [files](#source-files) under the `xrpld/app/rdb` directory. With the exception of test modules, no hard-coded SQL should be added to any other file in rippled. -* The base class `RelationalDatabase` is inherited by derived classes that each provide an interface for operating on distinct relational database systems. +- All hard-coded SQL statements should be stored in the [files](#source-files) under the `xrpld/app/rdb` directory. With the exception of test modules, no hard-coded SQL should be added to any other file in rippled. +- The base class `RelationalDatabase` is inherited by derived classes that each provide an interface for operating on distinct relational database systems. ## Overview @@ -45,36 +45,34 @@ src/xrpld/app/rdb/ ``` ### File Contents -| File | Contents | -| ----------- | ----------- | -| `Node.[h\|cpp]` | Defines/Implements methods used by `SQLiteDatabase` for interacting with SQLite node databases| -|`SQLiteDatabase.[h\|cpp]`| Defines/Implements the class `SQLiteDatabase`/`SQLiteDatabaseImp` which inherits from `RelationalDatabase` and is used to operate on the main stores | -| `PeerFinder.[h\|cpp]` | Defines/Implements methods for interacting with the PeerFinder SQLite database | -|`RelationalDatabase.cpp`| Implements the static method `RelationalDatabase::init` which is used to initialize an instance of `RelationalDatabase` | -| `RelationalDatabase.h` | Defines the abstract class `RelationalDatabase`, the primary class of the Relational Database Interface | -| `State.[h\|cpp]` | Defines/Implements methods for interacting with the State SQLite database which concerns ledger deletion and database rotation | -| `Vacuum.[h\|cpp]` | Defines/Implements a method for performing the `VACUUM` operation on SQLite databases | -| `Wallet.[h\|cpp]` | Defines/Implements methods for interacting with Wallet SQLite databases | + +| File | Contents | +| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Node.[h\|cpp]` | Defines/Implements methods used by `SQLiteDatabase` for interacting with SQLite node databases | +| `SQLiteDatabase.[h\|cpp]` | Defines/Implements the class `SQLiteDatabase`/`SQLiteDatabaseImp` which inherits from `RelationalDatabase` and is used to operate on the main stores | +| `PeerFinder.[h\|cpp]` | Defines/Implements methods for interacting with the PeerFinder SQLite database | +| `RelationalDatabase.cpp` | Implements the static method `RelationalDatabase::init` which is used to initialize an instance of `RelationalDatabase` | +| `RelationalDatabase.h` | Defines the abstract class `RelationalDatabase`, the primary class of the Relational Database Interface | +| `State.[h\|cpp]` | Defines/Implements methods for interacting with the State SQLite database which concerns ledger deletion and database rotation | +| `Vacuum.[h\|cpp]` | Defines/Implements a method for performing the `VACUUM` operation on SQLite databases | +| `Wallet.[h\|cpp]` | Defines/Implements methods for interacting with Wallet SQLite databases | ## Classes -The abstract class `RelationalDatabase` is the primary class of the Relational Database Interface and is defined in the eponymous header file. This class provides a static method `init()` which, when invoked, creates a concrete instance of a derived class whose type is specified by the system configuration. All other methods in the class are virtual. Presently there exist two classes that derive from `RelationalDatabase`, namely `SQLiteDatabase` and `PostgresDatabase`. +The abstract class `RelationalDatabase` is the primary class of the Relational Database Interface and is defined in the eponymous header file. This class provides a static method `init()` which, when invoked, creates a concrete instance of a derived class whose type is specified by the system configuration. All other methods in the class are virtual. Presently there exist two classes that derive from `RelationalDatabase`, namely `SQLiteDatabase` and `PostgresDatabase`. ## Database Methods The Relational Database Interface provides three categories of methods for interacting with databases: -* Free functions for interacting with SQLite databases used by various components of the software. These methods feature a `soci::session` parameter which facilitates connecting to SQLite databases, and are defined and implemented in the following files: - - * `PeerFinder.[h\|cpp]` - * `State.[h\|cpp]` - * `Vacuum.[h\|cpp]` - * `Wallet.[h\|cpp]` - - -* Free functions used exclusively by `SQLiteDatabaseImp` for interacting with SQLite databases owned by the node store. Unlike the free functions in the files listed above, these are not intended to be invoked directly by clients. Rather, these methods are invoked by derived instances of `RelationalDatabase`. These methods are defined in the following files: +- Free functions for interacting with SQLite databases used by various components of the software. These methods feature a `soci::session` parameter which facilitates connecting to SQLite databases, and are defined and implemented in the following files: - * `Node.[h|cpp]` +- `PeerFinder.[h\|cpp]` +- `State.[h\|cpp]` +- `Vacuum.[h\|cpp]` +- `Wallet.[h\|cpp]` +- Free functions used exclusively by `SQLiteDatabaseImp` for interacting with SQLite databases owned by the node store. Unlike the free functions in the files listed above, these are not intended to be invoked directly by clients. Rather, these methods are invoked by derived instances of `RelationalDatabase`. These methods are defined in the following files: + - `Node.[h|cpp]` -* Member functions of `RelationalDatabase`, `SQLiteDatabase`, and `PostgresDatabase` which are used to access the node store. +- Member functions of `RelationalDatabase`, `SQLiteDatabase`, and `PostgresDatabase` which are used to access the node store. diff --git a/src/xrpld/app/tx/detail/AMMClawback.cpp b/src/xrpld/app/tx/detail/AMMClawback.cpp index 64a42374ec5..07c51517277 100644 --- a/src/xrpld/app/tx/detail/AMMClawback.cpp +++ b/src/xrpld/app/tx/detail/AMMClawback.cpp @@ -151,6 +151,20 @@ AMMClawback::applyGuts(Sandbox& sb) if (!accountSle) return tecINTERNAL; // LCOV_EXCL_LINE + if (sb.rules().enabled(fixAMMClawbackRounding)) + { + // retrieve LP token balance inside the amendment gate to avoid + // inconsistent error behavior + auto const lpTokenBalance = ammLPHolds(sb, *ammSle, holder, j_); + if (lpTokenBalance == beast::zero) + return tecAMM_BALANCE; + + if (auto const res = verifyAndAdjustLPTokenBalance( + sb, lpTokenBalance, ammSle, holder); + !res) + return res.error(); // LCOV_EXCL_LINE + } + auto const expected = ammHolds( sb, *ammSle, @@ -248,10 +262,11 @@ AMMClawback::equalWithdrawMatchingOneAmount( STAmount const& amount) { auto frac = Number{amount} / amountBalance; - auto const amount2Withdraw = amount2Balance * frac; + auto amount2Withdraw = amount2Balance * frac; auto const lpTokensWithdraw = toSTAmount(lptAMMBalance.issue(), lptAMMBalance * frac); + if (lpTokensWithdraw > holdLPtokens) // if lptoken balance less than what the issuer intended to clawback, // clawback all the tokens. Because we are doing a two-asset withdrawal, @@ -272,6 +287,42 @@ AMMClawback::equalWithdrawMatchingOneAmount( mPriorBalance, ctx_.journal); + auto const& rules = sb.rules(); + if (rules.enabled(fixAMMClawbackRounding)) + { + auto tokensAdj = + getRoundedLPTokens(rules, lptAMMBalance, frac, IsDeposit::No); + + // LCOV_EXCL_START + if (tokensAdj == beast::zero) + return { + tecAMM_INVALID_TOKENS, STAmount{}, STAmount{}, std::nullopt}; + // LCOV_EXCL_STOP + + frac = adjustFracByTokens(rules, lptAMMBalance, tokensAdj, frac); + auto amount2Rounded = + getRoundedAsset(rules, amount2Balance, frac, IsDeposit::No); + + auto amountRounded = + getRoundedAsset(rules, amountBalance, frac, IsDeposit::No); + + return AMMWithdraw::withdraw( + sb, + ammSle, + ammAccount, + holder, + amountBalance, + amountRounded, + amount2Rounded, + lptAMMBalance, + tokensAdj, + 0, + FreezeHandling::fhIGNORE_FREEZE, + WithdrawAll::No, + mPriorBalance, + ctx_.journal); + } + // Because we are doing a two-asset withdrawal, // tfee is actually not used, so pass tfee as 0. return AMMWithdraw::withdraw( diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp index 69243f3f488..2ad1a19df56 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.cpp +++ b/src/xrpld/app/tx/detail/AMMWithdraw.cpp @@ -311,24 +311,9 @@ AMMWithdraw::applyGuts(Sandbox& sb) if (sb.rules().enabled(fixAMMv1_1)) { if (auto const res = - isOnlyLiquidityProvider(sb, lpTokens.issue(), account_); + verifyAndAdjustLPTokenBalance(sb, lpTokens, ammSle, account_); !res) return {res.error(), false}; - else if (res.value()) - { - if (withinRelativeDistance( - lpTokens, - ammSle->getFieldAmount(sfLPTokenBalance), - Number{1, -3})) - { - ammSle->setFieldAmount(sfLPTokenBalance, lpTokens); - sb.update(ammSle); - } - else - { - return {tecAMM_INVALID_TOKENS, false}; - } - } } auto const tfee = getTradingFee(ctx_.view(), *ammSle, account_); diff --git a/src/xrpld/app/tx/detail/CreateOffer.cpp b/src/xrpld/app/tx/detail/CreateOffer.cpp index 7ccecd7a472..3cfae92cbde 100644 --- a/src/xrpld/app/tx/detail/CreateOffer.cpp +++ b/src/xrpld/app/tx/detail/CreateOffer.cpp @@ -26,9 +26,9 @@ #include #include #include -#include #include #include +#include #include namespace ripple { @@ -50,12 +50,6 @@ CreateOffer::preflight(PreflightContext const& ctx) !ctx.rules.enabled(featurePermissionedDEX)) return temDISABLED; - // Permissioned offers should use the PE (which must be enabled by - // featureFlowCross amendment) - if (ctx.rules.enabled(featurePermissionedDEX) && - !ctx.rules.enabled(featureFlowCross)) - return temDISABLED; - if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; @@ -317,422 +311,6 @@ CreateOffer::checkAcceptAsset( return tesSUCCESS; } -bool -CreateOffer::dry_offer(ApplyView& view, Offer const& offer) -{ - if (offer.fully_consumed()) - return true; - auto const amount = accountFunds( - view, - offer.owner(), - offer.amount().out, - fhZERO_IF_FROZEN, - ctx_.app.journal("View")); - return (amount <= beast::zero); -} - -std::pair -CreateOffer::select_path( - bool have_direct, - OfferStream const& direct, - bool have_bridge, - OfferStream const& leg1, - OfferStream const& leg2) -{ - // If we don't have any viable path, why are we here?! - XRPL_ASSERT( - have_direct || have_bridge, - "ripple::CreateOffer::select_path : valid inputs"); - - // If there's no bridged path, the direct is the best by default. - if (!have_bridge) - return std::make_pair(true, direct.tip().quality()); - - Quality const bridged_quality( - composed_quality(leg1.tip().quality(), leg2.tip().quality())); - - if (have_direct) - { - // We compare the quality of the composed quality of the bridged - // offers and compare it against the direct offer to pick the best. - Quality const direct_quality(direct.tip().quality()); - - if (bridged_quality < direct_quality) - return std::make_pair(true, direct_quality); - } - - // Either there was no direct offer, or it didn't have a better quality - // than the bridge. - return std::make_pair(false, bridged_quality); -} - -bool -CreateOffer::reachedOfferCrossingLimit(Taker const& taker) const -{ - auto const crossings = - taker.get_direct_crossings() + (2 * taker.get_bridge_crossings()); - - // The crossing limit is part of the Ripple protocol and - // changing it is a transaction-processing change. - return crossings >= 850; -} - -std::pair -CreateOffer::bridged_cross( - Taker& taker, - ApplyView& view, - ApplyView& view_cancel, - NetClock::time_point const when) -{ - auto const& takerAmount = taker.original_offer(); - - XRPL_ASSERT( - !isXRP(takerAmount.in) && !isXRP(takerAmount.out), - "ripple::CreateOffer::bridged_cross : neither is XRP"); - - if (isXRP(takerAmount.in) || isXRP(takerAmount.out)) - Throw("Bridging with XRP and an endpoint."); - - OfferStream offers_direct( - view, - view_cancel, - Book(taker.issue_in(), taker.issue_out(), std::nullopt), - when, - stepCounter_, - j_); - - OfferStream offers_leg1( - view, - view_cancel, - Book(taker.issue_in(), xrpIssue(), std::nullopt), - when, - stepCounter_, - j_); - - OfferStream offers_leg2( - view, - view_cancel, - Book(xrpIssue(), taker.issue_out(), std::nullopt), - when, - stepCounter_, - j_); - - TER cross_result = tesSUCCESS; - - // Note the subtle distinction here: self-offers encountered in the - // bridge are taken, but self-offers encountered in the direct book - // are not. - bool have_bridge = offers_leg1.step() && offers_leg2.step(); - bool have_direct = step_account(offers_direct, taker); - int count = 0; - - auto viewJ = ctx_.app.journal("View"); - - // Modifying the order or logic of the operations in the loop will cause - // a protocol breaking change. - while (have_direct || have_bridge) - { - bool leg1_consumed = false; - bool leg2_consumed = false; - bool direct_consumed = false; - - auto const [use_direct, quality] = select_path( - have_direct, offers_direct, have_bridge, offers_leg1, offers_leg2); - - // We are always looking at the best quality; we are done with - // crossing as soon as we cross the quality boundary. - if (taker.reject(quality)) - break; - - count++; - - if (use_direct) - { - if (auto stream = j_.debug()) - { - stream << count << " Direct:"; - stream << " offer: " << offers_direct.tip(); - stream << " in: " << offers_direct.tip().amount().in; - stream << " out: " << offers_direct.tip().amount().out; - stream << " owner: " << offers_direct.tip().owner(); - stream << " funds: " - << accountFunds( - view, - offers_direct.tip().owner(), - offers_direct.tip().amount().out, - fhIGNORE_FREEZE, - viewJ); - } - - cross_result = taker.cross(offers_direct.tip()); - - JLOG(j_.debug()) << "Direct Result: " << transToken(cross_result); - - if (dry_offer(view, offers_direct.tip())) - { - direct_consumed = true; - have_direct = step_account(offers_direct, taker); - } - } - else - { - if (auto stream = j_.debug()) - { - auto const owner1_funds_before = accountFunds( - view, - offers_leg1.tip().owner(), - offers_leg1.tip().amount().out, - fhIGNORE_FREEZE, - viewJ); - - auto const owner2_funds_before = accountFunds( - view, - offers_leg2.tip().owner(), - offers_leg2.tip().amount().out, - fhIGNORE_FREEZE, - viewJ); - - stream << count << " Bridge:"; - stream << " offer1: " << offers_leg1.tip(); - stream << " in: " << offers_leg1.tip().amount().in; - stream << " out: " << offers_leg1.tip().amount().out; - stream << " owner: " << offers_leg1.tip().owner(); - stream << " funds: " << owner1_funds_before; - stream << " offer2: " << offers_leg2.tip(); - stream << " in: " << offers_leg2.tip().amount().in; - stream << " out: " << offers_leg2.tip().amount().out; - stream << " owner: " << offers_leg2.tip().owner(); - stream << " funds: " << owner2_funds_before; - } - - cross_result = taker.cross(offers_leg1.tip(), offers_leg2.tip()); - - JLOG(j_.debug()) << "Bridge Result: " << transToken(cross_result); - - if (view.rules().enabled(fixTakerDryOfferRemoval)) - { - // have_bridge can be true the next time 'round only if - // neither of the OfferStreams are dry. - leg1_consumed = dry_offer(view, offers_leg1.tip()); - if (leg1_consumed) - have_bridge &= offers_leg1.step(); - - leg2_consumed = dry_offer(view, offers_leg2.tip()); - if (leg2_consumed) - have_bridge &= offers_leg2.step(); - } - else - { - // This old behavior may leave an empty offer in the book for - // the second leg. - if (dry_offer(view, offers_leg1.tip())) - { - leg1_consumed = true; - have_bridge = (have_bridge && offers_leg1.step()); - } - if (dry_offer(view, offers_leg2.tip())) - { - leg2_consumed = true; - have_bridge = (have_bridge && offers_leg2.step()); - } - } - } - - if (cross_result != tesSUCCESS) - { - cross_result = tecFAILED_PROCESSING; - break; - } - - if (taker.done()) - { - JLOG(j_.debug()) << "The taker reports he's done during crossing!"; - break; - } - - if (reachedOfferCrossingLimit(taker)) - { - JLOG(j_.debug()) << "The offer crossing limit has been exceeded!"; - break; - } - - // Postcondition: If we aren't done, then we *must* have consumed at - // least one offer fully. - XRPL_ASSERT( - direct_consumed || leg1_consumed || leg2_consumed, - "ripple::CreateOffer::bridged_cross : consumed an offer"); - - if (!direct_consumed && !leg1_consumed && !leg2_consumed) - Throw( - "bridged crossing: nothing was fully consumed."); - } - - return std::make_pair(cross_result, taker.remaining_offer()); -} - -std::pair -CreateOffer::direct_cross( - Taker& taker, - ApplyView& view, - ApplyView& view_cancel, - NetClock::time_point const when) -{ - OfferStream offers( - view, - view_cancel, - Book(taker.issue_in(), taker.issue_out(), std::nullopt), - when, - stepCounter_, - j_); - - TER cross_result(tesSUCCESS); - int count = 0; - - bool have_offer = step_account(offers, taker); - - // Modifying the order or logic of the operations in the loop will cause - // a protocol breaking change. - while (have_offer) - { - bool direct_consumed = false; - auto& offer(offers.tip()); - - // We are done with crossing as soon as we cross the quality boundary - if (taker.reject(offer.quality())) - break; - - count++; - - if (auto stream = j_.debug()) - { - stream << count << " Direct:"; - stream << " offer: " << offer; - stream << " in: " << offer.amount().in; - stream << " out: " << offer.amount().out; - stream << "quality: " << offer.quality(); - stream << " owner: " << offer.owner(); - stream << " funds: " - << accountFunds( - view, - offer.owner(), - offer.amount().out, - fhIGNORE_FREEZE, - ctx_.app.journal("View")); - } - - cross_result = taker.cross(offer); - - JLOG(j_.debug()) << "Direct Result: " << transToken(cross_result); - - if (dry_offer(view, offer)) - { - direct_consumed = true; - have_offer = step_account(offers, taker); - } - - if (cross_result != tesSUCCESS) - { - cross_result = tecFAILED_PROCESSING; - break; - } - - if (taker.done()) - { - JLOG(j_.debug()) << "The taker reports he's done during crossing!"; - break; - } - - if (reachedOfferCrossingLimit(taker)) - { - JLOG(j_.debug()) << "The offer crossing limit has been exceeded!"; - break; - } - - // Postcondition: If we aren't done, then we *must* have consumed the - // offer on the books fully! - XRPL_ASSERT( - direct_consumed, - "ripple::CreateOffer::direct_cross : consumed an offer"); - - if (!direct_consumed) - Throw( - "direct crossing: nothing was fully consumed."); - } - - return std::make_pair(cross_result, taker.remaining_offer()); -} - -// Step through the stream for as long as possible, skipping any offers -// that are from the taker or which cross the taker's threshold. -// Return false if the is no offer in the book, true otherwise. -bool -CreateOffer::step_account(OfferStream& stream, Taker const& taker) -{ - while (stream.step()) - { - auto const& offer = stream.tip(); - - // This offer at the tip crosses the taker's threshold. We're done. - if (taker.reject(offer.quality())) - return true; - - // This offer at the tip is not from the taker. We're done. - if (offer.owner() != taker.account()) - return true; - } - - // We ran out of offers. Can't advance. - return false; -} - -// Fill as much of the offer as possible by consuming offers -// already on the books. Return the status and the amount of -// the offer to left unfilled. -std::pair -CreateOffer::takerCross( - Sandbox& sb, - Sandbox& sbCancel, - Amounts const& takerAmount) -{ - NetClock::time_point const when = sb.parentCloseTime(); - - beast::WrappedSink takerSink(j_, "Taker "); - - Taker taker( - cross_type_, - sb, - account_, - takerAmount, - ctx_.tx.getFlags(), - beast::Journal(takerSink)); - - // If the taker is unfunded before we begin crossing - // there's nothing to do - just return an error. - // - // We check this in preclaim, but when selling XRP - // charged fees can cause a user's available balance - // to go to 0 (by causing it to dip below the reserve) - // so we check this case again. - if (taker.unfunded()) - { - JLOG(j_.debug()) << "Not crossing: taker is unfunded."; - return {tecUNFUNDED_OFFER, takerAmount}; - } - - try - { - if (cross_type_ == CrossType::IouToIou) - return bridged_cross(taker, sb, sbCancel, when); - - return direct_cross(taker, sb, sbCancel, when); - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "Exception during offer crossing: " << e.what(); - return {tecINTERNAL, taker.remaining_offer()}; - } -} - std::pair CreateOffer::flowCross( PaymentSandbox& psb, @@ -937,32 +515,6 @@ CreateOffer::flowCross( return {tecINTERNAL, takerAmount}; } -std::pair -CreateOffer::cross( - Sandbox& sb, - Sandbox& sbCancel, - Amounts const& takerAmount, - std::optional const& domainID) -{ - if (sb.rules().enabled(featureFlowCross)) - { - PaymentSandbox psbFlow{&sb}; - PaymentSandbox psbCancelFlow{&sbCancel}; - auto const ret = - flowCross(psbFlow, psbCancelFlow, takerAmount, domainID); - psbFlow.apply(sb); - psbCancelFlow.apply(sbCancel); - return ret; - } - - Sandbox sbTaker{&sb}; - Sandbox sbCancelTaker{&sbCancel}; - auto const ret = takerCross(sbTaker, sbCancelTaker, takerAmount); - sbTaker.apply(sb); - sbCancelTaker.apply(sbCancel); - return ret; -} - std::string CreateOffer::format_amount(STAmount const& amount) { @@ -972,20 +524,6 @@ CreateOffer::format_amount(STAmount const& amount) return txt; } -void -CreateOffer::preCompute() -{ - cross_type_ = CrossType::IouToIou; - bool const pays_xrp = ctx_.tx.getFieldAmount(sfTakerPays).native(); - bool const gets_xrp = ctx_.tx.getFieldAmount(sfTakerGets).native(); - if (pays_xrp && !gets_xrp) - cross_type_ = CrossType::IouToXrp; - else if (gets_xrp && !pays_xrp) - cross_type_ = CrossType::XrpToIou; - - return Transactor::preCompute(); -} - TER CreateOffer::applyHybrid( Sandbox& sb, @@ -1149,11 +687,6 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) // We reverse pays and gets because during crossing we are taking. Amounts const takerAmount(saTakerGets, saTakerPays); - // The amount of the offer that is unfilled after crossing has been - // performed. It may be equal to the original amount (didn't cross), - // empty (fully crossed), or something in-between. - Amounts place_offer; - JLOG(j_.debug()) << "Attempting cross: " << to_string(takerAmount.in.issue()) << " -> " << to_string(takerAmount.out.issue()); @@ -1166,8 +699,17 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) stream << " out: " << format_amount(takerAmount.out); } + // The amount of the offer that is unfilled after crossing has been + // performed. It may be equal to the original amount (didn't cross), + // empty (fully crossed), or something in-between. + Amounts place_offer; + PaymentSandbox psbFlow{&sb}; + PaymentSandbox psbCancelFlow{&sbCancel}; + std::tie(result, place_offer) = - cross(sb, sbCancel, takerAmount, domainID); + flowCross(psbFlow, psbCancelFlow, takerAmount, domainID); + psbFlow.apply(sb); + psbCancelFlow.apply(sbCancel); // We expect the implementation of cross to succeed // or give a tec. diff --git a/src/xrpld/app/tx/detail/CreateOffer.h b/src/xrpld/app/tx/detail/CreateOffer.h index 9b35062d8a7..6e3d6145b15 100644 --- a/src/xrpld/app/tx/detail/CreateOffer.h +++ b/src/xrpld/app/tx/detail/CreateOffer.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_TX_CREATEOFFER_H_INCLUDED #define RIPPLE_TX_CREATEOFFER_H_INCLUDED -#include -#include #include +#include + namespace ripple { class PaymentSandbox; @@ -36,8 +36,7 @@ class CreateOffer : public Transactor static constexpr ConsequencesFactoryType ConsequencesFactory{Custom}; /** Construct a Transactor subclass that creates an offer in the ledger. */ - explicit CreateOffer(ApplyContext& ctx) - : Transactor(ctx), stepCounter_(1000, j_) + explicit CreateOffer(ApplyContext& ctx) : Transactor(ctx) { } @@ -52,10 +51,6 @@ class CreateOffer : public Transactor static TER preclaim(PreclaimContext const& ctx); - /** Gather information beyond what the Transactor base class gathers. */ - void - preCompute() override; - /** Precondition: fee collection is likely. Attempt to create the offer. */ TER doApply() override; @@ -73,49 +68,6 @@ class CreateOffer : public Transactor beast::Journal const j, Issue const& issue); - bool - dry_offer(ApplyView& view, Offer const& offer); - - static std::pair - select_path( - bool have_direct, - OfferStream const& direct, - bool have_bridge, - OfferStream const& leg1, - OfferStream const& leg2); - - std::pair - bridged_cross( - Taker& taker, - ApplyView& view, - ApplyView& view_cancel, - NetClock::time_point const when); - - std::pair - direct_cross( - Taker& taker, - ApplyView& view, - ApplyView& view_cancel, - NetClock::time_point const when); - - // Step through the stream for as long as possible, skipping any offers - // that are from the taker or which cross the taker's threshold. - // Return false if the is no offer in the book, true otherwise. - static bool - step_account(OfferStream& stream, Taker const& taker); - - // True if the number of offers that have been crossed - // exceeds the limit. - bool - reachedOfferCrossingLimit(Taker const& taker) const; - - // Fill offer as much as possible by consuming offers already on the books, - // and adjusting account balances accordingly. - // - // Charges fees on top to taker. - std::pair - takerCross(Sandbox& sb, Sandbox& sbCancel, Amounts const& takerAmount); - // Use the payment flow code to perform offer crossing. std::pair flowCross( @@ -124,17 +76,6 @@ class CreateOffer : public Transactor Amounts const& takerAmount, std::optional const& domainID); - // Temporary - // This is a central location that invokes both versions of cross - // so the results can be compared. Eventually this layer will be - // removed once flowCross is determined to be stable. - std::pair - cross( - Sandbox& sb, - Sandbox& sbCancel, - Amounts const& takerAmount, - std::optional const& domainID); - static std::string format_amount(STAmount const& amount); @@ -146,13 +87,6 @@ class CreateOffer : public Transactor STAmount const& saTakerPays, STAmount const& saTakerGets, std::function)> const& setDir); - -private: - // What kind of offer we are placing - CrossType cross_type_; - - // The number of steps to take through order books while crossing - OfferStream::StepCounter stepCounter_; }; using OfferCreate = CreateOffer; diff --git a/src/xrpld/app/tx/detail/DeleteAccount.cpp b/src/xrpld/app/tx/detail/DeleteAccount.cpp index 7aa47e05f38..4311aa79a8d 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.cpp +++ b/src/xrpld/app/tx/detail/DeleteAccount.cpp @@ -58,7 +58,8 @@ DeleteAccount::preflight(PreflightContext const& ctx) // An account cannot be deleted and give itself the resulting XRP. return temDST_IS_SRC; - if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err)) + if (auto const err = credentials::checkFields(ctx.tx, ctx.j); + !isTesSuccess(err)) return err; return preflight2(ctx); @@ -241,7 +242,8 @@ DeleteAccount::preclaim(PreclaimContext const& ctx) return tecDST_TAG_NEEDED; // If credentials are provided - check them anyway - if (auto const err = credentials::valid(ctx, account); !isTesSuccess(err)) + if (auto const err = credentials::valid(ctx.tx, ctx.view, account, ctx.j); + !isTesSuccess(err)) return err; // if credentials then postpone auth check to doApply, to check for expired @@ -376,7 +378,8 @@ DeleteAccount::doApply() if (ctx_.view().rules().enabled(featureDepositAuth) && ctx_.tx.isFieldPresent(sfCredentialIDs)) { - if (auto err = verifyDepositPreauth(ctx_, account_, dstID, dst); + if (auto err = verifyDepositPreauth( + ctx_.tx, ctx_.view(), account_, dstID, dst, ctx_.journal); !isTesSuccess(err)) return err; } diff --git a/src/xrpld/app/tx/detail/Escrow.cpp b/src/xrpld/app/tx/detail/Escrow.cpp index 75080da9a5c..dd0ffac7787 100644 --- a/src/xrpld/app/tx/detail/Escrow.cpp +++ b/src/xrpld/app/tx/detail/Escrow.cpp @@ -34,13 +34,13 @@ #include #include +namespace ripple { + // During an EscrowFinish, the transaction must specify both // a condition and a fulfillment. We track whether that // fulfillment matches and validates the condition. -#define SF_CF_INVALID SF_PRIVATE5 -#define SF_CF_VALID SF_PRIVATE6 - -namespace ripple { +constexpr HashRouterFlags SF_CF_INVALID = HashRouterFlags::PRIVATE5; +constexpr HashRouterFlags SF_CF_VALID = HashRouterFlags::PRIVATE6; /* Escrow @@ -315,14 +315,14 @@ escrowCreatePreclaimHelper( // authorized auto const& mptIssue = amount.get(); if (auto const ter = - requireAuth(ctx.view, mptIssue, account, MPTAuthType::WeakAuth); + requireAuth(ctx.view, mptIssue, account, AuthType::WeakAuth); ter != tesSUCCESS) return ter; // If the issuer has requireAuth set, check if the destination is // authorized if (auto const ter = - requireAuth(ctx.view, mptIssue, dest, MPTAuthType::WeakAuth); + requireAuth(ctx.view, mptIssue, dest, AuthType::WeakAuth); ter != tesSUCCESS) return ter; @@ -663,7 +663,7 @@ EscrowFinish::preflight(PreflightContext const& ctx) // If we haven't checked the condition, check it // now. Whether it passes or not isn't important // in preflight. - if (!(flags & (SF_CF_INVALID | SF_CF_VALID))) + if (!any(flags & (SF_CF_INVALID | SF_CF_VALID))) { if (checkCondition(*fb, *cb)) router.setFlags(id, SF_CF_VALID); @@ -672,7 +672,8 @@ EscrowFinish::preflight(PreflightContext const& ctx) } } - if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err)) + if (auto const err = credentials::checkFields(ctx.tx, ctx.j); + !isTesSuccess(err)) return err; return tesSUCCESS; @@ -745,7 +746,7 @@ escrowFinishPreclaimHelper( // authorized auto const& mptIssue = amount.get(); if (auto const ter = - requireAuth(ctx.view, mptIssue, dest, MPTAuthType::WeakAuth); + requireAuth(ctx.view, mptIssue, dest, AuthType::WeakAuth); ter != tesSUCCESS) return ter; @@ -761,7 +762,8 @@ EscrowFinish::preclaim(PreclaimContext const& ctx) { if (ctx.view.rules().enabled(featureCredentials)) { - if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); + if (auto const err = + credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j); !isTesSuccess(err)) return err; } @@ -1062,7 +1064,7 @@ EscrowFinish::doApply() // It's unlikely that the results of the check will // expire from the hash router, but if it happens, // simply re-run the check. - if (cb && !(flags & (SF_CF_INVALID | SF_CF_VALID))) + if (cb && !any(flags & (SF_CF_INVALID | SF_CF_VALID))) { auto const fb = ctx_.tx[~sfFulfillment]; @@ -1079,7 +1081,7 @@ EscrowFinish::doApply() // If the check failed, then simply return an error // and don't look at anything else. - if (flags & SF_CF_INVALID) + if (any(flags & SF_CF_INVALID)) return tecCRYPTOCONDITION_ERROR; // Check against condition in the ledger entry: @@ -1107,7 +1109,8 @@ EscrowFinish::doApply() if (ctx_.view().rules().enabled(featureDepositAuth)) { - if (auto err = verifyDepositPreauth(ctx_, account_, destID, sled); + if (auto err = verifyDepositPreauth( + ctx_.tx, ctx_.view(), account_, destID, sled, ctx_.journal); !isTesSuccess(err)) return err; } @@ -1256,7 +1259,7 @@ escrowCancelPreclaimHelper( // authorized auto const& mptIssue = amount.get(); if (auto const ter = - requireAuth(ctx.view, mptIssue, account, MPTAuthType::WeakAuth); + requireAuth(ctx.view, mptIssue, account, AuthType::WeakAuth); ter != tesSUCCESS) return ter; diff --git a/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp b/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp index 77b21b65f36..77fe19a287b 100644 --- a/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp +++ b/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp @@ -175,126 +175,18 @@ MPTokenAuthorize::createMPToken( return tesSUCCESS; } -TER -MPTokenAuthorize::authorize( - ApplyView& view, - beast::Journal journal, - MPTAuthorizeArgs const& args) -{ - auto const sleAcct = view.peek(keylet::account(args.account)); - if (!sleAcct) - return tecINTERNAL; - - // If the account that submitted the tx is a holder - // Note: `account_` is holder's account - // `holderID` is NOT used - if (!args.holderID) - { - // When a holder wants to unauthorize/delete a MPT, the ledger must - // - delete mptokenKey from owner directory - // - delete the MPToken - if (args.flags & tfMPTUnauthorize) - { - auto const mptokenKey = - keylet::mptoken(args.mptIssuanceID, args.account); - auto const sleMpt = view.peek(mptokenKey); - if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0) - return tecINTERNAL; // LCOV_EXCL_LINE - - if (!view.dirRemove( - keylet::ownerDir(args.account), - (*sleMpt)[sfOwnerNode], - sleMpt->key(), - false)) - return tecINTERNAL; // LCOV_EXCL_LINE - - adjustOwnerCount(view, sleAcct, -1, journal); - - view.erase(sleMpt); - return tesSUCCESS; - } - - // A potential holder wants to authorize/hold a mpt, the ledger must: - // - add the new mptokenKey to the owner directory - // - create the MPToken object for the holder - - // The reserve that is required to create the MPToken. Note - // that although the reserve increases with every item - // an account owns, in the case of MPTokens we only - // *enforce* a reserve if the user owns more than two - // items. This is similar to the reserve requirements of trust lines. - std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount); - XRPAmount const reserveCreate( - (uOwnerCount < 2) ? XRPAmount(beast::zero) - : view.fees().accountReserve(uOwnerCount + 1)); - - if (args.priorBalance < reserveCreate) - return tecINSUFFICIENT_RESERVE; - - auto const mptokenKey = - keylet::mptoken(args.mptIssuanceID, args.account); - auto mptoken = std::make_shared(mptokenKey); - if (auto ter = dirLink(view, args.account, mptoken)) - return ter; // LCOV_EXCL_LINE - - (*mptoken)[sfAccount] = args.account; - (*mptoken)[sfMPTokenIssuanceID] = args.mptIssuanceID; - (*mptoken)[sfFlags] = 0; - view.insert(mptoken); - - // Update owner count. - adjustOwnerCount(view, sleAcct, 1, journal); - - return tesSUCCESS; - } - - auto const sleMptIssuance = - view.read(keylet::mptIssuance(args.mptIssuanceID)); - if (!sleMptIssuance) - return tecINTERNAL; - - // If the account that submitted this tx is the issuer of the MPT - // Note: `account_` is issuer's account - // `holderID` is holder's account - if (args.account != (*sleMptIssuance)[sfIssuer]) - return tecINTERNAL; - - auto const sleMpt = - view.peek(keylet::mptoken(args.mptIssuanceID, *args.holderID)); - if (!sleMpt) - return tecINTERNAL; - - std::uint32_t const flagsIn = sleMpt->getFieldU32(sfFlags); - std::uint32_t flagsOut = flagsIn; - - // Issuer wants to unauthorize the holder, unset lsfMPTAuthorized on - // their MPToken - if (args.flags & tfMPTUnauthorize) - flagsOut &= ~lsfMPTAuthorized; - // Issuer wants to authorize a holder, set lsfMPTAuthorized on their - // MPToken - else - flagsOut |= lsfMPTAuthorized; - - if (flagsIn != flagsOut) - sleMpt->setFieldU32(sfFlags, flagsOut); - - view.update(sleMpt); - return tesSUCCESS; -} - TER MPTokenAuthorize::doApply() { auto const& tx = ctx_.tx; - return authorize( + return authorizeMPToken( ctx_.view(), + mPriorBalance, + tx[sfMPTokenIssuanceID], + account_, ctx_.journal, - {.priorBalance = mPriorBalance, - .mptIssuanceID = tx[sfMPTokenIssuanceID], - .account = account_, - .flags = tx.getFlags(), - .holderID = tx[~sfHolder]}); + tx.getFlags(), + tx[~sfHolder]); } } // namespace ripple diff --git a/src/xrpld/app/tx/detail/MPTokenAuthorize.h b/src/xrpld/app/tx/detail/MPTokenAuthorize.h index a81dc7dea27..85e8edcf9f5 100644 --- a/src/xrpld/app/tx/detail/MPTokenAuthorize.h +++ b/src/xrpld/app/tx/detail/MPTokenAuthorize.h @@ -48,12 +48,6 @@ class MPTokenAuthorize : public Transactor static TER preclaim(PreclaimContext const& ctx); - static TER - authorize( - ApplyView& view, - beast::Journal journal, - MPTAuthorizeArgs const& args); - static TER createMPToken( ApplyView& view, diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp index 1b96b27f24d..da3b57c8feb 100644 --- a/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp @@ -31,6 +31,11 @@ MPTokenIssuanceCreate::preflight(PreflightContext const& ctx) if (!ctx.rules.enabled(featureMPTokensV1)) return temDISABLED; + if (ctx.tx.isFieldPresent(sfDomainID) && + !(ctx.rules.enabled(featurePermissionedDomains) && + ctx.rules.enabled(featureSingleAssetVault))) + return temDISABLED; + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; @@ -48,6 +53,16 @@ MPTokenIssuanceCreate::preflight(PreflightContext const& ctx) return temMALFORMED; } + if (auto const domain = ctx.tx[~sfDomainID]) + { + if (*domain == beast::zero) + return temMALFORMED; + + // Domain present implies that MPTokenIssuance is not public + if ((ctx.tx.getFlags() & tfMPTRequireAuth) == 0) + return temMALFORMED; + } + if (auto const metadata = ctx.tx[~sfMPTokenMetadata]) { if (metadata->length() == 0 || @@ -142,6 +157,7 @@ MPTokenIssuanceCreate::doApply() .assetScale = tx[~sfAssetScale], .transferFee = tx[~sfTransferFee], .metadata = tx[~sfMPTokenMetadata], + .domainId = tx[~sfDomainID], }); return result ? tesSUCCESS : result.error(); } diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp index 06ea0895263..e05862af370 100644 --- a/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp @@ -21,6 +21,7 @@ #include #include +#include #include namespace ripple { @@ -31,6 +32,14 @@ MPTokenIssuanceSet::preflight(PreflightContext const& ctx) if (!ctx.rules.enabled(featureMPTokensV1)) return temDISABLED; + if (ctx.tx.isFieldPresent(sfDomainID) && + !(ctx.rules.enabled(featurePermissionedDomains) && + ctx.rules.enabled(featureSingleAssetVault))) + return temDISABLED; + + if (ctx.tx.isFieldPresent(sfDomainID) && ctx.tx.isFieldPresent(sfHolder)) + return temMALFORMED; + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; @@ -48,6 +57,13 @@ MPTokenIssuanceSet::preflight(PreflightContext const& ctx) if (holderID && accountID == holderID) return temMALFORMED; + if (ctx.rules.enabled(featureSingleAssetVault)) + { + // Is this transaction actually changing anything ? + if (txFlags == 0 && !ctx.tx.isFieldPresent(sfDomainID)) + return temMALFORMED; + } + return preflight2(ctx); } @@ -97,9 +113,14 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) if (!sleMptIssuance) return tecOBJECT_NOT_FOUND; - // if the mpt has disabled locking - if (!((*sleMptIssuance)[sfFlags] & lsfMPTCanLock)) - return tecNO_PERMISSION; + if (!sleMptIssuance->isFlag(lsfMPTCanLock)) + { + // For readability two separate `if` rather than `||` of two conditions + if (!ctx.view.rules().enabled(featureSingleAssetVault)) + return tecNO_PERMISSION; + else if (ctx.tx.isFlag(tfMPTLock) || ctx.tx.isFlag(tfMPTUnlock)) + return tecNO_PERMISSION; + } // ensure it is issued by the tx submitter if ((*sleMptIssuance)[sfIssuer] != ctx.tx[sfAccount]) @@ -117,6 +138,20 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) return tecOBJECT_NOT_FOUND; } + if (auto const domain = ctx.tx[~sfDomainID]) + { + if (not sleMptIssuance->isFlag(lsfMPTRequireAuth)) + return tecNO_PERMISSION; + + if (*domain != beast::zero) + { + auto const sleDomain = + ctx.view.read(keylet::permissionedDomain(*domain)); + if (!sleDomain) + return tecOBJECT_NOT_FOUND; + } + } + return tesSUCCESS; } @@ -126,6 +161,7 @@ MPTokenIssuanceSet::doApply() auto const mptIssuanceID = ctx_.tx[sfMPTokenIssuanceID]; auto const txFlags = ctx_.tx.getFlags(); auto const holderID = ctx_.tx[~sfHolder]; + auto const domainID = ctx_.tx[~sfDomainID]; std::shared_ptr sle; if (holderID) @@ -147,6 +183,24 @@ MPTokenIssuanceSet::doApply() if (flagsIn != flagsOut) sle->setFieldU32(sfFlags, flagsOut); + if (domainID) + { + // This is enforced in preflight. + XRPL_ASSERT( + sle->getType() == ltMPTOKEN_ISSUANCE, + "MPTokenIssuanceSet::doApply : modifying MPTokenIssuance"); + + if (*domainID != beast::zero) + { + sle->setFieldH256(sfDomainID, *domainID); + } + else + { + if (sle->isFieldPresent(sfDomainID)) + sle->makeFieldAbsent(sfDomainID); + } + } + view().update(sle); return tesSUCCESS; diff --git a/src/xrpld/app/tx/detail/PayChan.cpp b/src/xrpld/app/tx/detail/PayChan.cpp index a42902f6acd..d9e53ac75c7 100644 --- a/src/xrpld/app/tx/detail/PayChan.cpp +++ b/src/xrpld/app/tx/detail/PayChan.cpp @@ -473,7 +473,8 @@ PayChanClaim::preflight(PreflightContext const& ctx) return temBAD_SIGNATURE; } - if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err)) + if (auto const err = credentials::checkFields(ctx.tx, ctx.j); + !isTesSuccess(err)) return err; return preflight2(ctx); @@ -485,7 +486,8 @@ PayChanClaim::preclaim(PreclaimContext const& ctx) if (!ctx.view.rules().enabled(featureCredentials)) return Transactor::preclaim(ctx); - if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); + if (auto const err = + credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j); !isTesSuccess(err)) return err; @@ -554,7 +556,8 @@ PayChanClaim::doApply() if (depositAuth) { - if (auto err = verifyDepositPreauth(ctx_, txAccount, dst, sled); + if (auto err = verifyDepositPreauth( + ctx_.tx, ctx_.view(), txAccount, dst, sled, ctx_.journal); !isTesSuccess(err)) return err; } diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index f36e1bfe3d0..386b170ed1b 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -238,7 +238,8 @@ Payment::preflight(PreflightContext const& ctx) } } - if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err)) + if (auto const err = credentials::checkFields(ctx.tx, ctx.j); + !isTesSuccess(err)) return err; return preflight2(ctx); @@ -358,7 +359,8 @@ Payment::preclaim(PreclaimContext const& ctx) } } - if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); + if (auto const err = + credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j); !isTesSuccess(err)) return err; @@ -450,8 +452,13 @@ Payment::doApply() // 1. If Account == Destination, or // 2. If Account is deposit preauthorized by destination. - if (auto err = - verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst); + if (auto err = verifyDepositPreauth( + ctx_.tx, + ctx_.view(), + account_, + dstAccountID, + sleDst, + ctx_.journal); !isTesSuccess(err)) return err; } @@ -521,8 +528,13 @@ Payment::doApply() ter != tesSUCCESS) return ter; - if (auto err = - verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst); + if (auto err = verifyDepositPreauth( + ctx_.tx, + ctx_.view(), + account_, + dstAccountID, + sleDst, + ctx_.journal); !isTesSuccess(err)) return err; @@ -568,7 +580,16 @@ Payment::doApply() auto res = accountSend( pv, account_, dstAccountID, amountDeliver, ctx_.journal); if (res == tesSUCCESS) + { pv.apply(ctx_.rawView()); + + // If the actual amount delivered is different from the original + // amount due to partial payment or transfer fee, we need to update + // DelieveredAmount using the actual delivered amount + if (view().rules().enabled(fixMPTDeliveredAmount) && + amountDeliver != dstAmount) + ctx_.deliver(amountDeliver); + } else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY) res = tecPATH_PARTIAL; @@ -644,8 +665,13 @@ Payment::doApply() if (dstAmount > dstReserve || sleDst->getFieldAmount(sfBalance) > dstReserve) { - if (auto err = - verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst); + if (auto err = verifyDepositPreauth( + ctx_.tx, + ctx_.view(), + account_, + dstAccountID, + sleDst, + ctx_.journal); !isTesSuccess(err)) return err; } diff --git a/src/xrpld/app/tx/detail/SetOracle.cpp b/src/xrpld/app/tx/detail/SetOracle.cpp index 8559c3e7b9e..d598507cb71 100644 --- a/src/xrpld/app/tx/detail/SetOracle.cpp +++ b/src/xrpld/app/tx/detail/SetOracle.cpp @@ -209,6 +209,17 @@ SetOracle::doApply() { auto const oracleID = keylet::oracle(account_, ctx_.tx[sfOracleDocumentID]); + auto populatePriceData = [](STObject& priceData, STObject const& entry) { + setPriceDataInnerObjTemplate(priceData); + priceData.setFieldCurrency( + sfBaseAsset, entry.getFieldCurrency(sfBaseAsset)); + priceData.setFieldCurrency( + sfQuoteAsset, entry.getFieldCurrency(sfQuoteAsset)); + priceData.setFieldU64(sfAssetPrice, entry.getFieldU64(sfAssetPrice)); + if (entry.isFieldPresent(sfScale)) + priceData.setFieldU8(sfScale, entry.getFieldU8(sfScale)); + }; + if (auto sle = ctx_.view().peek(oracleID)) { // update @@ -249,15 +260,7 @@ SetOracle::doApply() { // add a token pair with the price STObject priceData{sfPriceData}; - setPriceDataInnerObjTemplate(priceData); - priceData.setFieldCurrency( - sfBaseAsset, entry.getFieldCurrency(sfBaseAsset)); - priceData.setFieldCurrency( - sfQuoteAsset, entry.getFieldCurrency(sfQuoteAsset)); - priceData.setFieldU64( - sfAssetPrice, entry.getFieldU64(sfAssetPrice)); - if (entry.isFieldPresent(sfScale)) - priceData.setFieldU8(sfScale, entry.getFieldU8(sfScale)); + populatePriceData(priceData, entry); pairs.emplace(key, std::move(priceData)); } } @@ -285,7 +288,26 @@ SetOracle::doApply() sle->setFieldVL(sfProvider, ctx_.tx[sfProvider]); if (ctx_.tx.isFieldPresent(sfURI)) sle->setFieldVL(sfURI, ctx_.tx[sfURI]); - auto const& series = ctx_.tx.getFieldArray(sfPriceDataSeries); + + STArray series; + if (!ctx_.view().rules().enabled(fixPriceOracleOrder)) + { + series = ctx_.tx.getFieldArray(sfPriceDataSeries); + } + else + { + std::map, STObject> pairs; + for (auto const& entry : ctx_.tx.getFieldArray(sfPriceDataSeries)) + { + auto const key = tokenPairKey(entry); + STObject priceData{sfPriceData}; + populatePriceData(priceData, entry); + pairs.emplace(key, std::move(priceData)); + } + for (auto const& iter : pairs) + series.push_back(std::move(iter.second)); + } + sle->setFieldArray(sfPriceDataSeries, series); sle->setFieldVL(sfAssetClass, ctx_.tx[sfAssetClass]); sle->setFieldU32(sfLastUpdateTime, ctx_.tx[sfLastUpdateTime]); diff --git a/src/xrpld/app/tx/detail/Taker.cpp b/src/xrpld/app/tx/detail/Taker.cpp deleted file mode 100644 index 9bfd6dc1d3d..00000000000 --- a/src/xrpld/app/tx/detail/Taker.cpp +++ /dev/null @@ -1,863 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include - -#include -#include - -namespace ripple { - -static std::string -format_amount(STAmount const& amount) -{ - std::string txt = amount.getText(); - txt += "/"; - txt += to_string(amount.issue().currency); - return txt; -} - -BasicTaker::BasicTaker( - CrossType cross_type, - AccountID const& account, - Amounts const& amount, - Quality const& quality, - std::uint32_t flags, - Rate const& rate_in, - Rate const& rate_out, - beast::Journal journal) - : account_(account) - , quality_(quality) - , threshold_(quality_) - , sell_(flags & tfSell) - , original_(amount) - , remaining_(amount) - , issue_in_(remaining_.in.issue()) - , issue_out_(remaining_.out.issue()) - , m_rate_in(rate_in) - , m_rate_out(rate_out) - , cross_type_(cross_type) - , journal_(journal) -{ - XRPL_ASSERT( - remaining_.in > beast::zero, - "ripple::BasicTaker::BasicTaker : positive remaining in"); - XRPL_ASSERT( - remaining_.out > beast::zero, - "ripple::BasicTaker::BasicTaker : positive remaining out"); - - XRPL_ASSERT( - m_rate_in.value, "ripple::BasicTaker::BasicTaker : nonzero rate in"); - XRPL_ASSERT( - m_rate_out.value, "ripple::BasicTaker::BasicTaker : nonzero rate out"); - - // If we are dealing with a particular flavor, make sure that it's the - // flavor we expect: - XRPL_ASSERT( - cross_type != CrossType::XrpToIou || - (isXRP(issue_in()) && !isXRP(issue_out())), - "ripple::BasicTaker::BasicTaker : valid cross to IOU"); - - XRPL_ASSERT( - cross_type != CrossType::IouToXrp || - (!isXRP(issue_in()) && isXRP(issue_out())), - "ripple::BasicTaker::BasicTaker : valid cross to XRP"); - - // And make sure we're not crossing XRP for XRP - XRPL_ASSERT( - !isXRP(issue_in()) || !isXRP(issue_out()), - "ripple::BasicTaker::BasicTaker : not crossing XRP for XRP"); - - // If this is a passive order, we adjust the quality so as to prevent offers - // at the same quality level from being consumed. - if (flags & tfPassive) - ++threshold_; -} - -Rate -BasicTaker::effective_rate( - Rate const& rate, - Issue const& issue, - AccountID const& from, - AccountID const& to) -{ - // If there's a transfer rate, the issuer is not involved - // and the sender isn't the same as the recipient, return - // the actual transfer rate. - if (rate != parityRate && from != to && from != issue.account && - to != issue.account) - { - return rate; - } - - return parityRate; -} - -bool -BasicTaker::unfunded() const -{ - if (get_funds(account(), remaining_.in) > beast::zero) - return false; - - JLOG(journal_.debug()) << "Unfunded: taker is out of funds."; - return true; -} - -bool -BasicTaker::done() const -{ - // We are done if we have consumed all the input currency - if (remaining_.in <= beast::zero) - { - JLOG(journal_.debug()) - << "Done: all the input currency has been consumed."; - return true; - } - - // We are done if using buy semantics and we received the - // desired amount of output currency - if (!sell_ && (remaining_.out <= beast::zero)) - { - JLOG(journal_.debug()) << "Done: the desired amount has been received."; - return true; - } - - // We are done if the taker is out of funds - if (unfunded()) - { - JLOG(journal_.debug()) << "Done: taker out of funds."; - return true; - } - - return false; -} - -Amounts -BasicTaker::remaining_offer() const -{ - // If the taker is done, then there's no offer to place. - if (done()) - return Amounts(remaining_.in.zeroed(), remaining_.out.zeroed()); - - // Avoid math altogether if we didn't cross. - if (original_ == remaining_) - return original_; - - if (sell_) - { - XRPL_ASSERT( - remaining_.in > beast::zero, - "ripple::BasicTaker::remaining_offer : positive remaining in"); - - // We scale the output based on the remaining input: - return Amounts( - remaining_.in, - divRound(remaining_.in, quality_.rate(), issue_out_, true)); - } - - XRPL_ASSERT( - remaining_.out > beast::zero, - "ripple::BasicTaker::remaining_offer : positive remaining out"); - - // We scale the input based on the remaining output: - return Amounts( - mulRound(remaining_.out, quality_.rate(), issue_in_, true), - remaining_.out); -} - -Amounts const& -BasicTaker::original_offer() const -{ - return original_; -} - -// TODO: the presence of 'output' is an artifact caused by the fact that -// Amounts carry issue information which should be decoupled. -static STAmount -qual_div(STAmount const& amount, Quality const& quality, STAmount const& output) -{ - auto result = divide(amount, quality.rate(), output.issue()); - return std::min(result, output); -} - -static STAmount -qual_mul(STAmount const& amount, Quality const& quality, STAmount const& output) -{ - auto result = multiply(amount, quality.rate(), output.issue()); - return std::min(result, output); -} - -void -BasicTaker::log_flow(char const* description, Flow const& flow) -{ - auto stream = journal_.debug(); - if (!stream) - return; - - stream << description; - - if (isXRP(issue_in())) - stream << " order in: " << format_amount(flow.order.in); - else - stream << " order in: " << format_amount(flow.order.in) - << " (issuer: " << format_amount(flow.issuers.in) << ")"; - - if (isXRP(issue_out())) - stream << " order out: " << format_amount(flow.order.out); - else - stream << " order out: " << format_amount(flow.order.out) - << " (issuer: " << format_amount(flow.issuers.out) << ")"; -} - -BasicTaker::Flow -BasicTaker::flow_xrp_to_iou( - Amounts const& order, - Quality quality, - STAmount const& owner_funds, - STAmount const& taker_funds, - Rate const& rate_out) -{ - Flow f; - f.order = order; - f.issuers.out = multiply(f.order.out, rate_out); - - log_flow("flow_xrp_to_iou", f); - - // Clamp on owner balance - if (owner_funds < f.issuers.out) - { - f.issuers.out = owner_funds; - f.order.out = divide(f.issuers.out, rate_out); - f.order.in = qual_mul(f.order.out, quality, f.order.in); - log_flow("(clamped on owner balance)", f); - } - - // Clamp if taker wants to limit the output - if (!sell_ && remaining_.out < f.order.out) - { - f.order.out = remaining_.out; - f.order.in = qual_mul(f.order.out, quality, f.order.in); - f.issuers.out = multiply(f.order.out, rate_out); - log_flow("(clamped on taker output)", f); - } - - // Clamp on the taker's funds - if (taker_funds < f.order.in) - { - f.order.in = taker_funds; - f.order.out = qual_div(f.order.in, quality, f.order.out); - f.issuers.out = multiply(f.order.out, rate_out); - log_flow("(clamped on taker funds)", f); - } - - // Clamp on remaining offer if we are not handling the second leg - // of an autobridge. - if (cross_type_ == CrossType::XrpToIou && (remaining_.in < f.order.in)) - { - f.order.in = remaining_.in; - f.order.out = qual_div(f.order.in, quality, f.order.out); - f.issuers.out = multiply(f.order.out, rate_out); - log_flow("(clamped on taker input)", f); - } - - return f; -} - -BasicTaker::Flow -BasicTaker::flow_iou_to_xrp( - Amounts const& order, - Quality quality, - STAmount const& owner_funds, - STAmount const& taker_funds, - Rate const& rate_in) -{ - Flow f; - f.order = order; - f.issuers.in = multiply(f.order.in, rate_in); - - log_flow("flow_iou_to_xrp", f); - - // Clamp on owner's funds - if (owner_funds < f.order.out) - { - f.order.out = owner_funds; - f.order.in = qual_mul(f.order.out, quality, f.order.in); - f.issuers.in = multiply(f.order.in, rate_in); - log_flow("(clamped on owner funds)", f); - } - - // Clamp if taker wants to limit the output and we are not the - // first leg of an autobridge. - if (!sell_ && cross_type_ == CrossType::IouToXrp) - { - if (remaining_.out < f.order.out) - { - f.order.out = remaining_.out; - f.order.in = qual_mul(f.order.out, quality, f.order.in); - f.issuers.in = multiply(f.order.in, rate_in); - log_flow("(clamped on taker output)", f); - } - } - - // Clamp on the taker's input offer - if (remaining_.in < f.order.in) - { - f.order.in = remaining_.in; - f.issuers.in = multiply(f.order.in, rate_in); - f.order.out = qual_div(f.order.in, quality, f.order.out); - log_flow("(clamped on taker input)", f); - } - - // Clamp on the taker's input balance - if (taker_funds < f.issuers.in) - { - f.issuers.in = taker_funds; - f.order.in = divide(f.issuers.in, rate_in); - f.order.out = qual_div(f.order.in, quality, f.order.out); - log_flow("(clamped on taker funds)", f); - } - - return f; -} - -BasicTaker::Flow -BasicTaker::flow_iou_to_iou( - Amounts const& order, - Quality quality, - STAmount const& owner_funds, - STAmount const& taker_funds, - Rate const& rate_in, - Rate const& rate_out) -{ - Flow f; - f.order = order; - f.issuers.in = multiply(f.order.in, rate_in); - f.issuers.out = multiply(f.order.out, rate_out); - - log_flow("flow_iou_to_iou", f); - - // Clamp on owner balance - if (owner_funds < f.issuers.out) - { - f.issuers.out = owner_funds; - f.order.out = divide(f.issuers.out, rate_out); - f.order.in = qual_mul(f.order.out, quality, f.order.in); - f.issuers.in = multiply(f.order.in, rate_in); - log_flow("(clamped on owner funds)", f); - } - - // Clamp on taker's offer - if (!sell_ && remaining_.out < f.order.out) - { - f.order.out = remaining_.out; - f.order.in = qual_mul(f.order.out, quality, f.order.in); - f.issuers.out = multiply(f.order.out, rate_out); - f.issuers.in = multiply(f.order.in, rate_in); - log_flow("(clamped on taker output)", f); - } - - // Clamp on the taker's input offer - if (remaining_.in < f.order.in) - { - f.order.in = remaining_.in; - f.issuers.in = multiply(f.order.in, rate_in); - f.order.out = qual_div(f.order.in, quality, f.order.out); - f.issuers.out = multiply(f.order.out, rate_out); - log_flow("(clamped on taker input)", f); - } - - // Clamp on the taker's input balance - if (taker_funds < f.issuers.in) - { - f.issuers.in = taker_funds; - f.order.in = divide(f.issuers.in, rate_in); - f.order.out = qual_div(f.order.in, quality, f.order.out); - f.issuers.out = multiply(f.order.out, rate_out); - log_flow("(clamped on taker funds)", f); - } - - return f; -} - -// Calculates the direct flow through the specified offer -BasicTaker::Flow -BasicTaker::do_cross(Amounts offer, Quality quality, AccountID const& owner) -{ - auto const owner_funds = get_funds(owner, offer.out); - auto const taker_funds = get_funds(account(), offer.in); - - Flow result; - - if (cross_type_ == CrossType::XrpToIou) - { - result = flow_xrp_to_iou( - offer, - quality, - owner_funds, - taker_funds, - out_rate(owner, account())); - } - else if (cross_type_ == CrossType::IouToXrp) - { - result = flow_iou_to_xrp( - offer, - quality, - owner_funds, - taker_funds, - in_rate(owner, account())); - } - else - { - result = flow_iou_to_iou( - offer, - quality, - owner_funds, - taker_funds, - in_rate(owner, account()), - out_rate(owner, account())); - } - - if (!result.sanity_check()) - Throw("Computed flow fails sanity check."); - - remaining_.out -= result.order.out; - remaining_.in -= result.order.in; - - XRPL_ASSERT( - remaining_.in >= beast::zero, - "ripple::BasicTaker::do_cross : minimum remaining in"); - - return result; -} - -// Calculates the bridged flow through the specified offers -std::pair -BasicTaker::do_cross( - Amounts offer1, - Quality quality1, - AccountID const& owner1, - Amounts offer2, - Quality quality2, - AccountID const& owner2) -{ - XRPL_ASSERT( - !offer1.in.native(), - "ripple::BasicTaker::do_cross : offer1 in is not XRP"); - XRPL_ASSERT( - offer1.out.native(), - "ripple::BasicTaker::do_cross : offer1 out is XRP"); - XRPL_ASSERT( - offer2.in.native(), "ripple::BasicTaker::do_cross : offer2 in is XRP"); - XRPL_ASSERT( - !offer2.out.native(), - "ripple::BasicTaker::do_cross : offer2 out is not XRP"); - - // If the taker owns the first leg of the offer, then the taker's available - // funds aren't the limiting factor for the input - the offer itself is. - auto leg1_in_funds = get_funds(account(), offer1.in); - - if (account() == owner1) - { - JLOG(journal_.trace()) << "The taker owns the first leg of a bridge."; - leg1_in_funds = std::max(leg1_in_funds, offer1.in); - } - - // If the taker owns the second leg of the offer, then the taker's available - // funds are not the limiting factor for the output - the offer itself is. - auto leg2_out_funds = get_funds(owner2, offer2.out); - - if (account() == owner2) - { - JLOG(journal_.trace()) << "The taker owns the second leg of a bridge."; - leg2_out_funds = std::max(leg2_out_funds, offer2.out); - } - - // The amount available to flow via XRP is the amount that the owner of the - // first leg of the bridge has, up to the first leg's output. - // - // But, when both legs of a bridge are owned by the same person, the amount - // of XRP that can flow between the two legs is, essentially, infinite - // since all the owner is doing is taking out XRP of his left pocket - // and putting it in his right pocket. In that case, we set the available - // XRP to the largest of the two offers. - auto xrp_funds = get_funds(owner1, offer1.out); - - if (owner1 == owner2) - { - JLOG(journal_.trace()) - << "The bridge endpoints are owned by the same account."; - xrp_funds = std::max(offer1.out, offer2.in); - } - - if (auto stream = journal_.debug()) - { - stream << "Available bridge funds:"; - stream << " leg1 in: " << format_amount(leg1_in_funds); - stream << " leg2 out: " << format_amount(leg2_out_funds); - stream << " xrp: " << format_amount(xrp_funds); - } - - auto const leg1_rate = in_rate(owner1, account()); - auto const leg2_rate = out_rate(owner2, account()); - - // Attempt to determine the maximal flow that can be achieved across each - // leg independent of the other. - auto flow1 = - flow_iou_to_xrp(offer1, quality1, xrp_funds, leg1_in_funds, leg1_rate); - - if (!flow1.sanity_check()) - Throw("Computed flow1 fails sanity check."); - - auto flow2 = - flow_xrp_to_iou(offer2, quality2, leg2_out_funds, xrp_funds, leg2_rate); - - if (!flow2.sanity_check()) - Throw("Computed flow2 fails sanity check."); - - // We now have the maximal flows across each leg individually. We need to - // equalize them, so that the amount of XRP that flows out of the first leg - // is the same as the amount of XRP that flows into the second leg. We take - // the side which is the limiting factor (if any) and adjust the other. - if (flow1.order.out < flow2.order.in) - { - // Adjust the second leg of the offer down: - flow2.order.in = flow1.order.out; - flow2.order.out = qual_div(flow2.order.in, quality2, flow2.order.out); - flow2.issuers.out = multiply(flow2.order.out, leg2_rate); - log_flow("Balancing: adjusted second leg down", flow2); - } - else if (flow1.order.out > flow2.order.in) - { - // Adjust the first leg of the offer down: - flow1.order.out = flow2.order.in; - flow1.order.in = qual_mul(flow1.order.out, quality1, flow1.order.in); - flow1.issuers.in = multiply(flow1.order.in, leg1_rate); - log_flow("Balancing: adjusted first leg down", flow2); - } - - if (flow1.order.out != flow2.order.in) - Throw("Bridged flow is out of balance."); - - remaining_.out -= flow2.order.out; - remaining_.in -= flow1.order.in; - - return std::make_pair(flow1, flow2); -} - -//============================================================================== - -Taker::Taker( - CrossType cross_type, - ApplyView& view, - AccountID const& account, - Amounts const& offer, - std::uint32_t flags, - beast::Journal journal) - : BasicTaker( - cross_type, - account, - offer, - Quality(offer), - flags, - calculateRate(view, offer.in.getIssuer(), account), - calculateRate(view, offer.out.getIssuer(), account), - journal) - , view_(view) - , xrp_flow_(0) - , direct_crossings_(0) - , bridge_crossings_(0) -{ - XRPL_ASSERT( - issue_in() == offer.in.issue(), - "ripple::Taker::Taker : issue in is a match"); - XRPL_ASSERT( - issue_out() == offer.out.issue(), - "ripple::Taker::Taker : issue out is a match"); - - if (auto stream = journal_.debug()) - { - stream << "Crossing as: " << to_string(account); - - if (isXRP(issue_in())) - stream << " Offer in: " << format_amount(offer.in); - else - stream << " Offer in: " << format_amount(offer.in) - << " (issuer: " << issue_in().account << ")"; - - if (isXRP(issue_out())) - stream << " Offer out: " << format_amount(offer.out); - else - stream << " Offer out: " << format_amount(offer.out) - << " (issuer: " << issue_out().account << ")"; - - stream << " Balance: " - << format_amount(get_funds(account, offer.in)); - } -} - -void -Taker::consume_offer(Offer& offer, Amounts const& order) -{ - if (order.in < beast::zero) - Throw("flow with negative input."); - - if (order.out < beast::zero) - Throw("flow with negative output."); - - JLOG(journal_.debug()) << "Consuming from offer " << offer; - - if (auto stream = journal_.trace()) - { - auto const& available = offer.amount(); - - stream << " in:" << format_amount(available.in); - stream << " out:" << format_amount(available.out); - } - - offer.consume(view_, order); -} - -STAmount -Taker::get_funds(AccountID const& account, STAmount const& amount) const -{ - return accountFunds(view_, account, amount, fhZERO_IF_FROZEN, journal_); -} - -TER -Taker::transferXRP( - AccountID const& from, - AccountID const& to, - STAmount const& amount) -{ - if (!isXRP(amount)) - Throw("Using transferXRP with IOU"); - - if (from == to) - return tesSUCCESS; - - // Transferring zero is equivalent to not doing a transfer - if (amount == beast::zero) - return tesSUCCESS; - - return ripple::transferXRP(view_, from, to, amount, journal_); -} - -TER -Taker::redeemIOU( - AccountID const& account, - STAmount const& amount, - Issue const& issue) -{ - if (isXRP(amount)) - Throw("Using redeemIOU with XRP"); - - if (account == issue.account) - return tesSUCCESS; - - // Transferring zero is equivalent to not doing a transfer - if (amount == beast::zero) - return tesSUCCESS; - - // If we are trying to redeem some amount, then the account - // must have a credit balance. - if (get_funds(account, amount) <= beast::zero) - Throw("redeemIOU has no funds to redeem"); - - auto ret = ripple::redeemIOU(view_, account, amount, issue, journal_); - - if (get_funds(account, amount) < beast::zero) - Throw("redeemIOU redeemed more funds than available"); - - return ret; -} - -TER -Taker::issueIOU( - AccountID const& account, - STAmount const& amount, - Issue const& issue) -{ - if (isXRP(amount)) - Throw("Using issueIOU with XRP"); - - if (account == issue.account) - return tesSUCCESS; - - // Transferring zero is equivalent to not doing a transfer - if (amount == beast::zero) - return tesSUCCESS; - - return ripple::issueIOU(view_, account, amount, issue, journal_); -} - -// Performs funds transfers to fill the given offer and adjusts offer. -TER -Taker::fill(BasicTaker::Flow const& flow, Offer& offer) -{ - // adjust offer - consume_offer(offer, flow.order); - - TER result = tesSUCCESS; - - if (cross_type() != CrossType::XrpToIou) - { - XRPL_ASSERT( - !isXRP(flow.order.in), "ripple::Taker::fill : order in is not XRP"); - - if (result == tesSUCCESS) - result = - redeemIOU(account(), flow.issuers.in, flow.issuers.in.issue()); - - if (result == tesSUCCESS) - result = - issueIOU(offer.owner(), flow.order.in, flow.order.in.issue()); - } - else - { - XRPL_ASSERT( - isXRP(flow.order.in), "ripple::Taker::fill : order in is XRP"); - - if (result == tesSUCCESS) - result = transferXRP(account(), offer.owner(), flow.order.in); - } - - // Now send funds from the account whose offer we're taking - if (cross_type() != CrossType::IouToXrp) - { - XRPL_ASSERT( - !isXRP(flow.order.out), - "ripple::Taker::fill : order out is not XRP"); - - if (result == tesSUCCESS) - result = redeemIOU( - offer.owner(), flow.issuers.out, flow.issuers.out.issue()); - - if (result == tesSUCCESS) - result = - issueIOU(account(), flow.order.out, flow.order.out.issue()); - } - else - { - XRPL_ASSERT( - isXRP(flow.order.out), "ripple::Taker::fill : order out is XRP"); - - if (result == tesSUCCESS) - result = transferXRP(offer.owner(), account(), flow.order.out); - } - - if (result == tesSUCCESS) - direct_crossings_++; - - return result; -} - -// Performs bridged funds transfers to fill the given offers and adjusts offers. -TER -Taker::fill( - BasicTaker::Flow const& flow1, - Offer& leg1, - BasicTaker::Flow const& flow2, - Offer& leg2) -{ - // Adjust offers accordingly - consume_offer(leg1, flow1.order); - consume_offer(leg2, flow2.order); - - TER result = tesSUCCESS; - - // Taker to leg1: IOU - if (leg1.owner() != account()) - { - if (result == tesSUCCESS) - result = redeemIOU( - account(), flow1.issuers.in, flow1.issuers.in.issue()); - - if (result == tesSUCCESS) - result = - issueIOU(leg1.owner(), flow1.order.in, flow1.order.in.issue()); - } - - // leg1 to leg2: bridging over XRP - if (result == tesSUCCESS) - result = transferXRP(leg1.owner(), leg2.owner(), flow1.order.out); - - // leg2 to Taker: IOU - if (leg2.owner() != account()) - { - if (result == tesSUCCESS) - result = redeemIOU( - leg2.owner(), flow2.issuers.out, flow2.issuers.out.issue()); - - if (result == tesSUCCESS) - result = - issueIOU(account(), flow2.order.out, flow2.order.out.issue()); - } - - if (result == tesSUCCESS) - { - bridge_crossings_++; - xrp_flow_ += flow1.order.out; - } - - return result; -} - -TER -Taker::cross(Offer& offer) -{ - // In direct crossings, at least one leg must not be XRP. - if (isXRP(offer.amount().in) && isXRP(offer.amount().out)) - return tefINTERNAL; - - auto const amount = - do_cross(offer.amount(), offer.quality(), offer.owner()); - - return fill(amount, offer); -} - -TER -Taker::cross(Offer& leg1, Offer& leg2) -{ - // In bridged crossings, XRP must can't be the input to the first leg - // or the output of the second leg. - if (isXRP(leg1.amount().in) || isXRP(leg2.amount().out)) - return tefINTERNAL; - - auto ret = do_cross( - leg1.amount(), - leg1.quality(), - leg1.owner(), - leg2.amount(), - leg2.quality(), - leg2.owner()); - - return fill(ret.first, leg1, ret.second, leg2); -} - -Rate -Taker::calculateRate( - ApplyView const& view, - AccountID const& issuer, - AccountID const& account) -{ - return isXRP(issuer) || (account == issuer) ? parityRate - : transferRate(view, issuer); -} - -} // namespace ripple diff --git a/src/xrpld/app/tx/detail/Taker.h b/src/xrpld/app/tx/detail/Taker.h deleted file mode 100644 index 3702a30deb7..00000000000 --- a/src/xrpld/app/tx/detail/Taker.h +++ /dev/null @@ -1,341 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_BOOK_TAKER_H_INCLUDED -#define RIPPLE_APP_BOOK_TAKER_H_INCLUDED - -#include -#include - -#include -#include -#include -#include -#include - -namespace ripple { - -/** The flavor of an offer crossing */ -enum class CrossType { XrpToIou, IouToXrp, IouToIou }; - -/** State for the active party during order book or payment operations. */ -class BasicTaker -{ -private: - AccountID account_; - Quality quality_; - Quality threshold_; - - bool sell_; - - // The original in and out quantities. - Amounts const original_; - - // The amounts still left over for us to try and take. - Amounts remaining_; - - // The issuers for the input and output - Issue const& issue_in_; - Issue const& issue_out_; - - // The rates that will be paid when the input and output currencies are - // transfered and the currency issuer isn't involved: - Rate const m_rate_in; - Rate const m_rate_out; - - // The type of crossing that we are performing - CrossType cross_type_; - -protected: - beast::Journal const journal_; - - struct Flow - { - explicit Flow() = default; - - Amounts order; - Amounts issuers; - - bool - sanity_check() const - { - using beast::zero; - - if (isXRP(order.in) && isXRP(order.out)) - return false; - - return order.in >= zero && order.out >= zero && - issuers.in >= zero && issuers.out >= zero; - } - }; - -private: - void - log_flow(char const* description, Flow const& flow); - - Flow - flow_xrp_to_iou( - Amounts const& offer, - Quality quality, - STAmount const& owner_funds, - STAmount const& taker_funds, - Rate const& rate_out); - - Flow - flow_iou_to_xrp( - Amounts const& offer, - Quality quality, - STAmount const& owner_funds, - STAmount const& taker_funds, - Rate const& rate_in); - - Flow - flow_iou_to_iou( - Amounts const& offer, - Quality quality, - STAmount const& owner_funds, - STAmount const& taker_funds, - Rate const& rate_in, - Rate const& rate_out); - - // Calculates the transfer rate that we should use when calculating - // flows for a particular issue between two accounts. - static Rate - effective_rate( - Rate const& rate, - Issue const& issue, - AccountID const& from, - AccountID const& to); - - // The transfer rate for the input currency between the given accounts - Rate - in_rate(AccountID const& from, AccountID const& to) const - { - return effective_rate(m_rate_in, original_.in.issue(), from, to); - } - - // The transfer rate for the output currency between the given accounts - Rate - out_rate(AccountID const& from, AccountID const& to) const - { - return effective_rate(m_rate_out, original_.out.issue(), from, to); - } - -public: - BasicTaker() = delete; - BasicTaker(BasicTaker const&) = delete; - - BasicTaker( - CrossType cross_type, - AccountID const& account, - Amounts const& amount, - Quality const& quality, - std::uint32_t flags, - Rate const& rate_in, - Rate const& rate_out, - beast::Journal journal = beast::Journal{beast::Journal::getNullSink()}); - - virtual ~BasicTaker() = default; - - /** Returns the amount remaining on the offer. - This is the amount at which the offer should be placed. It may either - be for the full amount when there were no crossing offers, or for zero - when the offer fully crossed, or any amount in between. - It is always at the original offer quality (quality_) - */ - Amounts - remaining_offer() const; - - /** Returns the amount that the offer was originally placed at. */ - Amounts const& - original_offer() const; - - /** Returns the account identifier of the taker. */ - AccountID const& - account() const noexcept - { - return account_; - } - - /** Returns `true` if the quality does not meet the taker's requirements. */ - bool - reject(Quality const& quality) const noexcept - { - return quality < threshold_; - } - - /** Returns the type of crossing that is being performed */ - CrossType - cross_type() const - { - return cross_type_; - } - - /** Returns the Issue associated with the input of the offer */ - Issue const& - issue_in() const - { - return issue_in_; - } - - /** Returns the Issue associated with the output of the offer */ - Issue const& - issue_out() const - { - return issue_out_; - } - - /** Returns `true` if the taker has run out of funds. */ - bool - unfunded() const; - - /** Returns `true` if order crossing should not continue. - Order processing is stopped if the taker's order quantities have - been reached, or if the taker has run out of input funds. - */ - bool - done() const; - - /** Perform direct crossing through given offer. - @return an `Amounts` describing the flow achieved during cross - */ - BasicTaker::Flow - do_cross(Amounts offer, Quality quality, AccountID const& owner); - - /** Perform bridged crossing through given offers. - @return a pair of `Amounts` describing the flow achieved during cross - */ - std::pair - do_cross( - Amounts offer1, - Quality quality1, - AccountID const& owner1, - Amounts offer2, - Quality quality2, - AccountID const& owner2); - - virtual STAmount - get_funds(AccountID const& account, STAmount const& funds) const = 0; -}; - -//------------------------------------------------------------------------------ - -class Taker : public BasicTaker -{ -public: - Taker() = delete; - Taker(Taker const&) = delete; - - Taker( - CrossType cross_type, - ApplyView& view, - AccountID const& account, - Amounts const& offer, - std::uint32_t flags, - beast::Journal journal); - ~Taker() = default; - - void - consume_offer(Offer& offer, Amounts const& order); - - STAmount - get_funds(AccountID const& account, STAmount const& funds) const override; - - STAmount const& - get_xrp_flow() const - { - return xrp_flow_; - } - - std::uint32_t - get_direct_crossings() const - { - return direct_crossings_; - } - - std::uint32_t - get_bridge_crossings() const - { - return bridge_crossings_; - } - - /** Perform a direct or bridged offer crossing as appropriate. - Funds will be transferred accordingly, and offers will be adjusted. - @return tesSUCCESS if successful, or an error code otherwise. - */ - /** @{ */ - TER - cross(Offer& offer); - - TER - cross(Offer& leg1, Offer& leg2); - /** @} */ - -private: - static Rate - calculateRate( - ApplyView const& view, - AccountID const& issuer, - AccountID const& account); - - TER - fill(BasicTaker::Flow const& flow, Offer& offer); - - TER - fill( - BasicTaker::Flow const& flow1, - Offer& leg1, - BasicTaker::Flow const& flow2, - Offer& leg2); - - TER - transferXRP( - AccountID const& from, - AccountID const& to, - STAmount const& amount); - - TER - redeemIOU( - AccountID const& account, - STAmount const& amount, - Issue const& issue); - - TER - issueIOU( - AccountID const& account, - STAmount const& amount, - Issue const& issue); - -private: - // The underlying ledger entry we are dealing with - ApplyView& view_; - - // The amount of XRP that flowed if we were autobridging - STAmount xrp_flow_; - - // The number direct crossings that we performed - std::uint32_t direct_crossings_; - - // The number autobridged crossings that we performed - std::uint32_t bridge_crossings_; -}; - -} // namespace ripple - -#endif diff --git a/src/xrpld/app/tx/detail/VaultDeposit.cpp b/src/xrpld/app/tx/detail/VaultDeposit.cpp index 0efddb0ff7c..db1fc3bbfe8 100644 --- a/src/xrpld/app/tx/detail/VaultDeposit.cpp +++ b/src/xrpld/app/tx/detail/VaultDeposit.cpp @@ -210,12 +210,12 @@ VaultDeposit::doApply() auto sleMpt = view().read(keylet::mptoken(mptIssuanceID, account_)); if (!sleMpt) { - if (auto const err = MPTokenAuthorize::authorize( + if (auto const err = authorizeMPToken( view(), - ctx_.journal, - {.priorBalance = mPriorBalance, - .mptIssuanceID = mptIssuanceID->value(), - .account = account_}); + mPriorBalance, + mptIssuanceID->value(), + account_, + ctx_.journal); !isTesSuccess(err)) return err; } @@ -223,15 +223,15 @@ VaultDeposit::doApply() // If the vault is private, set the authorized flag for the vault owner if (vault->isFlag(tfVaultPrivate)) { - if (auto const err = MPTokenAuthorize::authorize( + if (auto const err = authorizeMPToken( view(), + mPriorBalance, // priorBalance + mptIssuanceID->value(), // mptIssuanceID + sleIssuance->at(sfIssuer), // account ctx_.journal, - { - .priorBalance = mPriorBalance, - .mptIssuanceID = mptIssuanceID->value(), - .account = sleIssuance->at(sfIssuer), - .holderID = account_, - }); + {}, // flags + account_ // holderID + ); !isTesSuccess(err)) return err; } diff --git a/src/xrpld/app/tx/detail/VaultWithdraw.cpp b/src/xrpld/app/tx/detail/VaultWithdraw.cpp index 7a8605cdbdb..09a9fd14e14 100644 --- a/src/xrpld/app/tx/detail/VaultWithdraw.cpp +++ b/src/xrpld/app/tx/detail/VaultWithdraw.cpp @@ -52,9 +52,19 @@ VaultWithdraw::preflight(PreflightContext const& ctx) return temBAD_AMOUNT; if (auto const destination = ctx.tx[~sfDestination]; - destination && *destination == beast::zero) + destination.has_value()) { - JLOG(ctx.j.debug()) << "VaultWithdraw: zero/empty destination account."; + if (*destination == beast::zero) + { + JLOG(ctx.j.debug()) + << "VaultWithdraw: zero/empty destination account."; + return temMALFORMED; + } + } + else if (ctx.tx.isFieldPresent(sfDestinationTag)) + { + JLOG(ctx.j.debug()) << "VaultWithdraw: sfDestinationTag is set but " + "sfDestination is not"; return temMALFORMED; } @@ -123,33 +133,39 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx) // Withdrawal to a 3rd party destination account is essentially a transfer, // via shares in the vault. Enforce all the usual asset transfer checks. + AuthType authType = AuthType::Legacy; if (account != dstAcct) { auto const sleDst = ctx.view.read(keylet::account(dstAcct)); if (sleDst == nullptr) return tecNO_DST; - if (sleDst->getFlags() & lsfRequireDestTag) + if (sleDst->isFlag(lsfRequireDestTag) && + !ctx.tx.isFieldPresent(sfDestinationTag)) return tecDST_TAG_NEEDED; // Cannot send without a tag - if (sleDst->getFlags() & lsfDepositAuth) + if (sleDst->isFlag(lsfDepositAuth)) { if (!ctx.view.exists(keylet::depositPreauth(dstAcct, account))) return tecNO_PERMISSION; } + // The destination account must have consented to receive the asset by + // creating a RippleState or MPToken + authType = AuthType::StrongAuth; } - // Destination MPToken must exist (if asset is an MPT) - if (auto const ter = requireAuth(ctx.view, vaultAsset, dstAcct); + // Destination MPToken (for an MPT) or trust line (for an IOU) must exist + // if not sending to Account. + if (auto const ter = requireAuth(ctx.view, vaultAsset, dstAcct, authType); !isTesSuccess(ter)) return ter; // Cannot withdraw from a Vault an Asset frozen for the destination account - if (isFrozen(ctx.view, dstAcct, vaultAsset)) - return vaultAsset.holds() ? tecFROZEN : tecLOCKED; + if (auto const ret = checkFrozen(ctx.view, dstAcct, vaultAsset)) + return ret; - if (isFrozen(ctx.view, account, vaultShare)) - return tecLOCKED; + if (auto const ret = checkFrozen(ctx.view, account, vaultShare)) + return ret; return tesSUCCESS; } diff --git a/src/xrpld/app/tx/detail/apply.cpp b/src/xrpld/app/tx/detail/apply.cpp index 889a520032d..e2e0adae45c 100644 --- a/src/xrpld/app/tx/detail/apply.cpp +++ b/src/xrpld/app/tx/detail/apply.cpp @@ -27,11 +27,16 @@ namespace ripple { -// These are the same flags defined as SF_PRIVATE1-4 in HashRouter.h -#define SF_SIGBAD SF_PRIVATE1 // Signature is bad -#define SF_SIGGOOD SF_PRIVATE2 // Signature is good -#define SF_LOCALBAD SF_PRIVATE3 // Local checks failed -#define SF_LOCALGOOD SF_PRIVATE4 // Local checks passed +// These are the same flags defined as HashRouterFlags::PRIVATE1-4 in +// HashRouter.h +constexpr HashRouterFlags SF_SIGBAD = + HashRouterFlags::PRIVATE1; // Signature is bad +constexpr HashRouterFlags SF_SIGGOOD = + HashRouterFlags::PRIVATE2; // Signature is good +constexpr HashRouterFlags SF_LOCALBAD = + HashRouterFlags::PRIVATE3; // Local checks failed +constexpr HashRouterFlags SF_LOCALGOOD = + HashRouterFlags::PRIVATE4; // Local checks passed //------------------------------------------------------------------------------ @@ -66,11 +71,11 @@ checkValidity( return {Validity::Valid, ""}; } - if (flags & SF_SIGBAD) + if (any(flags & SF_SIGBAD)) // Signature is known bad return {Validity::SigBad, "Transaction has bad signature."}; - if (!(flags & SF_SIGGOOD)) + if (!any(flags & SF_SIGGOOD)) { // Don't know signature state. Check it. auto const requireCanonicalSig = @@ -88,12 +93,12 @@ checkValidity( } // Signature is now known good - if (flags & SF_LOCALBAD) + if (any(flags & SF_LOCALBAD)) // ...but the local checks // are known bad. return {Validity::SigGoodOnly, "Local checks failed."}; - if (flags & SF_LOCALGOOD) + if (any(flags & SF_LOCALGOOD)) // ...and the local checks // are known good. return {Validity::Valid, ""}; @@ -112,7 +117,7 @@ checkValidity( void forceValidity(HashRouter& router, uint256 const& txid, Validity validity) { - int flags = 0; + HashRouterFlags flags = HashRouterFlags::UNDEFINED; switch (validity) { case Validity::Valid: @@ -125,7 +130,7 @@ forceValidity(HashRouter& router, uint256 const& txid, Validity validity) // would be silly to call directly break; } - if (flags) + if (any(flags)) router.setFlags(txid, flags); } diff --git a/src/xrpld/consensus/Consensus.cpp b/src/xrpld/consensus/Consensus.cpp index fb57687df08..d4edb1445c9 100644 --- a/src/xrpld/consensus/Consensus.cpp +++ b/src/xrpld/consensus/Consensus.cpp @@ -139,11 +139,11 @@ checkConsensusReached( return false; } - // We only get stalled when every disputed transaction unequivocally has 80% - // (minConsensusPct) agreement, either for or against. That is: either under - // 20% or over 80% consensus (repectively "nay" or "yay"). This prevents - // manipulation by a minority of byzantine peers of which transactions make - // the cut to get into the ledger. + // We only get stalled when there are disputed transactions and all of them + // unequivocally have 80% (minConsensusPct) agreement, either for or + // against. That is: either under 20% or over 80% consensus (repectively + // "nay" or "yay"). This prevents manipulation by a minority of byzantine + // peers of which transactions make the cut to get into the ledger. if (stalled) { CLOG(clog) << "consensus stalled. "; diff --git a/src/xrpld/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h index f3265cf3810..df6cedccff1 100644 --- a/src/xrpld/consensus/Consensus.h +++ b/src/xrpld/consensus/Consensus.h @@ -84,8 +84,8 @@ shouldCloseLedger( agree @param stalled the network appears to be stalled, where neither we nor our peers have changed their vote on any disputes in a - while. This is undesirable, and will cause us to end consensus - without 80% agreement. + while. This is undesirable, and should be rare, and will cause us to + end consensus without 80% agreement. @param parms Consensus constant parameters @param proposing whether we should count ourselves @param j journal for logging @@ -1712,15 +1712,29 @@ Consensus::haveConsensus( << ", disagree=" << disagree; ConsensusParms const& parms = adaptor_.parms(); - // Stalling is BAD + // Stalling is BAD. It means that we have a consensus on the close time, so + // peers are talking, but we have disputed transactions that peers are + // unable or unwilling to come to agreement on one way or the other. bool const stalled = haveCloseTimeConsensus_ && + !result_->disputes.empty() && std::ranges::all_of(result_->disputes, - [this, &parms](auto const& dispute) { + [this, &parms, &clog](auto const& dispute) { return dispute.second.stalled( parms, mode_.get() == ConsensusMode::proposing, - peerUnchangedCounter_); + peerUnchangedCounter_, + j_, + clog); }); + if (stalled) + { + std::stringstream ss; + ss << "Consensus detects as stalled with " << (agree + disagree) << "/" + << prevProposers_ << " proposers, and " << result_->disputes.size() + << " stalled disputed transactions."; + JLOG(j_.error()) << ss.str(); + CLOG(clog) << ss.str(); + } // Determine if we actually have consensus or not result_->state = checkConsensus( diff --git a/src/xrpld/consensus/DisputedTx.h b/src/xrpld/consensus/DisputedTx.h index 4ed31b77ca5..e774c8366cd 100644 --- a/src/xrpld/consensus/DisputedTx.h +++ b/src/xrpld/consensus/DisputedTx.h @@ -85,7 +85,12 @@ class DisputedTx //! Are we and our peers "stalled" where we probably won't change //! our vote? bool - stalled(ConsensusParms const& p, bool proposing, int peersUnchanged) const + stalled( + ConsensusParms const& p, + bool proposing, + int peersUnchanged, + beast::Journal j, + std::unique_ptr const& clog) const { // at() can throw, but the map is built by hand to ensure all valid // values are available. @@ -123,8 +128,24 @@ class DisputedTx int const weight = support / total; // Returns true if the tx has more than minCONSENSUS_PCT (80) percent // agreement. Either voting for _or_ voting against the tx. - return weight > p.minCONSENSUS_PCT || - weight < (100 - p.minCONSENSUS_PCT); + bool const stalled = + weight > p.minCONSENSUS_PCT || weight < (100 - p.minCONSENSUS_PCT); + + if (stalled) + { + // stalling is an error condition for even a single + // transaction. + std::stringstream s; + s << "Transaction " << ID() << " is stalled. We have been voting " + << (getOurVote() ? "YES" : "NO") << " for " << currentVoteCounter_ + << " rounds. Peers have not changed their votes in " + << peersUnchanged << " rounds. The transaction has " << weight + << "% support. "; + JLOG(j_.error()) << s.str(); + CLOG(clog) << s.str(); + } + + return stalled; } //! The disputed transaction. diff --git a/src/xrpld/consensus/README.md b/src/xrpld/consensus/README.md index c8850a2a51a..3cc1294c4f8 100644 --- a/src/xrpld/consensus/README.md +++ b/src/xrpld/consensus/README.md @@ -1,9 +1,8 @@ # Consensus This directory contains the implementation of a -generic consensus algorithm. The implementation +generic consensus algorithm. The implementation follows a CRTP design, requiring client code to implement specific functions and types to use consensus in their -application. The interface is undergoing refactoring and +application. The interface is undergoing refactoring and is not yet finalized. - diff --git a/src/xrpld/core/JobQueue.h b/src/xrpld/core/JobQueue.h index 051c2982514..eda956c0194 100644 --- a/src/xrpld/core/JobQueue.h +++ b/src/xrpld/core/JobQueue.h @@ -30,6 +30,8 @@ #include +#include + namespace ripple { namespace perf { diff --git a/src/xrpld/ledger/PaymentSandbox.h b/src/xrpld/ledger/PaymentSandbox.h index a41a0211a29..2cd31ea490d 100644 --- a/src/xrpld/ledger/PaymentSandbox.h +++ b/src/xrpld/ledger/PaymentSandbox.h @@ -27,7 +27,6 @@ #include #include -#include namespace ripple { diff --git a/src/xrpld/ledger/View.h b/src/xrpld/ledger/View.h index 8c391499b6a..07f6945dd44 100644 --- a/src/xrpld/ledger/View.h +++ b/src/xrpld/ledger/View.h @@ -175,6 +175,29 @@ isFrozen( asset.value()); } +[[nodiscard]] inline TER +checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue) +{ + return isFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS; +} + +[[nodiscard]] inline TER +checkFrozen( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue) +{ + return isFrozen(view, account, mptIssue) ? (TER)tecLOCKED : (TER)tesSUCCESS; +} + +[[nodiscard]] inline TER +checkFrozen(ReadView const& view, AccountID const& account, Asset const& asset) +{ + return std::visit( + [&](auto const& issue) { return checkFrozen(view, account, issue); }, + asset.value()); +} + [[nodiscard]] bool isAnyFrozen( ReadView const& view, @@ -577,6 +600,16 @@ addEmptyHolding( asset.value()); } +[[nodiscard]] TER +authorizeMPToken( + ApplyView& view, + XRPAmount const& priorBalance, + MPTID const& mptIssuanceID, + AccountID const& account, + beast::Journal journal, + std::uint32_t flags = 0, + std::optional holderID = std::nullopt); + // VFALCO NOTE Both STAmount parameters should just // be "Amount", a unit-less number. // @@ -725,19 +758,40 @@ transferXRP( STAmount const& amount, beast::Journal j); -/* Check if MPToken exists: - * - StrongAuth - before checking lsfMPTRequireAuth is set - * - WeakAuth - after checking if lsfMPTRequireAuth is set +/* Check if MPToken (for MPT) or trust line (for IOU) exists: + * - StrongAuth - before checking if authorization is required + * - WeakAuth + * for MPT - after checking lsfMPTRequireAuth flag + * for IOU - do not check if trust line exists + * - Legacy + * for MPT - before checking lsfMPTRequireAuth flag i.e. same as StrongAuth + * for IOU - do not check if trust line exists i.e. same as WeakAuth */ -enum class MPTAuthType : bool { StrongAuth = true, WeakAuth = false }; +enum class AuthType { StrongAuth, WeakAuth, Legacy }; /** Check if the account lacks required authorization. * - * Return tecNO_AUTH or tecNO_LINE if it does - * and tesSUCCESS otherwise. + * Return tecNO_AUTH or tecNO_LINE if it does + * and tesSUCCESS otherwise. + * + * If StrongAuth then return tecNO_LINE if the RippleState doesn't exist. Return + * tecNO_AUTH if lsfRequireAuth is set on the issuer's AccountRoot, and the + * RippleState does exist, and the RippleState is not authorized. + * + * If WeakAuth then return tecNO_AUTH if lsfRequireAuth is set, and the + * RippleState exists, and is not authorized. Return tecNO_LINE if + * lsfRequireAuth is set and the RippleState doesn't exist. Consequently, if + * WeakAuth and lsfRequireAuth is *not* set, this function will return + * tesSUCCESS even if RippleState does *not* exist. + * + * The default "Legacy" auth type is equivalent to WeakAuth. */ [[nodiscard]] TER -requireAuth(ReadView const& view, Issue const& issue, AccountID const& account); +requireAuth( + ReadView const& view, + Issue const& issue, + AccountID const& account, + AuthType authType = AuthType::Legacy); /** Check if the account lacks required authorization. * @@ -751,32 +805,33 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account); * purely defensive, as we currently do not allow such vaults to be created. * * If StrongAuth then return tecNO_AUTH if MPToken doesn't exist or - * lsfMPTRequireAuth is set and MPToken is not authorized. If WeakAuth then - * return tecNO_AUTH if lsfMPTRequireAuth is set and MPToken doesn't exist or is - * not authorized (explicitly or via credentials, if DomainID is set in - * MPTokenIssuance). Consequently, if WeakAuth and lsfMPTRequireAuth is *not* - * set, this function will return true even if MPToken does *not* exist. + * lsfMPTRequireAuth is set and MPToken is not authorized. + * + * If WeakAuth then return tecNO_AUTH if lsfMPTRequireAuth is set and MPToken + * doesn't exist or is not authorized (explicitly or via credentials, if + * DomainID is set in MPTokenIssuance). Consequently, if WeakAuth and + * lsfMPTRequireAuth is *not* set, this function will return true even if + * MPToken does *not* exist. + * + * The default "Legacy" auth type is equivalent to StrongAuth. */ [[nodiscard]] TER requireAuth( ReadView const& view, MPTIssue const& mptIssue, AccountID const& account, - MPTAuthType authType = MPTAuthType::StrongAuth, + AuthType authType = AuthType::Legacy, int depth = 0); [[nodiscard]] TER inline requireAuth( ReadView const& view, Asset const& asset, AccountID const& account, - MPTAuthType authType = MPTAuthType::StrongAuth) + AuthType authType = AuthType::Legacy) { return std::visit( [&](TIss const& issue_) { - if constexpr (std::is_same_v) - return requireAuth(view, issue_, account); - else - return requireAuth(view, issue_, account, authType); + return requireAuth(view, issue_, account, authType); }, asset.value()); } diff --git a/src/xrpld/ledger/detail/View.cpp b/src/xrpld/ledger/detail/View.cpp index cb958190145..7c6e1d60f18 100644 --- a/src/xrpld/ledger/detail/View.cpp +++ b/src/xrpld/ledger/detail/View.cpp @@ -18,7 +18,6 @@ //============================================================================== #include -#include #include #include @@ -505,8 +504,8 @@ accountHolds( if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED && view.rules().enabled(featureSingleAssetVault)) { - if (auto const err = requireAuth( - view, mptIssue, account, MPTAuthType::StrongAuth); + if (auto const err = + requireAuth(view, mptIssue, account, AuthType::StrongAuth); !isTesSuccess(err)) amount.clear(mptIssue); } @@ -1215,12 +1214,115 @@ addEmptyHolding( if (view.peek(keylet::mptoken(mptID, accountID))) return tecDUPLICATE; - return MPTokenAuthorize::authorize( - view, - journal, - {.priorBalance = priorBalance, - .mptIssuanceID = mptID, - .account = accountID}); + return authorizeMPToken(view, priorBalance, mptID, accountID, journal); +} + +[[nodiscard]] TER +authorizeMPToken( + ApplyView& view, + XRPAmount const& priorBalance, + MPTID const& mptIssuanceID, + AccountID const& account, + beast::Journal journal, + std::uint32_t flags, + std::optional holderID) +{ + auto const sleAcct = view.peek(keylet::account(account)); + if (!sleAcct) + return tecINTERNAL; + + // If the account that submitted the tx is a holder + // Note: `account_` is holder's account + // `holderID` is NOT used + if (!holderID) + { + // When a holder wants to unauthorize/delete a MPT, the ledger must + // - delete mptokenKey from owner directory + // - delete the MPToken + if (flags & tfMPTUnauthorize) + { + auto const mptokenKey = keylet::mptoken(mptIssuanceID, account); + auto const sleMpt = view.peek(mptokenKey); + if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (!view.dirRemove( + keylet::ownerDir(account), + (*sleMpt)[sfOwnerNode], + sleMpt->key(), + false)) + return tecINTERNAL; // LCOV_EXCL_LINE + + adjustOwnerCount(view, sleAcct, -1, journal); + + view.erase(sleMpt); + return tesSUCCESS; + } + + // A potential holder wants to authorize/hold a mpt, the ledger must: + // - add the new mptokenKey to the owner directory + // - create the MPToken object for the holder + + // The reserve that is required to create the MPToken. Note + // that although the reserve increases with every item + // an account owns, in the case of MPTokens we only + // *enforce* a reserve if the user owns more than two + // items. This is similar to the reserve requirements of trust lines. + std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount); + XRPAmount const reserveCreate( + (uOwnerCount < 2) ? XRPAmount(beast::zero) + : view.fees().accountReserve(uOwnerCount + 1)); + + if (priorBalance < reserveCreate) + return tecINSUFFICIENT_RESERVE; + + auto const mptokenKey = keylet::mptoken(mptIssuanceID, account); + auto mptoken = std::make_shared(mptokenKey); + if (auto ter = dirLink(view, account, mptoken)) + return ter; // LCOV_EXCL_LINE + + (*mptoken)[sfAccount] = account; + (*mptoken)[sfMPTokenIssuanceID] = mptIssuanceID; + (*mptoken)[sfFlags] = 0; + view.insert(mptoken); + + // Update owner count. + adjustOwnerCount(view, sleAcct, 1, journal); + + return tesSUCCESS; + } + + auto const sleMptIssuance = view.read(keylet::mptIssuance(mptIssuanceID)); + if (!sleMptIssuance) + return tecINTERNAL; + + // If the account that submitted this tx is the issuer of the MPT + // Note: `account_` is issuer's account + // `holderID` is holder's account + if (account != (*sleMptIssuance)[sfIssuer]) + return tecINTERNAL; + + auto const sleMpt = view.peek(keylet::mptoken(mptIssuanceID, *holderID)); + if (!sleMpt) + return tecINTERNAL; + + std::uint32_t const flagsIn = sleMpt->getFieldU32(sfFlags); + std::uint32_t flagsOut = flagsIn; + + // Issuer wants to unauthorize the holder, unset lsfMPTAuthorized on + // their MPToken + if (flags & tfMPTUnauthorize) + flagsOut &= ~lsfMPTAuthorized; + // Issuer wants to authorize a holder, set lsfMPTAuthorized on their + // MPToken + else + flagsOut |= lsfMPTAuthorized; + + if (flagsIn != flagsOut) + sleMpt->setFieldU32(sfFlags, flagsOut); + + view.update(sleMpt); + return tesSUCCESS; } TER @@ -1418,13 +1520,14 @@ removeEmptyHolding( if (mptoken->at(sfMPTAmount) != 0) return tecHAS_OBLIGATIONS; - return MPTokenAuthorize::authorize( + return authorizeMPToken( view, + {}, // priorBalance + mptID, + accountID, journal, - {.priorBalance = {}, - .mptIssuanceID = mptID, - .account = accountID, - .flags = tfMPTUnauthorize}); + tfMPTUnauthorize // flags + ); } TER @@ -2298,15 +2401,27 @@ transferXRP( } TER -requireAuth(ReadView const& view, Issue const& issue, AccountID const& account) +requireAuth( + ReadView const& view, + Issue const& issue, + AccountID const& account, + AuthType authType) { if (isXRP(issue) || issue.account == account) return tesSUCCESS; + + auto const trustLine = + view.read(keylet::line(account, issue.account, issue.currency)); + // If account has no line, and this is a strong check, fail + if (!trustLine && authType == AuthType::StrongAuth) + return tecNO_LINE; + + // If this is a weak or legacy check, or if the account has a line, fail if + // auth is required and not set on the line if (auto const issuerAccount = view.read(keylet::account(issue.account)); issuerAccount && (*issuerAccount)[sfFlags] & lsfRequireAuth) { - if (auto const trustLine = - view.read(keylet::line(account, issue.account, issue.currency))) + if (trustLine) return ((*trustLine)[sfFlags] & ((account > issue.account) ? lsfLowAuth : lsfHighAuth)) ? tesSUCCESS @@ -2322,7 +2437,7 @@ requireAuth( ReadView const& view, MPTIssue const& mptIssue, AccountID const& account, - MPTAuthType authType, + AuthType authType, int depth) { auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); @@ -2357,7 +2472,7 @@ requireAuth( if (auto const err = std::visit( [&](TIss const& issue) { if constexpr (std::is_same_v) - return requireAuth(view, issue, account); + return requireAuth(view, issue, account, authType); else return requireAuth( view, issue, account, authType, depth + 1); @@ -2372,7 +2487,8 @@ requireAuth( auto const sleToken = view.read(mptokenID); // if account has no MPToken, fail - if (!sleToken && authType == MPTAuthType::StrongAuth) + if (!sleToken && + (authType == AuthType::StrongAuth || authType == AuthType::Legacy)) return tecNO_AUTH; // Note, this check is not amendment-gated because DomainID will be always @@ -2484,15 +2600,12 @@ enforceMPTokenAuthorization( XRPL_ASSERT( maybeDomainID.has_value() && sleToken == nullptr, "ripple::enforceMPTokenAuthorization : new MPToken for domain"); - if (auto const err = MPTokenAuthorize::authorize( + if (auto const err = authorizeMPToken( view, - j, - { - .priorBalance = priorBalance, - .mptIssuanceID = mptIssuanceID, - .account = account, - .flags = 0, - }); + priorBalance, // priorBalance + mptIssuanceID, // mptIssuanceID + account, // account + j); !isTesSuccess(err)) return err; diff --git a/src/xrpld/nodestore/README.md b/src/xrpld/nodestore/README.md index 1549c1ef968..a5d1128d179 100644 --- a/src/xrpld/nodestore/README.md +++ b/src/xrpld/nodestore/README.md @@ -1,6 +1,7 @@ # Database Documentation -* [NodeStore](#nodestore) -* [Benchmarks](#benchmarks) + +- [NodeStore](#nodestore) +- [Benchmarks](#benchmarks) # NodeStore @@ -12,41 +13,43 @@ identified by the hash, which is a 256 bit hash of the blob. The blob is a variable length block of serialized data. The type identifies what the blob contains. The fields are as follows: -* `mType` +- `mType` + +An enumeration that determines what the blob holds. There are four +different types of objects stored. - An enumeration that determines what the blob holds. There are four - different types of objects stored. +- **ledger** - * **ledger** + A ledger header. - A ledger header. +- **transaction** - * **transaction** + A signed transaction. - A signed transaction. +- **account node** - * **account node** + A node in a ledger's account state tree. - A node in a ledger's account state tree. +- **transaction node** - * **transaction node** + A node in a ledger's transaction tree. - A node in a ledger's transaction tree. +- `mHash` -* `mHash` +A 256-bit hash of the blob. - A 256-bit hash of the blob. +- `mData` -* `mData` +A blob containing the payload. Stored in the following format. - A blob containing the payload. Stored in the following format. +| Byte | | | +| :------ | :----- | :------------------------- | +| 0...7 | unused | | +| 8 | type | NodeObjectType enumeration | +| 9...end | data | body of the object data | -|Byte | | | -|:------|:--------------------|:-------------------------| -|0...7 |unused | | -|8 |type |NodeObjectType enumeration| -|9...end|data |body of the object data | --- + The `NodeStore` provides an interface that stores, in a persistent database, a collection of NodeObjects that rippled uses as its primary representation of ledger entries. All ledger entries are stored as NodeObjects and as such, need @@ -64,41 +67,42 @@ the configuration file [node_db] section as follows. One or more lines of key / value pairs Example: + ``` type=RocksDB path=rocksdb compression=1 ``` + Choices for 'type' (not case-sensitive) -* **HyperLevelDB** +- **HyperLevelDB** - An improved version of LevelDB (preferred). +An improved version of LevelDB (preferred). -* **LevelDB** +- **LevelDB** - Google's LevelDB database (deprecated). +Google's LevelDB database (deprecated). -* **none** +- **none** - Use no backend. +Use no backend. -* **RocksDB** +- **RocksDB** - Facebook's RocksDB database, builds on LevelDB. +Facebook's RocksDB database, builds on LevelDB. -* **SQLite** +- **SQLite** - Use SQLite. +Use SQLite. 'path' speficies where the backend will store its data files. Choices for 'compression' -* **0** off - -* **1** on (default) +- **0** off +- **1** on (default) # Benchmarks @@ -129,48 +133,48 @@ RocksDBQuickFactory is intended to provide a testbed for comparing potential rocksdb performance with the existing recommended configuration in rippled.cfg. Through various executions and profiling some conclusions are presented below. -* If the write ahead log is enabled, insert speed soon clogs up under load. The -BatchWriter class intends to stop this from blocking the main threads by queuing -up writes and running them in a separate thread. However, rocksdb already has -separate threads dedicated to flushing the memtable to disk and the memtable is -itself an in-memory queue. The result is two queues with a guarantee of -durability in between. However if the memtable was used as the sole queue and -the rocksdb::Flush() call was manually triggered at opportune moments, possibly -just after ledger close, then that would provide similar, but more predictable -guarantees. It would also remove an unneeded thread and unnecessary memory -usage. An alternative point of view is that because there will always be many -other rippled instances running there is no need for such guarantees. The nodes -will always be available from another peer. - -* Lookup in a block was previously using binary search. With rippled's use case -it is highly unlikely that two adjacent key/values will ever be requested one -after the other. Therefore hash indexing of blocks makes much more sense. -Rocksdb has a number of options for hash indexing both memtables and blocks and -these need more testing to find the best choice. - -* The current Database implementation has two forms of caching, so the LRU cache -of blocks at Factory level does not make any sense. However, if the hash -indexing and potentially the new [bloom -filter](http://rocksdb.org/blog/1427/new-bloom-filter-format/) can provide -faster lookup for non-existent keys, then potentially the caching could exist at -Factory level. - -* Multiple runs of the benchmarks can yield surprisingly different results. This -can perhaps be attributed to the asynchronous nature of rocksdb's compaction -process. The benchmarks are artifical and create highly unlikely write load to -create the dataset to measure different read access patterns. Therefore multiple -runs of the benchmarks are required to get a feel for the effectiveness of the -changes. This contrasts sharply with the keyvadb benchmarking were highly -repeatable timings were discovered. Also realistically sized datasets are -required to get a correct insight. The number of 2,000,000 key/values (actually -4,000,000 after the two insert benchmarks complete) is too low to get a full -picture. - -* An interesting side effect of running the benchmarks in a profiler was that a -clear pattern of what RocksDB does under the hood was observable. This led to -the decision to trial hash indexing and also the discovery of the native CRC32 -instruction not being used. - -* Important point to note that is if this factory is tested with an existing set -of sst files none of the old sst files will benefit from indexing changes until -they are compacted at a future point in time. +- If the write ahead log is enabled, insert speed soon clogs up under load. The + BatchWriter class intends to stop this from blocking the main threads by queuing + up writes and running them in a separate thread. However, rocksdb already has + separate threads dedicated to flushing the memtable to disk and the memtable is + itself an in-memory queue. The result is two queues with a guarantee of + durability in between. However if the memtable was used as the sole queue and + the rocksdb::Flush() call was manually triggered at opportune moments, possibly + just after ledger close, then that would provide similar, but more predictable + guarantees. It would also remove an unneeded thread and unnecessary memory + usage. An alternative point of view is that because there will always be many + other rippled instances running there is no need for such guarantees. The nodes + will always be available from another peer. + +- Lookup in a block was previously using binary search. With rippled's use case + it is highly unlikely that two adjacent key/values will ever be requested one + after the other. Therefore hash indexing of blocks makes much more sense. + Rocksdb has a number of options for hash indexing both memtables and blocks and + these need more testing to find the best choice. + +- The current Database implementation has two forms of caching, so the LRU cache + of blocks at Factory level does not make any sense. However, if the hash + indexing and potentially the new [bloom + filter](http://rocksdb.org/blog/1427/new-bloom-filter-format/) can provide + faster lookup for non-existent keys, then potentially the caching could exist at + Factory level. + +- Multiple runs of the benchmarks can yield surprisingly different results. This + can perhaps be attributed to the asynchronous nature of rocksdb's compaction + process. The benchmarks are artifical and create highly unlikely write load to + create the dataset to measure different read access patterns. Therefore multiple + runs of the benchmarks are required to get a feel for the effectiveness of the + changes. This contrasts sharply with the keyvadb benchmarking were highly + repeatable timings were discovered. Also realistically sized datasets are + required to get a correct insight. The number of 2,000,000 key/values (actually + 4,000,000 after the two insert benchmarks complete) is too low to get a full + picture. + +- An interesting side effect of running the benchmarks in a profiler was that a + clear pattern of what RocksDB does under the hood was observable. This led to + the decision to trial hash indexing and also the discovery of the native CRC32 + instruction not being used. + +- Important point to note that is if this factory is tested with an existing set + of sst files none of the old sst files will benefit from indexing changes until + they are compacted at a future point in time. diff --git a/src/xrpld/overlay/README.md b/src/xrpld/overlay/README.md index 6525e5edf86..cd004889154 100644 --- a/src/xrpld/overlay/README.md +++ b/src/xrpld/overlay/README.md @@ -39,10 +39,10 @@ The HTTP [request](https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html) must: - Use HTTP version 1.1. - Specify a request URI consisting of a single forward slash character ("/") -indicating the server root. Requests using different URIs are reserved for -future protocol implementations. + indicating the server root. Requests using different URIs are reserved for + future protocol implementations. - Use the [_HTTP/1.1 Upgrade_][upgrade_header] mechanism with additional custom -fields to communicate protocol specific information related to the upgrade. + fields to communicate protocol specific information related to the upgrade. HTTP requests which do not conform to this requirements must generate an appropriate HTTP error and result in the connection being closed. @@ -72,7 +72,6 @@ Previous-Ledger: q4aKbP7sd5wv+EXArwCmQiWZhq9AwBl2p/hCtpGJNsc= ##### Example HTTP Upgrade Response (Success) - ``` HTTP/1.1 101 Switching Protocols Connection: Upgrade @@ -102,9 +101,9 @@ Content-Type: application/json #### Standard Fields -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `User-Agent` | :heavy_check_mark: | | +| Field Name | Request | Response | +| ------------ | :----------------: | :------: | +| `User-Agent` | :heavy_check_mark: | | The `User-Agent` field indicates the version of the software that the peer that is making the HTTP request is using. No semantic meaning is @@ -113,9 +112,9 @@ specify the version of the software that is used. See [RFC2616 §14.43](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43). -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Server` | | :heavy_check_mark: | +| Field Name | Request | Response | +| ---------- | :-----: | :----------------: | +| `Server` | | :heavy_check_mark: | The `Server` field indicates the version of the software that the peer that is processing the HTTP request is using. No semantic meaning is @@ -124,18 +123,18 @@ specify the version of the software that is used. See [RFC2616 §14.38](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.38). -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Connection` | :heavy_check_mark: | :heavy_check_mark: | +| Field Name | Request | Response | +| ------------ | :----------------: | :----------------: | +| `Connection` | :heavy_check_mark: | :heavy_check_mark: | The `Connection` field should have a value of `Upgrade` to indicate that a request to upgrade the connection is being performed. See [RFC2616 §14.10](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10). -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Upgrade` | :heavy_check_mark: | :heavy_check_mark: | +| Field Name | Request | Response | +| ---------- | :----------------: | :----------------: | +| `Upgrade` | :heavy_check_mark: | :heavy_check_mark: | The `Upgrade` field is part of the standard connection upgrade mechanism and must be present in both requests and responses. It is used to negotiate the @@ -156,12 +155,11 @@ equal to 2 and the minor is greater than or equal to 0. See [RFC 2616 §14.42](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42) - #### Custom Fields -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Connect-As` | :heavy_check_mark: | :heavy_check_mark: | +| Field Name | Request | Response | +| ------------ | :----------------: | :----------------: | +| `Connect-As` | :heavy_check_mark: | :heavy_check_mark: | The mandatory `Connect-As` field is used to specify that type of connection that is being requested. @@ -175,10 +173,9 @@ elements specified in the request. If a server processing a request does not recognize any of the connection types, the request should fail with an appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response). - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Remote-IP` | :white_check_mark: | :white_check_mark: | +| Field Name | Request | Response | +| ----------- | :----------------: | :----------------: | +| `Remote-IP` | :white_check_mark: | :white_check_mark: | The optional `Remote-IP` field contains the string representation of the IP address of the remote end of the connection as seen from the peer that is @@ -187,10 +184,9 @@ sending the field. By observing values of this field from a sufficient number of different servers, a peer making outgoing connections can deduce its own IP address. - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Local-IP` | :white_check_mark: | :white_check_mark: | +| Field Name | Request | Response | +| ---------- | :----------------: | :----------------: | +| `Local-IP` | :white_check_mark: | :white_check_mark: | The optional `Local-IP` field contains the string representation of the IP address that the peer sending the field believes to be its own. @@ -198,10 +194,9 @@ address that the peer sending the field believes to be its own. Servers receiving this field can detect IP address mismatches, which may indicate a potential man-in-the-middle attack. - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Network-ID` | :white_check_mark: | :white_check_mark: | +| Field Name | Request | Response | +| ------------ | :----------------: | :----------------: | +| `Network-ID` | :white_check_mark: | :white_check_mark: | The optional `Network-ID` can be used to identify to which of several [parallel networks](https://xrpl.org/parallel-networks.html) the server @@ -217,10 +212,9 @@ If a server configured to join one network receives a connection request from a server configured to join another network, the request should fail with an appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response). - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Network-Time` | :white_check_mark: | :white_check_mark: | +| Field Name | Request | Response | +| -------------- | :----------------: | :----------------: | +| `Network-Time` | :white_check_mark: | :white_check_mark: | The optional `Network-Time` field reports the current [time](https://xrpl.org/basic-data-types.html#specifying-time) according to sender's internal clock. @@ -232,20 +226,18 @@ each other with an appropriate HTTP error code (e.g. by sending an HTTP 400 It is highly recommended that servers synchronize their clocks using time synchronization software. For more on this topic, please visit [ntp.org](http://www.ntp.org/). - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Public-Key` | :heavy_check_mark: | :heavy_check_mark: | +| Field Name | Request | Response | +| ------------ | :----------------: | :----------------: | +| `Public-Key` | :heavy_check_mark: | :heavy_check_mark: | The mandatory `Public-Key` field identifies the sending server's public key, encoded in base58 using the standard encoding for node public keys. See: https://xrpl.org/base58-encodings.html - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Server-Domain` | :white_check_mark: | :white_check_mark: | +| Field Name | Request | Response | +| --------------- | :----------------: | :----------------: | +| `Server-Domain` | :white_check_mark: | :white_check_mark: | The optional `Server-Domain` field allows a server to report the domain that it is operating under. The value is configured by the server administrator in @@ -259,10 +251,9 @@ under the specified domain and locating the public key of this server under the Sending a malformed domain will prevent a connection from being established. - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Session-Signature` | :heavy_check_mark: | :heavy_check_mark: | +| Field Name | Request | Response | +| ------------------- | :----------------: | :----------------: | +| `Session-Signature` | :heavy_check_mark: | :heavy_check_mark: | The `Session-Signature` field is mandatory and is used to secure the peer link against certain types of attack. For more details see "Session Signature" below. @@ -272,36 +263,35 @@ should support both **Base64** and **HEX** encoding for this value. For more details on this field, please see **Session Signature** below. - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Crawl` | :white_check_mark: | :white_check_mark: | +| Field Name | Request | Response | +| ---------- | :----------------: | :----------------: | +| `Crawl` | :white_check_mark: | :white_check_mark: | The optional `Crawl` field can be used by a server to indicate whether peers should include it in crawl reports. The field can take two values: + - **`Public`**: The server's IP address and port should be included in crawl -reports. + reports. - **`Private`**: The server's IP address and port should not be included in -crawl reports. _This is the default, if the field is omitted._ + crawl reports. _This is the default, if the field is omitted._ For more on the Peer Crawler, please visit https://xrpl.org/peer-crawler.html. - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Closed-Ledger` | :white_check_mark: | :white_check_mark: | +| Field Name | Request | Response | +| --------------- | :----------------: | :----------------: | +| `Closed-Ledger` | :white_check_mark: | :white_check_mark: | If present, identifies the hash of the last ledger that the sending server considers to be closed. The value is encoded as **HEX**, but implementations should support both **Base64** and **HEX** encoding for this value for legacy purposes. - -| Field Name | Request | Response | -|--------------------- |:-----------------: |:-----------------: | -| `Previous-Ledger` | :white_check_mark: | :white_check_mark: | + +| Field Name | Request | Response | +| ----------------- | :----------------: | :----------------: | +| `Previous-Ledger` | :white_check_mark: | :white_check_mark: | If present, identifies the hash of the parent ledger that the sending server considers to be closed. @@ -317,7 +307,6 @@ and values in both requests and responses. Implementations should not reject requests because of the presence of fields that they do not understand. - ### Session Signature Even for SSL/TLS encrypted connections, it is possible for an attacker to mount @@ -365,8 +354,7 @@ transferred between A and B and will not be able to intelligently tamper with th message stream between Alice and Bob, although she may be still be able to inject delays or terminate the link. - -# Ripple Clustering # +# Ripple Clustering A cluster consists of more than one Ripple server under common administration that share load information, distribute cryptography @@ -374,19 +362,19 @@ operations, and provide greater response consistency. Cluster nodes are identified by their public node keys. Cluster nodes exchange information about endpoints that are imposing load upon them. -Cluster nodes share information about their internal load status. Cluster +Cluster nodes share information about their internal load status. Cluster nodes do not have to verify the cryptographic signatures on messages received from other cluster nodes. -## Configuration ## +## Configuration A server's public key can be determined from the output of the `server_info` -command. The key is in the `pubkey_node` value, and is a text string -beginning with the letter `n`. The key is maintained across runs in a +command. The key is in the `pubkey_node` value, and is a text string +beginning with the letter `n`. The key is maintained across runs in a database. Cluster members are configured in the `rippled.cfg` file under -`[cluster_nodes]`. Each member should be configured on a line beginning +`[cluster_nodes]`. Each member should be configured on a line beginning with the node public key, followed optionally by a space and a friendly name. @@ -404,23 +392,23 @@ New spokes can be added as follows: - Restart each hub, one by one - Restart the spoke -## Transaction Behavior ## +## Transaction Behavior When a transaction is received from a cluster member, several normal checks are bypassed: Signature checking is bypassed because we trust that a cluster member would -not relay a transaction with an incorrect signature. Validators may wish to +not relay a transaction with an incorrect signature. Validators may wish to disable this feature, preferring the additional load to get the additional security of having validators check each transaction. Local checks for transaction checking are also bypassed. For example, a server will not reject a transaction from a cluster peer because the fee -does not meet its current relay fee. It is preferable to keep the cluster +does not meet its current relay fee. It is preferable to keep the cluster in agreement and permit confirmation from one cluster member to more reliably indicate the transaction's acceptance by the cluster. -## Server Load Information ## +## Server Load Information Cluster members exchange information on their server's load level. The load level is essentially the amount by which the normal fee levels are multiplied @@ -431,22 +419,22 @@ fee, is the highest of its local load level, the network load level, and the cluster load level. The cluster load level is the median load level reported by a cluster member. -## Gossip ## +## Gossip Gossip is the mechanism by which cluster members share information about endpoints (typically IPv4 addresses) that are imposing unusually high load -on them. The endpoint load manager takes into account gossip to reduce the +on them. The endpoint load manager takes into account gossip to reduce the amount of load the endpoint is permitted to impose on the local server before it is warned, disconnected, or banned. Suppose, for example, that an attacker controls a large number of IP addresses, and with these, he can send sufficient requests to overload a -server. Without gossip, he could use these same addresses to overload all -the servers in a cluster. With gossip, if he chooses to use the same IP +server. Without gossip, he could use these same addresses to overload all +the servers in a cluster. With gossip, if he chooses to use the same IP address to impose load on more than one server, he will find that the amount of load he can impose before getting disconnected is much lower. -## Monitoring ## +## Monitoring The `peers` command will report on the status of the cluster. The `cluster` object will contain one entry for each member of the cluster (either configured diff --git a/src/xrpld/overlay/Slot.h b/src/xrpld/overlay/Slot.h index 0956eb06f76..ea9fc3285ba 100644 --- a/src/xrpld/overlay/Slot.h +++ b/src/xrpld/overlay/Slot.h @@ -446,6 +446,8 @@ Slot::deletePeer(PublicKey const& validator, id_t id, bool erase) auto it = peers_.find(id); if (it != peers_.end()) { + std::vector toUnsquelch; + JLOG(journal_.trace()) << "deletePeer: " << Slice(validator) << " " << id << " selected " << (it->second.state == PeerState::Selected) << " considered " @@ -457,7 +459,7 @@ Slot::deletePeer(PublicKey const& validator, id_t id, bool erase) for (auto& [k, v] : peers_) { if (v.state == PeerState::Squelched) - handler_.unsquelch(validator, k); + toUnsquelch.push_back(k); v.state = PeerState::Counting; v.count = 0; v.expire = now; @@ -479,6 +481,10 @@ Slot::deletePeer(PublicKey const& validator, id_t id, bool erase) if (erase) peers_.erase(it); + + // Must be after peers_.erase(it) + for (auto const& k : toUnsquelch) + handler_.unsquelch(validator, k); } } diff --git a/src/xrpld/overlay/detail/ConnectAttempt.cpp b/src/xrpld/overlay/detail/ConnectAttempt.cpp index 84fbd36d321..61049579c53 100644 --- a/src/xrpld/overlay/detail/ConnectAttempt.cpp +++ b/src/xrpld/overlay/detail/ConnectAttempt.cpp @@ -379,7 +379,7 @@ ConnectAttempt::processResponse() auto const result = overlay_.peerFinder().activate( slot_, publicKey, static_cast(member)); if (result != PeerFinder::Result::success) - return fail("Outbound slots full"); + return fail("Outbound " + std::string(to_string(result))); auto const peer = std::make_shared( app_, diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index 3cc5b2a0242..874f951f563 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -41,8 +42,6 @@ #include -#include "xrpld/overlay/detail/TrafficCount.h" - namespace ripple { namespace CrawlOptions { @@ -269,8 +268,8 @@ OverlayImpl::onHandoff( if (result != PeerFinder::Result::success) { m_peerFinder->on_closed(slot); - JLOG(journal.debug()) - << "Peer " << remote_endpoint << " redirected, slots full"; + JLOG(journal.debug()) << "Peer " << remote_endpoint + << " redirected, " << to_string(result); handoff.moved = false; handoff.response = makeRedirectResponse( slot, request, remote_endpoint.address()); @@ -1423,7 +1422,12 @@ OverlayImpl::updateSlotAndSquelch( if (!strand_.running_in_this_thread()) return post( strand_, - [this, key, validator, peers = std::move(peers), type]() mutable { + // Must capture copies of reference parameters (i.e. key, validator) + [this, + key = key, + validator = validator, + peers = std::move(peers), + type]() mutable { updateSlotAndSquelch(key, validator, std::move(peers), type); }); @@ -1444,9 +1448,12 @@ OverlayImpl::updateSlotAndSquelch( return; if (!strand_.running_in_this_thread()) - return post(strand_, [this, key, validator, peer, type]() { - updateSlotAndSquelch(key, validator, peer, type); - }); + return post( + strand_, + // Must capture copies of reference parameters (i.e. key, validator) + [this, key = key, validator = validator, peer, type]() { + updateSlotAndSquelch(key, validator, peer, type); + }); slots_.updateSlotAndSquelch(key, validator, peer, type, [&]() { reportInboundTraffic(TrafficCount::squelch_ignored, 0); diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 1238833d0da..23b47604881 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -1296,13 +1296,13 @@ PeerImp::handleTransaction( } // LCOV_EXCL_STOP - int flags; + HashRouterFlags flags; constexpr std::chrono::seconds tx_interval = 10s; if (!app_.getHashRouter().shouldProcess(txID, id_, flags, tx_interval)) { // we have seen this transaction recently - if (flags & SF_BAD) + if (any(flags & HashRouterFlags::BAD)) { fee_.update(Resource::feeUselessData, "known bad"); JLOG(p_journal_.debug()) << "Ignoring known bad tx " << txID; @@ -1329,7 +1329,7 @@ PeerImp::handleTransaction( { // Skip local checks if a server we trust // put the transaction in its open ledger - flags |= SF_TRUSTED; + flags |= HashRouterFlags::TRUSTED; } // for non-validator nodes only -- localPublicKey is set for @@ -2841,7 +2841,7 @@ PeerImp::doTransactions( void PeerImp::checkTransaction( - int flags, + HashRouterFlags flags, bool checkSignature, std::shared_ptr const& stx, bool batch) @@ -2866,7 +2866,8 @@ PeerImp::checkTransaction( (stx->getFieldU32(sfLastLedgerSequence) < app_.getLedgerMaster().getValidLedgerIndex())) { - app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD); + app_.getHashRouter().setFlags( + stx->getTransactionID(), HashRouterFlags::BAD); charge(Resource::feeUselessData, "expired tx"); return; } @@ -2925,8 +2926,10 @@ PeerImp::checkTransaction( << "Exception checking transaction: " << validReason; } - // Probably not necessary to set SF_BAD, but doesn't hurt. - app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD); + // Probably not necessary to set HashRouterFlags::BAD, but + // doesn't hurt. + app_.getHashRouter().setFlags( + stx->getTransactionID(), HashRouterFlags::BAD); charge( Resource::feeInvalidSignature, "check transaction signature failure"); @@ -2949,12 +2952,13 @@ PeerImp::checkTransaction( JLOG(p_journal_.trace()) << "Exception checking transaction: " << reason; } - app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD); + app_.getHashRouter().setFlags( + stx->getTransactionID(), HashRouterFlags::BAD); charge(Resource::feeInvalidSignature, "tx (impossible)"); return; } - bool const trusted(flags & SF_TRUSTED); + bool const trusted = any(flags & HashRouterFlags::TRUSTED); app_.getOPs().processTransaction( tx, trusted, false, NetworkOPs::FailHard::no); } @@ -2962,7 +2966,8 @@ PeerImp::checkTransaction( { JLOG(p_journal_.warn()) << "Exception in " << __func__ << ": " << ex.what(); - app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD); + app_.getHashRouter().setFlags( + stx->getTransactionID(), HashRouterFlags::BAD); using namespace std::string_literals; charge(Resource::feeInvalidData, "tx "s + ex.what()); } diff --git a/src/xrpld/overlay/detail/PeerImp.h b/src/xrpld/overlay/detail/PeerImp.h index ecd3fc7f63f..5aa49fd1521 100644 --- a/src/xrpld/overlay/detail/PeerImp.h +++ b/src/xrpld/overlay/detail/PeerImp.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -98,7 +99,7 @@ class PeerImp : public Peer, // Node public key of peer. PublicKey const publicKey_; std::string name_; - boost::shared_mutex mutable nameMutex_; + std::shared_mutex mutable nameMutex_; // The indices of the smallest and largest ledgers this peer has available // @@ -214,7 +215,7 @@ class PeerImp : public Peer, total_bytes() const; private: - boost::shared_mutex mutable mutex_; + std::shared_mutex mutable mutex_; boost::circular_buffer rollingAvg_{30, 0ull}; clock_type::time_point intervalStart_{clock_type::now()}; std::uint64_t totalBytes_{0}; @@ -612,7 +613,7 @@ class PeerImp : public Peer, void checkTransaction( - int flags, + HashRouterFlags flags, bool checkSignature, std::shared_ptr const& stx, bool batch); diff --git a/src/xrpld/peerfinder/PeerfinderManager.h b/src/xrpld/peerfinder/PeerfinderManager.h index a670fb87802..f399251c381 100644 --- a/src/xrpld/peerfinder/PeerfinderManager.h +++ b/src/xrpld/peerfinder/PeerfinderManager.h @@ -28,6 +28,8 @@ #include +#include + namespace ripple { namespace PeerFinder { @@ -136,6 +138,36 @@ using Endpoints = std::vector; /** Possible results from activating a slot. */ enum class Result { duplicate, full, success }; +/** + * @brief Converts a `Result` enum value to its string representation. + * + * This function provides a human-readable string for a given `Result` enum, + * which is useful for logging, debugging, or displaying status messages. + * + * @param result The `Result` enum value to convert. + * @return A `std::string_view` representing the enum value. Returns "unknown" + * if the enum value is not explicitly handled. + * + * @note This function returns a `std::string_view` for performance. + * A `std::string` would need to allocate memory on the heap and copy the + * string literal into it every time the function is called. + */ +inline std::string_view +to_string(Result result) noexcept +{ + switch (result) + { + case Result::success: + return "success"; + case Result::duplicate: + return "duplicate connection"; + case Result::full: + return "slots full"; + } + + return "unknown"; +} + /** Maintains a set of IP addresses used for getting into the network. */ class Manager : public beast::PropertyStream::Source { diff --git a/src/xrpld/peerfinder/README.md b/src/xrpld/peerfinder/README.md index ab1ac4491a6..a3f89fd4468 100644 --- a/src/xrpld/peerfinder/README.md +++ b/src/xrpld/peerfinder/README.md @@ -1,4 +1,3 @@ - # PeerFinder ## Introduction @@ -31,23 +30,23 @@ slots_. PeerFinder has these responsibilities -* Maintain a persistent set of endpoint addresses suitable for bootstrapping +- Maintain a persistent set of endpoint addresses suitable for bootstrapping into the peer to peer overlay, ranked by relative locally observed utility. -* Send and receive protocol messages for discovery of endpoint addresses. +- Send and receive protocol messages for discovery of endpoint addresses. -* Provide endpoint addresses to new peers that need them. +- Provide endpoint addresses to new peers that need them. -* Maintain connections to a configured set of fixed peers. +- Maintain connections to a configured set of fixed peers. -* Impose limits on the various slots consumed by peer connections. +- Impose limits on the various slots consumed by peer connections. -* Initiate outgoing connection attempts to endpoint addresses to maintain the +- Initiate outgoing connection attempts to endpoint addresses to maintain the overlay connectivity and fixed peer policies. -* Verify the connectivity of neighbors who advertise inbound connection slots. +- Verify the connectivity of neighbors who advertise inbound connection slots. -* Prevent duplicate connections and connections to self. +- Prevent duplicate connections and connections to self. --- @@ -79,28 +78,28 @@ The `Config` structure defines the operational parameters of the PeerFinder. Some values come from the configuration file while others are calculated via tuned heuristics. The fields are as follows: -* `autoConnect` - +- `autoConnect` + A flag indicating whether or not the Autoconnect feature is enabled. -* `wantIncoming` +- `wantIncoming` A flag indicating whether or not the peer desires inbound connections. When this flag is turned off, a peer will not advertise itself in Endpoint messages. -* `listeningPort` +- `listeningPort` The port number to use when creating the listening socket for peer connections. -* `maxPeers` +- `maxPeers` The largest number of active peer connections to allow. This includes inbound and outbound connections, but excludes fixed and cluster peers. There is an implementation defined floor on this value. -* `outPeers` +- `outPeers` The number of automatic outbound connections that PeerFinder will maintain when the Autoconnect feature is enabled. The value is computed with fractional @@ -161,8 +160,8 @@ Endpoint messages are received from the overlay over time. The `Bootcache` stores IP addresses useful for gaining initial connections. Each address is associated with the following metadata: - -* **Valence** + +- **Valence** A signed integer which represents the number of successful consecutive connection attempts when positive, and the number of @@ -202,30 +201,30 @@ a slot. Slots have properties and state associated with them: The slot state represents the current stage of the connection as it passes through the business logic for establishing peer connections. -* `accept` +- `accept` The accept state is an initial state resulting from accepting an incoming connection request on a listening socket. The remote IP address and port are known, and a handshake is expected next. -* `connect` +- `connect` The connect state is an initial state used when actively establishing outbound connection attempts. The desired remote IP address and port are known. -* `connected` +- `connected` When an outbound connection attempt succeeds, it moves to the connected state. The handshake is initiated but not completed. -* `active` +- `active` The state becomes Active when a connection in either the Accepted or Connected state completes the handshake process, and a slot is available based on the properties. If no slot is available when the handshake completes, the socket is gracefully closed. -* `closing` +- `closing` The Closing state represents a connected socket in the process of being gracefully closed. @@ -234,13 +233,13 @@ through the business logic for establishing peer connections. Slot properties may be combined and are not mutually exclusive. -* **Inbound** +- **Inbound** An inbound slot is the condition of a socket which has accepted an incoming connection request. A connection which is not inbound is by definition outbound. -* **Fixed** +- **Fixed** A fixed slot is a desired connection to a known peer identified by IP address, usually entered manually in the configuration file. For the purpose of @@ -248,14 +247,14 @@ Slot properties may be combined and are not mutually exclusive. although only the IP address is checked to determine if the fixed peer is already connected. Fixed slots do not count towards connection limits. -* **Cluster** +- **Cluster** A cluster slot is a connection which has completed the handshake stage, whose public key matches a known public key usually entered manually in the configuration file or learned through overlay messages from other trusted peers. Cluster slots do not count towards connection limits. -* **Superpeer** (forthcoming) +- **Superpeer** (forthcoming) A superpeer slot is a connection to a peer which can accept incoming connections, meets certain resource availaibility requirements (such as @@ -279,7 +278,7 @@ Cluster slots are identified by the public key and set up during the initialization of the manager or discovered upon receipt of messages in the overlay from trusted connections. --------------------------------------------------------------------------------- +--- # Algorithms @@ -295,8 +294,8 @@ This stage is invoked when the number of active fixed connections is below the number of fixed connections specified in the configuration, and one of the following is true: -* There are eligible fixed addresses to try -* Any outbound connection attempts are in progress +- There are eligible fixed addresses to try +- Any outbound connection attempts are in progress Each fixed address is associated with a retry timer. On a fixed connection failure, the timer is reset so that the address is not tried for some amount @@ -317,8 +316,8 @@ The Livecache is invoked when Stage 1 is not active, autoconnect is enabled, and the number of active outbound connections is below the number desired. The stage remains active while: -* The Livecache has addresses to try -* Any outbound connection attempts are in progress +- The Livecache has addresses to try +- Any outbound connection attempts are in progress PeerFinder makes its best effort to exhaust addresses in the Livecache before moving on to the Bootcache, because Livecache addresses are highly likely @@ -333,7 +332,7 @@ The Bootcache is invoked when Stage 1 and Stage 2 are not active, autoconnect is enabled, and the number of active outbound connections is below the number desired. The stage remains active while: -* There are addresses in the cache that have not been tried recently. +- There are addresses in the cache that have not been tried recently. Entries in the Bootcache are ranked, with highly connectible addresses preferred over others. Connection attempts to Bootcache addresses are very likely to @@ -342,7 +341,7 @@ not have open slots. Before the remote peer closes the connection it will send a handful of addresses from its Livecache to help the new peer coming online obtain connections. --------------------------------------------------------------------------------- +--- # References @@ -352,10 +351,11 @@ Much of the work in PeerFinder was inspired by earlier work in Gnutella: _By Christopher Rohrs and Vincent Falco_ [Gnutella 0.6 Protocol:](http://rfc-gnutella.sourceforge.net/src/rfc-0_6-draft.html) Sections: -* 2.2.2 Ping (0x00) -* 2.2.3 Pong (0x01) -* 2.2.4 Use of Ping and Pong messages -* 2.2.4.1 A simple pong caching scheme -* 2.2.4.2 Other pong caching schemes + +- 2.2.2 Ping (0x00) +- 2.2.3 Pong (0x01) +- 2.2.4 Use of Ping and Pong messages +- 2.2.4.1 A simple pong caching scheme +- 2.2.4.2 Other pong caching schemes [overlay_network]: http://en.wikipedia.org/wiki/Overlay_network diff --git a/src/xrpld/rpc/README.md b/src/xrpld/rpc/README.md index cece30a3b20..5bb9655a762 100644 --- a/src/xrpld/rpc/README.md +++ b/src/xrpld/rpc/README.md @@ -2,15 +2,16 @@ ## Introduction. -By default, an RPC handler runs as an uninterrupted task on the JobQueue. This +By default, an RPC handler runs as an uninterrupted task on the JobQueue. This is fine for commands that are fast to compute but might not be acceptable for tasks that require multiple parts or are large, like a full ledger. -For this purpose, the rippled RPC handler allows *suspension with continuation* +For this purpose, the rippled RPC handler allows _suspension with continuation_ + - a request to suspend execution of the RPC response and to continue it after -some function or job has been executed. A default continuation is supplied -which simply reschedules the job on the JobQueue, or the programmer can supply -their own. + some function or job has been executed. A default continuation is supplied + which simply reschedules the job on the JobQueue, or the programmer can supply + their own. ## The classes. @@ -28,16 +29,16 @@ would prevent any other task from making forward progress when you call a `Callback`. A `Continuation` is a function that is given a `Callback` and promises to call -it later. A `Continuation` guarantees to call the `Callback` exactly once at +it later. A `Continuation` guarantees to call the `Callback` exactly once at some point in the future, but it does not have to be immediately or even in the current thread. -A `Suspend` is a function belonging to a `Coroutine`. A `Suspend` runs a +A `Suspend` is a function belonging to a `Coroutine`. A `Suspend` runs a `Continuation`, passing it a `Callback` that continues execution of the `Coroutine`. And finally, a `Coroutine` is a `std::function` which is given a -`Suspend`. This is what the RPC handler gives to the coroutine manager, +`Suspend`. This is what the RPC handler gives to the coroutine manager, expecting to get called back with a `Suspend` and to be able to start execution. ## The flow of control. diff --git a/src/xrpld/rpc/handlers/AccountInfo.cpp b/src/xrpld/rpc/handlers/AccountInfo.cpp index 6416309e2e9..3432021690a 100644 --- a/src/xrpld/rpc/handlers/AccountInfo.cpp +++ b/src/xrpld/rpc/handlers/AccountInfo.cpp @@ -108,6 +108,10 @@ doAccountInfo(RPC::JsonContext& context) allowTrustLineClawbackFlag{ "allowTrustLineClawback", lsfAllowTrustLineClawback}; + static constexpr std::pair + allowTrustLineLockingFlag{ + "allowTrustLineLocking", lsfAllowTrustLineLocking}; + auto const sleAccepted = ledger->read(keylet::account(accountID)); if (sleAccepted) { @@ -140,6 +144,10 @@ doAccountInfo(RPC::JsonContext& context) acctFlags[allowTrustLineClawbackFlag.first.data()] = sleAccepted->isFlag(allowTrustLineClawbackFlag.second); + if (ledger->rules().enabled(featureTokenEscrow)) + acctFlags[allowTrustLineLockingFlag.first.data()] = + sleAccepted->isFlag(allowTrustLineLockingFlag.second); + result[jss::account_flags] = std::move(acctFlags); // The document[https://xrpl.org/account_info.html#account_info] states diff --git a/src/xrpld/rpc/handlers/AccountTx.cpp b/src/xrpld/rpc/handlers/AccountTx.cpp index 26c8065edf5..d5df40303ba 100644 --- a/src/xrpld/rpc/handlers/AccountTx.cpp +++ b/src/xrpld/rpc/handlers/AccountTx.cpp @@ -348,7 +348,7 @@ populateJsonResponse( txnMeta->getJson(JsonOptions::include_date); insertDeliveredAmount( jvObj[jss::meta], context, txn, *txnMeta); - insertNFTSyntheticInJson(jvObj, sttx, *txnMeta); + RPC::insertNFTSyntheticInJson(jvObj, sttx, *txnMeta); RPC::insertMPTokenIssuanceID( jvObj[jss::meta], sttx, *txnMeta); } diff --git a/src/xrpld/rpc/handlers/LedgerHandler.cpp b/src/xrpld/rpc/handlers/LedgerHandler.cpp index 4015bb9fcc3..8987f2d07eb 100644 --- a/src/xrpld/rpc/handlers/LedgerHandler.cpp +++ b/src/xrpld/rpc/handlers/LedgerHandler.cpp @@ -54,10 +54,6 @@ LedgerHandler::check() bool const binary = params[jss::binary].asBool(); bool const owner_funds = params[jss::owner_funds].asBool(); bool const queue = params[jss::queue].asBool(); - auto type = chooseLedgerEntryType(params); - if (type.first) - return type.first; - type_ = type.second; options_ = (full ? LedgerFill::full : 0) | (expand ? LedgerFill::expand : 0) | diff --git a/src/xrpld/rpc/handlers/LedgerHandler.h b/src/xrpld/rpc/handlers/LedgerHandler.h index 0e47164ad3d..a573589cbca 100644 --- a/src/xrpld/rpc/handlers/LedgerHandler.h +++ b/src/xrpld/rpc/handlers/LedgerHandler.h @@ -76,7 +76,6 @@ class LedgerHandler std::vector queueTxs_; Json::Value result_; int options_ = 0; - LedgerEntryType type_; }; //////////////////////////////////////////////////////////////////////////////// @@ -91,7 +90,7 @@ LedgerHandler::writeResult(Object& value) if (ledger_) { Json::copyFrom(value, result_); - addJson(value, {*ledger_, &context_, options_, queueTxs_, type_}); + addJson(value, {*ledger_, &context_, options_, queueTxs_}); } else { @@ -105,6 +104,21 @@ LedgerHandler::writeResult(Object& value) addJson(open, {*master.getCurrentLedger(), &context_, 0}); } } + + Json::Value warnings{Json::arrayValue}; + if (context_.params.isMember(jss::type)) + { + Json::Value& w = warnings.append(Json::objectValue); + w[jss::id] = warnRPC_FIELDS_DEPRECATED; + w[jss::message] = + "Some fields from your request are deprecated. Please check the " + "documentation at " + "https://xrpl.org/docs/references/http-websocket-apis/ " + "and update your request. Field `type` is deprecated."; + } + + if (warnings.size()) + value[jss::warnings] = std::move(warnings); } } // namespace RPC diff --git a/src/xrpld/rpc/handlers/LogLevel.cpp b/src/xrpld/rpc/handlers/LogLevel.cpp index 0fc266569e8..a93d010706e 100644 --- a/src/xrpld/rpc/handlers/LogLevel.cpp +++ b/src/xrpld/rpc/handlers/LogLevel.cpp @@ -44,7 +44,6 @@ doLogLevel(RPC::JsonContext& context) Logs::toString(Logs::fromSeverity(context.app.logs().threshold())); std::vector> logTable( context.app.logs().partition_severities()); - using stringPair = std::map::value_type; for (auto const& [k, v] : logTable) lev[k] = v; diff --git a/src/xrpld/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp index 3db71d9002d..d43a699ab31 100644 --- a/src/xrpld/rpc/handlers/Tx.cpp +++ b/src/xrpld/rpc/handlers/Tx.cpp @@ -270,7 +270,7 @@ populateJsonResponse( response[jss::meta] = meta->getJson(JsonOptions::none); insertDeliveredAmount( response[jss::meta], context, result.txn, *meta); - insertNFTSyntheticInJson(response, sttx, *meta); + RPC::insertNFTSyntheticInJson(response, sttx, *meta); RPC::insertMPTokenIssuanceID(response[jss::meta], sttx, *meta); } } diff --git a/src/xrpld/shamap/README.md b/src/xrpld/shamap/README.md index ef2d22024bd..3bff74e67bd 100644 --- a/src/xrpld/shamap/README.md +++ b/src/xrpld/shamap/README.md @@ -1,4 +1,4 @@ -# SHAMap Introduction # +# SHAMap Introduction March 2020 @@ -30,20 +30,20 @@ The root node is always a SHAMapInnerNode. A given `SHAMap` always stores only one of three kinds of data: - * Transactions with metadata - * Transactions without metadata, or - * Account states. +- Transactions with metadata +- Transactions without metadata, or +- Account states. So all of the leaf nodes of a particular `SHAMap` will always have a uniform type. The inner nodes carry no data other than the hash of the nodes beneath them. All nodes are owned by shared_ptrs resident in either other nodes, or in case of -the root node, a shared_ptr in the `SHAMap` itself. The use of shared_ptrs -permits more than one `SHAMap` at a time to share ownership of a node. This +the root node, a shared_ptr in the `SHAMap` itself. The use of shared_ptrs +permits more than one `SHAMap` at a time to share ownership of a node. This occurs (for example), when a copy of a `SHAMap` is made. Copies are made with the `snapShot` function as opposed to the `SHAMap` copy -constructor. See the section on `SHAMap` creation for more details about +constructor. See the section on `SHAMap` creation for more details about `snapShot`. Sequence numbers are used to further customize the node ownership strategy. See @@ -51,62 +51,62 @@ the section on sequence numbers for details on sequence numbers. ![node diagram](https://user-images.githubusercontent.com/46455409/77350005-1ef12c80-6cf9-11ea-9c8d-56410f442859.png) -## Mutability ## +## Mutability There are two different ways of building and using a `SHAMap`: - 1. A mutable `SHAMap` and - 2. An immutable `SHAMap` +1. A mutable `SHAMap` and +2. An immutable `SHAMap` The distinction here is not of the classic C++ immutable-means-unchanging sense. - An immutable `SHAMap` contains *nodes* that are immutable. Also, once a node has +An immutable `SHAMap` contains _nodes_ that are immutable. Also, once a node has been located in an immutable `SHAMap`, that node is guaranteed to persist in that `SHAMap` for the lifetime of the `SHAMap`. So, somewhat counter-intuitively, an immutable `SHAMap` may grow as new nodes are -introduced. But an immutable `SHAMap` will never get smaller (until it entirely -evaporates when it is destroyed). Nodes, once introduced to the immutable -`SHAMap`, also never change their location in memory. So nodes in an immutable +introduced. But an immutable `SHAMap` will never get smaller (until it entirely +evaporates when it is destroyed). Nodes, once introduced to the immutable +`SHAMap`, also never change their location in memory. So nodes in an immutable `SHAMap` can be handled using raw pointers (if you're careful). One consequence of this design is that an immutable `SHAMap` can never be -"trimmed". There is no way to identify unnecessary nodes in an immutable `SHAMap` -that could be removed. Once a node has been brought into the in-memory `SHAMap`, +"trimmed". There is no way to identify unnecessary nodes in an immutable `SHAMap` +that could be removed. Once a node has been brought into the in-memory `SHAMap`, that node stays in memory for the life of the `SHAMap`. Most `SHAMap`s are immutable, in the sense that they don't modify or remove their contained nodes. An example where a mutable `SHAMap` is required is when we want to apply -transactions to the last closed ledger. To do so we'd make a mutable snapshot +transactions to the last closed ledger. To do so we'd make a mutable snapshot of the state trie and then start applying transactions to it. Because the snapshot is mutable, changes to nodes in the snapshot will not affect nodes in other `SHAMap`s. An example using a immutable ledger would be when there's an open ledger and -some piece of code wishes to query the state of the ledger. In this case we +some piece of code wishes to query the state of the ledger. In this case we don't wish to change the state of the `SHAMap`, so we'd use an immutable snapshot. -## Sequence numbers ## +## Sequence numbers -Both `SHAMap`s and their nodes carry a sequence number. This is simply an +Both `SHAMap`s and their nodes carry a sequence number. This is simply an unsigned number that indicates ownership or membership, or a non-membership. -`SHAMap`s sequence numbers normally start out as 1. However when a snap-shot of +`SHAMap`s sequence numbers normally start out as 1. However when a snap-shot of a `SHAMap` is made, the copy's sequence number is 1 greater than the original. -The nodes of a `SHAMap` have their own copy of a sequence number. If the `SHAMap` +The nodes of a `SHAMap` have their own copy of a sequence number. If the `SHAMap` is mutable, meaning it can change, then all of its nodes must have the -same sequence number as the `SHAMap` itself. This enforces an invariant that none +same sequence number as the `SHAMap` itself. This enforces an invariant that none of the nodes are shared with other `SHAMap`s. When a `SHAMap` needs to have a private copy of a node, not shared by any other `SHAMap`, it first clones it and then sets the new copy to have a sequence number -equal to the `SHAMap` sequence number. The `unshareNode` is a private utility +equal to the `SHAMap` sequence number. The `unshareNode` is a private utility which automates the task of first checking if the node is already sharable, and -if so, cloning it and giving it the proper sequence number. An example case +if so, cloning it and giving it the proper sequence number. An example case where a private copy is needed is when an inner node needs to have a child -pointer altered. Any modification to a node will require a non-shared node. +pointer altered. Any modification to a node will require a non-shared node. When a `SHAMap` decides that it is safe to share a node of its own, it sets the node's sequence number to 0 (a `SHAMap` never has a sequence number of 0). This @@ -116,40 +116,40 @@ Note that other objects in rippled also have sequence numbers (e.g. ledgers). The `SHAMap` and node sequence numbers should not be confused with these other sequence numbers (no relation). -## SHAMap Creation ## +## SHAMap Creation -A `SHAMap` is usually not created from vacuum. Once an initial `SHAMap` is +A `SHAMap` is usually not created from vacuum. Once an initial `SHAMap` is constructed, later `SHAMap`s are usually created by calling snapShot(bool -isMutable) on the original `SHAMap`. The returned `SHAMap` has the expected +isMutable) on the original `SHAMap`. The returned `SHAMap` has the expected characteristics (mutable or immutable) based on the passed in flag. It is cheaper to make an immutable snapshot of a `SHAMap` than to make a mutable -snapshot. If the `SHAMap` snapshot is mutable then sharable nodes must be +snapshot. If the `SHAMap` snapshot is mutable then sharable nodes must be copied before they are placed in the mutable map. -A new `SHAMap` is created with each new ledger round. Transactions not executed +A new `SHAMap` is created with each new ledger round. Transactions not executed in the previous ledger populate the `SHAMap` for the new ledger. -## Storing SHAMap data in the database ## +## Storing SHAMap data in the database -When consensus is reached, the ledger is closed. As part of this process, the +When consensus is reached, the ledger is closed. As part of this process, the `SHAMap` is stored to the database by calling `SHAMap::flushDirty`. Both `unshare()` and `flushDirty` walk the `SHAMap` by calling -`SHAMap::walkSubTree`. As `unshare()` walks the trie, nodes are not written to +`SHAMap::walkSubTree`. As `unshare()` walks the trie, nodes are not written to the database, and as `flushDirty` walks the trie nodes are written to the database. `walkSubTree` visits every node in the trie. This process must ensure that each node is only owned by this trie, and so "unshares" as it walks each -node (from the root down). This is done in the `preFlushNode` function by -ensuring that the node has a sequence number equal to that of the `SHAMap`. If +node (from the root down). This is done in the `preFlushNode` function by +ensuring that the node has a sequence number equal to that of the `SHAMap`. If the node doesn't, it is cloned. For each inner node encountered (starting with the root node), each of the -children are inspected (from 1 to 16). For each child, if it has a non-zero -sequence number (unshareable), the child is first copied. Then if the child is -an inner node, we recurse down to that node's children. Otherwise we've found a -leaf node and that node is written to the database. A count of each leaf node -that is visited is kept. The hash of the data in the leaf node is computed at +children are inspected (from 1 to 16). For each child, if it has a non-zero +sequence number (unshareable), the child is first copied. Then if the child is +an inner node, we recurse down to that node's children. Otherwise we've found a +leaf node and that node is written to the database. A count of each leaf node +that is visited is kept. The hash of the data in the leaf node is computed at this time, and the child is reassigned back into the parent inner node just in case the COW operation created a new pointer to this leaf node. @@ -157,22 +157,22 @@ After processing each node, the node is then marked as sharable again by setting its sequence number to 0. After all of an inner node's children are processed, then its hash is updated -and the inner node is written to the database. Then this inner node is assigned +and the inner node is written to the database. Then this inner node is assigned back into it's parent node, again in case the COW operation created a new pointer to it. -## Walking a SHAMap ## +## Walking a SHAMap -The private function `SHAMap::walkTowardsKey` is a good example of *how* to walk +The private function `SHAMap::walkTowardsKey` is a good example of _how_ to walk a `SHAMap`, and the various functions that call `walkTowardsKey` are good examples -of *why* one would want to walk a `SHAMap` (e.g. `SHAMap::findKey`). +of _why_ one would want to walk a `SHAMap` (e.g. `SHAMap::findKey`). `walkTowardsKey` always starts at the root of the `SHAMap` and traverses down through the inner nodes, looking for a leaf node along a path in the trie designated by a `uint256`. -As one walks the trie, one can *optionally* keep a stack of nodes that one has -passed through. This isn't necessary for walking the trie, but many clients -will use the stack after finding the desired node. For example if one is +As one walks the trie, one can _optionally_ keep a stack of nodes that one has +passed through. This isn't necessary for walking the trie, but many clients +will use the stack after finding the desired node. For example if one is deleting a node from the trie, the stack is handy for repairing invariants in the trie after the deletion. @@ -189,10 +189,10 @@ how we use a `SHAMapNodeID` to select a "branch" (child) by indexing into a path at a given depth. While the current node is an inner node, traversing down the trie from the root -continues, unless the path indicates a child that does not exist. And in this +continues, unless the path indicates a child that does not exist. And in this case, `nullptr` is returned to indicate no leaf node along the given path -exists. Otherwise a leaf node is found and a (non-owning) pointer to it is -returned. At each step, if a stack is requested, a +exists. Otherwise a leaf node is found and a (non-owning) pointer to it is +returned. At each step, if a stack is requested, a `pair, SHAMapNodeID>` is pushed onto the stack. When a child node is found by `selectBranch`, the traversal to that node @@ -210,35 +210,35 @@ The first step consists of several attempts to find the node in various places: If the node is not found in the trie, then it is installed into the trie as part of the traversal process. -## Late-arriving Nodes ## +## Late-arriving Nodes -As we noted earlier, `SHAMap`s (even immutable ones) may grow. If a `SHAMap` is +As we noted earlier, `SHAMap`s (even immutable ones) may grow. If a `SHAMap` is searching for a node and runs into an empty spot in the trie, then the `SHAMap` -looks to see if the node exists but has not yet been made part of the map. This -operation is performed in the `SHAMap::fetchNodeNT()` method. The *NT* +looks to see if the node exists but has not yet been made part of the map. This +operation is performed in the `SHAMap::fetchNodeNT()` method. The _NT_ is this case stands for 'No Throw'. The `fetchNodeNT()` method goes through three phases: - 1. By calling `cacheLookup()` we attempt to locate the missing node in the - TreeNodeCache. The TreeNodeCache is a cache of immutable SHAMapTreeNodes +1. By calling `cacheLookup()` we attempt to locate the missing node in the + TreeNodeCache. The TreeNodeCache is a cache of immutable SHAMapTreeNodes that are shared across all `SHAMap`s. Any SHAMapLeafNode that is immutable has a sequence number of zero (sharable). When a mutable `SHAMap` is created then its SHAMapTreeNodes are - given non-zero sequence numbers (unsharable). But all nodes in the + given non-zero sequence numbers (unsharable). But all nodes in the TreeNodeCache are immutable, so if one is found here, its sequence number will be 0. - 2. If the node is not in the TreeNodeCache, we attempt to locate the node - in the historic data stored by the data base. The call to to +2. If the node is not in the TreeNodeCache, we attempt to locate the node + in the historic data stored by the data base. The call to to `fetchNodeFromDB(hash)` does that work for us. - 3. Finally if a filter exists, we check if it can supply the node. This is +3. Finally if a filter exists, we check if it can supply the node. This is typically the LedgerMaster which tracks the current ledger and ledgers in the process of closing. -## Canonicalize ## +## Canonicalize `canonicalize()` is called every time a node is introduced into the `SHAMap`. @@ -251,51 +251,50 @@ by favoring the copy already in the `TreeNodeCache`. By using `canonicalize()` we manage a thread race condition where two different threads might both recognize the lack of a SHAMapLeafNode at the same time -(during a fetch). If they both attempt to insert the node into the `SHAMap`, then +(during a fetch). If they both attempt to insert the node into the `SHAMap`, then `canonicalize` makes sure that the first node in wins and the slower thread -receives back a pointer to the node inserted by the faster thread. Recall +receives back a pointer to the node inserted by the faster thread. Recall that these two `SHAMap`s will share the same `TreeNodeCache`. -## `TreeNodeCache` ## +## `TreeNodeCache` The `TreeNodeCache` is a `std::unordered_map` keyed on the hash of the -`SHAMap` node. The stored type consists of `shared_ptr`, +`SHAMap` node. The stored type consists of `shared_ptr`, `weak_ptr`, and a time point indicating the most recent -access of this node in the cache. The time point is based on +access of this node in the cache. The time point is based on `std::chrono::steady_clock`. The container uses a cryptographically secure hash that is randomly seeded. The `TreeNodeCache` also carries with it various data used for statistics -and logging, and a target age for the contained nodes. When the target age +and logging, and a target age for the contained nodes. When the target age for a node is exceeded, and there are no more references to the node, the node is removed from the `TreeNodeCache`. -## `FullBelowCache` ## +## `FullBelowCache` This cache remembers which trie keys have all of their children resident in a -`SHAMap`. This optimizes the process of acquiring a complete trie. This is used -when creating the missing nodes list. Missing nodes are those nodes that a +`SHAMap`. This optimizes the process of acquiring a complete trie. This is used +when creating the missing nodes list. Missing nodes are those nodes that a `SHAMap` refers to but that are not stored in the local database. As a depth-first walk of a `SHAMap` is performed, if an inner node answers true to `isFullBelow()` then it is known that none of this node's children are missing -nodes, and thus that subtree does not need to be walked. These nodes are stored -in the FullBelowCache. Subsequent walks check the FullBelowCache first when +nodes, and thus that subtree does not need to be walked. These nodes are stored +in the FullBelowCache. Subsequent walks check the FullBelowCache first when encountering a node, and ignore that subtree if found. -## `SHAMapTreeNode` ## +## `SHAMapTreeNode` -This is an abstract base class for the concrete node types. It holds the +This is an abstract base class for the concrete node types. It holds the following common data: 1. A hash 2. An identifier used to perform copy-on-write operations +### `SHAMapInnerNode` -### `SHAMapInnerNode` ### - -`SHAMapInnerNode` publicly inherits directly from `SHAMapTreeNode`. It holds +`SHAMapInnerNode` publicly inherits directly from `SHAMapTreeNode`. It holds the following data: 1. Up to 16 child nodes, each held with a shared_ptr. @@ -304,36 +303,34 @@ the following data: 4. An identifier used to determine whether the map below this node is fully populated -### `SHAMapLeafNode` ### +### `SHAMapLeafNode` `SHAMapLeafNode` is an abstract class which publicly inherits directly from -`SHAMapTreeNode`. It isIt holds the +`SHAMapTreeNode`. It isIt holds the following data: 1. A shared_ptr to a const SHAMapItem. -#### `SHAMapAccountStateLeafNode` #### +#### `SHAMapAccountStateLeafNode` `SHAMapAccountStateLeafNode` is a class which publicly inherits directly from `SHAMapLeafNode`. It is used to represent entries (i.e. account objects, escrow objects, trust lines, etc.) in a state map. -#### `SHAMapTxLeafNode` #### +#### `SHAMapTxLeafNode` `SHAMapTxLeafNode` is a class which publicly inherits directly from `SHAMapLeafNode`. It is used to represent transactions in a state map. -#### `SHAMapTxPlusMetaLeafNode` #### +#### `SHAMapTxPlusMetaLeafNode` `SHAMapTxPlusMetaLeafNode` is a class which publicly inherits directly from `SHAMapLeafNode`. It is used to represent transactions along with metadata associated with this transaction in a state map. -## SHAMapItem ## +## SHAMapItem This holds the following data: -1. uint256. The hash of the data. -2. vector. The data (transactions, account info). - - +1. uint256. The hash of the data. +2. vector. The data (transactions, account info). diff --git a/src/xrpld/shamap/SHAMap.h b/src/xrpld/shamap/SHAMap.h index 33c42c2d230..738cf96ecc5 100644 --- a/src/xrpld/shamap/SHAMap.h +++ b/src/xrpld/shamap/SHAMap.h @@ -36,6 +36,7 @@ #include #include +#include #include #include diff --git a/tests/README.md b/tests/README.md index 0306915b3be..c4a96005e77 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,4 +1,5 @@ # Integration tests + This directory contains integration tests for the project. These tests are run against the `libxrpl` library or `rippled` binary to verify they are working as expected. diff --git a/tests/conan/CMakeLists.txt b/tests/conan/CMakeLists.txt index 83aa24880d1..f1b37e7a694 100644 --- a/tests/conan/CMakeLists.txt +++ b/tests/conan/CMakeLists.txt @@ -9,7 +9,7 @@ project( LANGUAGES CXX ) -find_package(xrpl REQUIRED) +find_package(xrpl CONFIG REQUIRED) add_executable(example) target_sources(example PRIVATE src/example.cpp) diff --git a/tests/conan/conanfile.py b/tests/conan/conanfile.py index be3750bf9e9..1ea1b333fce 100644 --- a/tests/conan/conanfile.py +++ b/tests/conan/conanfile.py @@ -1,59 +1,42 @@ -from conan import ConanFile, conan_version +from pathlib import Path + +from conan import ConanFile +from conan.tools.build import can_run 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' - + name = 'example' license = 'ISC' - author = 'John Freeman ' + author = 'John Freeman , Michael Legleux