diff --git a/.github/workflows/guix-build.yml b/.github/workflows/guix-build.yml index dbdaddcb37e8b..e6435e7efc730 100644 --- a/.github/workflows/guix-build.yml +++ b/.github/workflows/guix-build.yml @@ -1,15 +1,20 @@ name: Guix Build +permissions: + packages: write + id-token: write + attestations: write + on: - pull_request: - types: [ labeled ] - workflow_dispatch: + pull_request_target: + push: jobs: - build: - runs-on: [ "self-hosted", "linux", "x64", "ubuntu-core" ] - if: contains(github.event.pull_request.labels.*.name, 'guix-build') - timeout-minutes: 480 + build-image: + runs-on: ubuntu-latest + outputs: + image-tag: ${{ steps.prepare.outputs.image-tag }} + repo-name: ${{ steps.prepare.outputs.repo-name }} steps: - name: Checkout uses: actions/checkout@v4 @@ -22,37 +27,72 @@ jobs: uses: docker/setup-buildx-action@v3 - name: Commit variables - id: dockerfile + id: prepare run: | echo "hash=$(sha256sum ./dash/contrib/containers/guix/Dockerfile | cut -d ' ' -f1)" >> $GITHUB_OUTPUT echo "host_user_id=$(id -u)" >> $GITHUB_OUTPUT echo "host_group_id=$(id -g)" >> $GITHUB_OUTPUT + BRANCH_NAME=$(echo "${GITHUB_REF##*/}" | tr '[:upper:]' '[:lower:]') + REPO_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') + echo "::set-output name=image-tag::${BRANCH_NAME}" + echo "::set-output name=repo-name::${REPO_NAME}" + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: ${{ github.workspace }}/dash build-args: | - USER_ID=${{ steps.dockerfile.outputs.host_user_id }} - GROUP_ID=${{ steps.dockerfile.outputs.host_group_id }} + USER_ID=${{ steps.prepare.outputs.host_user_id }} + GROUP_ID=${{ steps.prepare.outputs.host_group_id }} build-contexts: | docker_root=${{ github.workspace }}/dash/contrib/containers/guix file: ./dash/contrib/containers/guix/Dockerfile - load: true - tags: guix_ubuntu:latest - cache-from: type=gha - cache-to: type=gha,mode=max + push: true + tags: | + ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder:${{ steps.prepare.outputs.image-tag }} + ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder:latest + cache-from: type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder:latest + cache-to: type=inline,mode=max + + build: + needs: build-image + # runs-on: [ "self-hosted", "linux", "x64", "ubuntu-core" ] + runs-on: ubuntu-latest +# if: ${{ contains(github.event.pull_request.labels.*.name, 'guix-build') }} + strategy: + matrix: + build_target: [x86_64-linux-gnu, arm-linux-gnueabihf, aarch64-linux-gnu, riscv64-linux-gnu, x86_64-w64-mingw32, x86_64-apple-darwin, arm64-apple-darwin] + + timeout-minutes: 480 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + path: dash + fetch-depth: 0 - - name: Restore Guix cache and depends + - name: Cache Guix and depends id: guix-cache-restore - uses: actions/cache/restore@v3 + uses: actions/cache@v3 with: path: | ${{ github.workspace }}/.cache ${{ github.workspace }}/dash/depends/built ${{ github.workspace }}/dash/depends/sources ${{ github.workspace }}/dash/depends/work - key: ${{ runner.os }}-guix + /gnu/store + key: ${{ runner.os }}-guix-${{ matrix.build_target }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-guix-${{ matrix.build_target }} + ${{ runner.os }}-guix- - name: Create .cache folder if missing if: steps.guix-cache-restore.outputs.cache-hit != 'true' @@ -67,8 +107,8 @@ jobs: -v ${{ github.workspace }}/dash:/src/dash \ -v ${{ github.workspace }}/.cache:/home/ubuntu/.cache \ -w /src/dash \ - guix_ubuntu:latest && \ - docker exec guix-daemon bash -c '/usr/local/bin/guix-start' + ghcr.io/${{ needs.build-image.outputs.repo-name }}/dashcore-guix-builder:${{ needs.build-image.outputs.image-tag }} && \ + docker exec guix-daemon bash -c 'HOSTS=${{ matrix.build_target }} /usr/local/bin/guix-start' - name: Ensure build passes run: | @@ -77,17 +117,19 @@ jobs: exit 1 fi - - name: Save Guix cache and depends - id: guix-cache-save - uses: actions/cache/save@v3 + - name: Compute SHA256 checksums + continue-on-error: true # It will complain on depending on only some hosts + run: | + HOSTS=${{ matrix.build_target }} ./dash/contrib/containers/guix/scripts/guix-check ${{ github.workspace }}/dash + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 with: + name: guix-artifacts-${{ matrix.build_target }} path: | - ${{ github.workspace }}/.cache - ${{ github.workspace }}/dash/depends/built - ${{ github.workspace }}/dash/depends/sources - ${{ github.workspace }}/dash/depends/work - key: ${{ steps.guix-cache-restore.outputs.cache-primary-key }} + ${{ github.workspace }}/dash/guix-build*/output/${{ matrix.build_target }}/ - - name: Compute SHA256 checksums - run: | - ./dash/contrib/containers/guix/scripts/guix-check ${{ github.workspace }}/dash + - name: Attest build provenance + uses: actions/attest-build-provenance@v1 + with: + subject-path: ${{ github.workspace }}/dash/guix-build*/output/${{ matrix.build_target }}/* diff --git a/configure.ac b/configure.ac index 52fe2db6d83fa..ab071c9f569c0 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.69]) dnl Don't forget to push a corresponding tag when updating any of _CLIENT_VERSION_* numbers define(_CLIENT_VERSION_MAJOR, 21) define(_CLIENT_VERSION_MINOR, 1) -define(_CLIENT_VERSION_BUILD, 0) +define(_CLIENT_VERSION_BUILD, 1) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers]) diff --git a/contrib/builder-keys/kittywhiskers.pgp b/contrib/builder-keys/kittywhiskers.pgp new file mode 100644 index 0000000000000..03feedde469eb --- /dev/null +++ b/contrib/builder-keys/kittywhiskers.pgp @@ -0,0 +1,32 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEZZs7ABYJKwYBBAHaRw8BAQdAxvpS5zLLn9agjKg1bpMyHtKROTC8SLTl3AZm +b4DKXJq0P0tpdHR5d2hpc2tlcnMgVmFuIEdvZ2ggPDYzMTg5NTMxK2t3dmdAdXNl +cnMubm9yZXBseS5naXRodWIuY29tPoiaBBMWCABCAhsDBQkDw7iAAheAAhkBFiEE +lpGHqOdP5AqKSAZ0MM0MBl5cSq0FAmbpq2gFCwkIBwIGFQoJCAsCBRYCAwEAAh4F +AAoJEDDNDAZeXEqt6D4BALOgavknWXzg3zyBI4rzqS2Qq1qrDl0AVohpYQYJrUZ6 +AP92LejS8DyeR4NZuUeP4gCxL/0wOydz6LkmEefaTvNiD7RIS2l0dHl3aGlza2Vy +cyBWYW4gR29naCA8NjMxODk1MzEra2l0dHl3aGlza2Vyc0B1c2Vycy5ub3JlcGx5 +LmdpdGh1Yi5jb20+iJcEExYIAD8CGwMFCQPDuIACF4AWIQSWkYeo50/kCopIBnQw +zQwGXlxKrQUCZumraQULCQgHAgYVCgkICwIFFgIDAQACHgUACgkQMM0MBl5cSq3B +zAD/T6dYqUtzIuZjIIBXisBMISNTHQxRv1KH3txuN+lCW/UBAIMV6Y41aIqbGnI2 +ADm+WYFsnABokj+mT5GZBuqfEYQEtEdLaXR0eXdoaXNrZXJzIFZhbiBHb2doIDw2 +MDk4OTc0LWtpdHR5d2hpc2tlcnNAdXNlcnMubm9yZXBseS5naXRsYWIuY29tPoiX +BBMWCAA/AhsDBQkDw7iAAheAFiEElpGHqOdP5AqKSAZ0MM0MBl5cSq0FAmbpq2kF +CwkIBwIGFQoJCAsCBRYCAwEAAh4FAAoJEDDNDAZeXEqt2D0BAIZOVRQgvP6DZeXc +ONNZcFGp3mrbumudjsoCCiDTS/PZAP48LFSFBB8NBcXgjj1edktii9AN3JYyW+yF +60uLMN4NAbQvS2l0dHl3aGlza2VycyBWYW4gR29naCA8a2l0dHl3aGlza2Vyc0Bk +YXNoLm9yZz6IlwQTFgoAPwIbAwUJA8O4gAIXgBYhBJaRh6jnT+QKikgGdDDNDAZe +XEqtBQJm6atpBQsJCAcCBhUKCQgLAgUWAgMBAAIeBQAKCRAwzQwGXlxKrSHfAQCU +Tu3DPWNWj8weotN4NKoShfsMrIEEeKqv1ykLc1K2lwD8CwEBUG69Pl8NFWMElvam +6wu9OWtOKp9xBkFS+CjM8A60NktpdHR5d2hpc2tlcnMgVmFuIEdvZ2ggPGt3dmdA +dXNlcnMubm9yZXBseS5naXRodWIuY29tPoiXBBMWCgA/AhsDBQkDw7iAAheAFiEE +lpGHqOdP5AqKSAZ0MM0MBl5cSq0FAmbpq2kFCwkIBwIGFQoJCAsCBRYCAwEAAh4F +AAoJEDDNDAZeXEqt4YAA/22FrVJGDOeZVYRNLjFL34+YjXEyTO5dACjZ8jV2/uHD +AQDB9osQDYr/lDfuMMSPZhufAryHIWBJp/e8AwHwJ65aALg4BGWbOwASCisGAQQB +l1UBBQEBB0DCbqznf45arlTBDkpS76ineVKFabpOa3vohGKIKJ+5FAMBCAeIfgQY +FggAJhYhBJaRh6jnT+QKikgGdDDNDAZeXEqtBQJlmzsAAhsMBQkDw7iAAAoJEDDN +DAZeXEqtUvEBALBrYJ7jRRCwBMBTG2doiFupibGQh2vN46gKSrXzYSG9AQDIXcCJ +moGvMWiiBz71Wr9JZ7/ZV6rcRE1YXfM06G6gCQ== +=gtD4 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/builder-keys/pasta.pgp b/contrib/builder-keys/pasta.pgp index 018162fd70a30..934ee1804afaf 100644 --- a/contrib/builder-keys/pasta.pgp +++ b/contrib/builder-keys/pasta.pgp @@ -24,53 +24,143 @@ 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 -u+HE6D2rqvc0CA1wAreY5+lD96PbmOAjnA== -=lPi0 +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 +t8FIucvlOdt4EqKaSmoBQZk0Aj/N5q4= +=vjZr -----END PGP PUBLIC KEY BLOCK----- diff --git a/doc/release-notes.md b/doc/release-notes.md index 7b0ef32142d27..06f26776e08a4 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,9 +1,8 @@ -# Dash Core version v21.1.0 +# Dash Core version v21.1.1 -This is a new minor version release, bringing important bugfixes. +This is a new patch version release, bringing important bugfixes. -This release is **mandatory** for all masternodes. -This release is optional but recommended for all other nodes. +This release is **optional** but recommended for all nodes. Please report bugs using the issue tracker at GitHub: @@ -34,18 +33,13 @@ reindex or re-sync the whole chain. # Notable changes -Allow EHF Resigning -------------------- - -During implementation, the values for requestID and msgHash for EHF signing were switched. As a result, a masternode -which participated in an earlier failed attempt to form an EHF message is unable to participate in subsequent -attempts. This is because the LLMQ Signing System requires that the requestID be unique, and that a node will not -sign two different msgHash for the same requestID. See the [forum post](https://www.dash.org/forum/index.php?threads/ehf-activation-issues.55146/) -explaining it further. - -As there is no need to restrict double signing for EHF, we now allow signing of multiple msgHash's for a single EHF -requestID. Once a sufficient number of masternodes upgrade to v21.1, the EHF message will be automatically signed and -mined. +- Core now categorizes asset unlock transactions as "Platform Transfers" on the Transactions tab in Dash-Qt and in the output of the `gettransaction` RPC (#6131) +- Persist Coinjoin Denoms options changes made via GUI over restarts (#6208) +- Fix incorrect payment predictions for evonodes in Dash-Qt and in RPC `masternode winners` (#6222) +- `creditOutputs` entries in various RPCs that output transaction JSON are shown as objects now instead of being shown as strings (#6229) +- Updated PGP key for builder 'pasta' to reflect new subkeys. You may need to reimport this key to validate signatures. (#6290) +- Build failures on Ubuntu 24.10 / clang 19.1.1 resolved (#6328) +- RPC errors in `masternode payments`, `getblock`, `getblockstats` related to Asset Unlock parsing have been fixed (#6336) # v21.1.0 Change log @@ -55,10 +49,10 @@ See detailed [set of changes][set-of-changes]. Thanks to everyone who directly contributed to this release: +- Kittywhiskers Van Gogh - Konstantin Akimov - PastaPastaPasta - UdjinM6 -- ogabrielides As well as everyone that submitted issues, reviewed pull requests and helped debug the release candidates. @@ -67,6 +61,7 @@ debug the release candidates. These release are considered obsolete. Old release notes can be found here: +- [v21.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-21.1.0.md) released Aug/8/2024 - [v21.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-21.0.2.md) released Aug/1/2024 - [v21.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-21.0.0.md) released Jul/25/2024 - [v20.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-20.1.1.md) released April/3/2024 @@ -118,4 +113,4 @@ These release are considered obsolete. Old release notes can be found here: - [v0.10.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.10.0.md) released Sep/25/2014 - [v0.9.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.9.0.md) released Mar/13/2014 -[set-of-changes]: https://github.com/dashpay/dash/compare/v21.0.2...dashpay:v21.1.0 +[set-of-changes]: https://github.com/dashpay/dash/compare/v21.1.0...dashpay:v21.1.1 diff --git a/doc/release-notes/dash/release-notes-21.1.0.md b/doc/release-notes/dash/release-notes-21.1.0.md new file mode 100644 index 0000000000000..7b0ef32142d27 --- /dev/null +++ b/doc/release-notes/dash/release-notes-21.1.0.md @@ -0,0 +1,121 @@ +# Dash Core version v21.1.0 + +This is a new minor version release, bringing important bugfixes. + +This release is **mandatory** for all masternodes. +This release is optional but recommended for all other nodes. + +Please report bugs using the issue tracker at GitHub: + + + + +# Upgrading and downgrading + +## How to Upgrade + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over /Applications/Dash-Qt (on Mac) or +dashd/dash-qt (on Linux). + +## Downgrade warning + +### Downgrade to a version < v21.0.0 + +Downgrading to a version older than v21.0.0 may not be supported due to changes +if you are using descriptor wallets. + +### Downgrade to a version < v19.2.0 + +Downgrading to a version older than v19.2.0 is not supported due to changes +in the evodb database. If you need to use an older version, you must either +reindex or re-sync the whole chain. + +# Notable changes + +Allow EHF Resigning +------------------- + +During implementation, the values for requestID and msgHash for EHF signing were switched. As a result, a masternode +which participated in an earlier failed attempt to form an EHF message is unable to participate in subsequent +attempts. This is because the LLMQ Signing System requires that the requestID be unique, and that a node will not +sign two different msgHash for the same requestID. See the [forum post](https://www.dash.org/forum/index.php?threads/ehf-activation-issues.55146/) +explaining it further. + +As there is no need to restrict double signing for EHF, we now allow signing of multiple msgHash's for a single EHF +requestID. Once a sufficient number of masternodes upgrade to v21.1, the EHF message will be automatically signed and +mined. + +# v21.1.0 Change log + +See detailed [set of changes][set-of-changes]. + +# Credits + +Thanks to everyone who directly contributed to this release: + +- Konstantin Akimov +- PastaPastaPasta +- UdjinM6 +- ogabrielides + +As well as everyone that submitted issues, reviewed pull requests and helped +debug the release candidates. + +# Older releases + +These release are considered obsolete. Old release notes can be found here: + +- [v21.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-21.0.2.md) released Aug/1/2024 +- [v21.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-21.0.0.md) released Jul/25/2024 +- [v20.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-20.1.1.md) released April/3/2024 +- [v20.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-20.1.0.md) released March/5/2024 +- [v20.0.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-20.0.4.md) released Jan/13/2024 +- [v20.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-20.0.3.md) released December/26/2023 +- [v20.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-20.0.2.md) released December/06/2023 +- [v20.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-20.0.1.md) released November/18/2023 +- [v20.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-20.0.0.md) released November/15/2023 +- [v19.3.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.3.0.md) released July/31/2023 +- [v19.2.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.2.0.md) released June/19/2023 +- [v19.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.1.0.md) released May/22/2023 +- [v19.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.0.0.md) released Apr/14/2023 +- [v18.2.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.2.md) released Mar/21/2023 +- [v18.2.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.1.md) released Jan/17/2023 +- [v18.2.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.0.md) released Jan/01/2023 +- [v18.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.1.md) released January/08/2023 +- [v18.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.0.md) released October/09/2022 +- [v18.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.0.2.md) released October/09/2022 +- [v18.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.0.1.md) released August/17/2022 +- [v0.17.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.17.0.3.md) released June/07/2021 +- [v0.17.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.17.0.2.md) released May/19/2021 +- [v0.16.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.1.1.md) released November/17/2020 +- [v0.16.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.1.0.md) released November/14/2020 +- [v0.16.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.0.1.md) released September/30/2020 +- [v0.15.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.15.0.0.md) released Febrary/18/2020 +- [v0.14.0.5](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.5.md) released December/08/2019 +- [v0.14.0.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.4.md) released November/22/2019 +- [v0.14.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.3.md) released August/15/2019 +- [v0.14.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.2.md) released July/4/2019 +- [v0.14.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.1.md) released May/31/2019 +- [v0.14.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.md) released May/22/2019 +- [v0.13.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.3.md) released Apr/04/2019 +- [v0.13.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.2.md) released Mar/15/2019 +- [v0.13.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.1.md) released Feb/9/2019 +- [v0.13.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.0.md) released Jan/14/2019 +- [v0.12.3.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.4.md) released Dec/14/2018 +- [v0.12.3.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.3.md) released Sep/19/2018 +- [v0.12.3.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.2.md) released Jul/09/2018 +- [v0.12.3.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.1.md) released Jul/03/2018 +- [v0.12.2.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.3.md) released Jan/12/2018 +- [v0.12.2.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.2.md) released Dec/17/2017 +- [v0.12.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.md) released Nov/08/2017 +- [v0.12.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.1.md) released Feb/06/2017 +- [v0.12.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.0.md) released Aug/15/2015 +- [v0.11.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.2.md) released Mar/04/2015 +- [v0.11.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.1.md) released Feb/10/2015 +- [v0.11.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.0.md) released Jan/15/2015 +- [v0.10.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.10.0.md) released Sep/25/2014 +- [v0.9.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.9.0.md) released Mar/13/2014 + +[set-of-changes]: https://github.com/dashpay/dash/compare/v21.0.2...dashpay:v21.1.0 diff --git a/src/core_write.cpp b/src/core_write.cpp index ffad7897ffc0b..a2cdf68aa4c0a 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -334,7 +334,12 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, bool include_add } if (calculate_fee) { - const CAmount fee = amt_total_in - amt_total_out; + CAmount fee = amt_total_in - amt_total_out; + if (tx.IsPlatformTransfer()) { + auto payload = GetTxPayload(tx); + CHECK_NONFATAL(payload); + fee = payload->getFee(); + } CHECK_NONFATAL(MoneyRange(fee)); entry.pushKV("fee", ValueFromAmount(fee)); } diff --git a/src/evo/assetlocktx.h b/src/evo/assetlocktx.h index ff4853fb3571d..b55902fea42a4 100644 --- a/src/evo/assetlocktx.h +++ b/src/evo/assetlocktx.h @@ -22,6 +22,10 @@ namespace llmq { class CQuorumManager; } // namespace llmq +// Forward declaration from core_io to get rid of circular dependency +UniValue ValueFromAmount(const CAmount amount); +void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex, bool include_addresses); + class CAssetLockPayload { public: @@ -51,14 +55,18 @@ class CAssetLockPayload [[nodiscard]] UniValue ToJson() const { - UniValue obj; - obj.setObject(); - obj.pushKV("version", int(nVersion)); - UniValue outputs; - outputs.setArray(); - for (const CTxOut& out : creditOutputs) { - outputs.push_back(out.ToString()); + UniValue outputs(UniValue::VARR); + for (const CTxOut& credit_output : creditOutputs) { + UniValue out(UniValue::VOBJ); + out.pushKV("value", ValueFromAmount(credit_output.nValue)); + out.pushKV("valueSat", credit_output.nValue); + UniValue spk(UniValue::VOBJ); + ScriptPubKeyToUniv(credit_output.scriptPubKey, spk, /* fIncludeHex = */ true, /* include_addresses = */ false); + out.pushKV("scriptPubKey", spk); + outputs.push_back(out); } + UniValue obj(UniValue::VOBJ); + obj.pushKV("version", int(nVersion)); obj.pushKV("creditOutputs", outputs); return obj; } diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index b35dab60a9804..b75c1403c2784 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -215,7 +215,9 @@ std::vector CDeterministicMNList::GetProjectedMNPayees(gsl if (nCount < 0 ) { return {}; } - const auto weighted_count = GetValidWeightedMNsCount(); + const bool isMNRewardReallocation = DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), + Consensus::DEPLOYMENT_MN_RR); + const auto weighted_count = isMNRewardReallocation ? GetValidMNsCount() : GetValidWeightedMNsCount(); nCount = std::min(nCount, int(weighted_count)); std::vector result; @@ -223,7 +225,6 @@ std::vector CDeterministicMNList::GetProjectedMNPayees(gsl int remaining_evo_payments{0}; CDeterministicMNCPtr evo_to_be_skipped{nullptr}; - const bool isMNRewardReallocation{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR)}; if (!isMNRewardReallocation) { ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) { if (dmn->pdmnState->nLastPaidHeight == nHeight) { @@ -242,7 +243,7 @@ std::vector CDeterministicMNList::GetProjectedMNPayees(gsl ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) { if (dmn == evo_to_be_skipped) return; - for ([[maybe_unused]] auto _ : irange::range(GetMnType(dmn->nType).voting_weight)) { + for ([[maybe_unused]] auto _ : irange::range(isMNRewardReallocation ? 1 : GetMnType(dmn->nType).voting_weight)) { result.emplace_back(dmn); } }); diff --git a/src/index/base.cpp b/src/index/base.cpp index 7a0afaff8d216..920df64f194a1 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -328,7 +328,7 @@ bool BaseIndex::BlockUntilSyncedToCurrentChain() const { // Skip the queue-draining stuff if we know we're caught up with - // ::ChainActive().Tip(). + // m_chain.Tip(). LOCK(cs_main); const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip(); const CBlockIndex* best_block_index = m_best_block_index.load(); diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 3b068f16be7c8..e2365c4c89161 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -408,6 +408,7 @@ struct WalletTx int64_t time; std::map value_map; bool is_coinbase; + bool is_platform_transfer{false}; bool is_denominate; }; diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 3a57c4311a000..6852342702e4f 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -554,7 +554,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo if (txHeight != nBestSeenHeight) { // Ignore side chains and re-orgs; assuming they are random they don't // affect the estimate. We'll potentially double count transactions in 1-block reorgs. - // Ignore txs if BlockPolicyEstimator is not in sync with ::ChainActive().Tip(). + // Ignore txs if BlockPolicyEstimator is not in sync with ActiveChain().Tip(). // It will be synced next time a block is processed. return; } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index dc87c07152e98..ba56ef366df8e 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -264,6 +264,11 @@ class CTransaction return nVersion >= SPECIAL_VERSION; } + bool IsPlatformTransfer() const noexcept + { + return IsSpecialTxVersion() && nType == TRANSACTION_ASSET_UNLOCK; + } + bool HasExtraPayloadField() const noexcept { return IsSpecialTxVersion() && nType != TRANSACTION_NORMAL; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 912e8d5dd87bc..416a122317e09 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -224,6 +224,8 @@ void OptionsModel::Init(bool resetSettings) // CoinJoin if (!settings.contains("nCoinJoinSessions")) settings.setValue("nCoinJoinSessions", DEFAULT_COINJOIN_SESSIONS); + if (!gArgs.SoftSetArg("-coinjoinsessions", settings.value("nCoinJoinSessions").toString().toStdString())) + addOverriddenOption("-coinjoinsessions"); if (!settings.contains("nCoinJoinRounds")) settings.setValue("nCoinJoinRounds", DEFAULT_COINJOIN_ROUNDS); @@ -247,9 +249,13 @@ void OptionsModel::Init(bool resetSettings) if (!settings.contains("nCoinJoinDenomsGoal")) settings.setValue("nCoinJoinDenomsGoal", DEFAULT_COINJOIN_DENOMS_GOAL); + if (!gArgs.SoftSetArg("-coinjoindenomsgoal", settings.value("nCoinJoinDenomsGoal").toString().toStdString())) + addOverriddenOption("-coinjoindenomsgoal"); if (!settings.contains("nCoinJoinDenomsHardCap")) settings.setValue("nCoinJoinDenomsHardCap", DEFAULT_COINJOIN_DENOMS_HARDCAP); + if (!gArgs.SoftSetArg("-coinjoindenomshardcap", settings.value("nCoinJoinDenomsHardCap").toString().toStdString())) + addOverriddenOption("-coinjoindenomshardcap"); #endif // Network diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 139db97a784fa..0e89ffe556485 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -93,6 +93,10 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall { strHTML += "" + tr("Source") + ": " + tr("Generated") + "
"; } + else if (wtx.is_platform_transfer) + { + strHTML += "" + tr("Source") + ": " + tr("Platform Transfer") + "
"; + } else if (wtx.value_map.count("from") && !wtx.value_map["from"].empty()) { // Online transaction diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 155c368c92d25..949a4ad19a8dd 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -39,7 +39,7 @@ QList TransactionRecord::decomposeTransaction(interfaces::Wal auto node = interfaces::MakeNode(); auto& coinJoinOptions = node->coinJoinOptions(); - if (nNet > 0 || wtx.is_coinbase) + if (nNet > 0 || wtx.is_coinbase || wtx.is_platform_transfer) { // // Credit @@ -74,6 +74,11 @@ QList TransactionRecord::decomposeTransaction(interfaces::Wal // Generated sub.type = TransactionRecord::Generated; } + if (wtx.is_platform_transfer) + { + // Withdrawal from platform + sub.type = TransactionRecord::PlatformTransfer; + } parts.append(sub); } diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 113ff35f21ee5..92a6086d65a8f 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -96,7 +96,8 @@ class TransactionRecord CoinJoinCollateralPayment, CoinJoinMakeCollaterals, CoinJoinCreateDenominations, - CoinJoinSend + CoinJoinSend, + PlatformTransfer, }; /** Number of confirmation recommended for accepting a transaction */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index c08c7db2f92ef..5ba76de95752c 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -431,6 +431,8 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const return tr("Payment to yourself"); case TransactionRecord::Generated: return tr("Mined"); + case TransactionRecord::PlatformTransfer: + return tr("Platform Transfer"); case TransactionRecord::CoinJoinMixing: return tr("%1 Mixing").arg(QString::fromStdString(gCoinJoinName)); @@ -443,9 +445,10 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const case TransactionRecord::CoinJoinSend: return tr("%1 Send").arg(QString::fromStdString(gCoinJoinName)); - default: - return QString(); - } + case TransactionRecord::Other: + break; // use fail-over here + } // no default case, so the compiler can warn about missing cases + return QString(); } QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx) const @@ -473,14 +476,20 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b case TransactionRecord::SendToAddress: case TransactionRecord::Generated: case TransactionRecord::CoinJoinSend: + case TransactionRecord::PlatformTransfer: return formatAddressLabel(wtx->strAddress, wtx->label, tooltip) + watchAddress; case TransactionRecord::SendToOther: return QString::fromStdString(wtx->strAddress) + watchAddress; case TransactionRecord::SendToSelf: return formatAddressLabel(wtx->strAddress, wtx->label, tooltip) + watchAddress; - default: - return tr("(n/a)") + watchAddress; - } + case TransactionRecord::CoinJoinMixing: + case TransactionRecord::CoinJoinCollateralPayment: + case TransactionRecord::CoinJoinMakeCollaterals: + case TransactionRecord::CoinJoinCreateDenominations: + case TransactionRecord::Other: + break; // use fail-over here + } // no default case, so the compiler can warn about missing cases + return tr("(n/a)") + watchAddress; } QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const @@ -491,6 +500,7 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const case TransactionRecord::RecvWithAddress: case TransactionRecord::SendToAddress: case TransactionRecord::Generated: + case TransactionRecord::PlatformTransfer: case TransactionRecord::CoinJoinSend: case TransactionRecord::RecvWithCoinJoin: { @@ -504,9 +514,11 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const case TransactionRecord::CoinJoinMakeCollaterals: case TransactionRecord::CoinJoinCollateralPayment: return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::BAREADDRESS); - default: + case TransactionRecord::SendToOther: + case TransactionRecord::RecvFromOther: + case TransactionRecord::Other: break; - } + } // no default case, so the compiler can warn about missing cases return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::DEFAULT); } @@ -530,6 +542,7 @@ QVariant TransactionTableModel::amountColor(const TransactionRecord *rec) const case TransactionRecord::RecvWithCoinJoin: case TransactionRecord::RecvWithAddress: case TransactionRecord::RecvFromOther: + case TransactionRecord::PlatformTransfer: return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::GREEN); case TransactionRecord::CoinJoinSend: case TransactionRecord::SendToAddress: diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 573d91d64fd3a..a711082dbb7c4 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -90,6 +90,7 @@ TransactionView::TransactionView(QWidget* parent) : typeWidget->addItem(tr("%1 Collateral Payment").arg(strCoinJoinName), TransactionFilterProxy::TYPE(TransactionRecord::CoinJoinCollateralPayment)); typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf)); typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); + typeWidget->addItem(tr("Platform Transfer"), TransactionFilterProxy::TYPE(TransactionRecord::PlatformTransfer)); typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other)); typeWidget->setCurrentIndex(settings.value("transactionType").toInt()); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 524736d560d1e..6535a70f9356d 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -47,6 +47,7 @@ #include #include +#include #include #include #include @@ -2423,6 +2424,13 @@ static RPCHelpMan getblockstats() } CAmount txfee = tx_total_in - tx_total_out; + + if (tx->IsPlatformTransfer()) { + auto payload = GetTxPayload(*tx); + CHECK_NONFATAL(payload); + txfee = payload->getFee(); + } + CHECK_NONFATAL(MoneyRange(txfee)); if (do_medianfee) { fee_array.push_back(txfee); diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 923cdc0993231..ad0869c3b76a9 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -409,6 +410,13 @@ static RPCHelpMan masternode_payments() if (tx->IsCoinBase()) { continue; } + if (tx->IsPlatformTransfer()) { + auto payload = GetTxPayload(*tx); + CHECK_NONFATAL(payload); + nBlockFees += payload->getFee(); + continue; + } + CAmount nValueIn{0}; for (const auto& txin : tx->vin) { uint256 blockHashTmp; diff --git a/src/txmempool.h b/src/txmempool.h index 12efa08b5147b..ad80c24aca7b3 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -524,17 +524,14 @@ class CTxMemPool * that are guarded by it. * * @par Consistency guarantees - * * By design, it is guaranteed that: - * * 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool - * that is consistent with current chain tip (`::ChainActive()` and + * that is consistent with current chain tip (`ActiveChain()` and * `CoinsTip()`) and is fully populated. Fully populated means that if the * current active chain is missing transactions that were present in a * previously active chain, all the missing transactions will have been * re-added to the mempool and should be present if they meet size and * consistency constraints. - * * 2. Locking `mempool.cs` without `cs_main` will give a view of a mempool * consistent with some chain that was active since `cs_main` was last * locked, and that is fully populated as described above. It is ok for diff --git a/src/validation.cpp b/src/validation.cpp index 15be0df400ea4..1509b8499f29a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4678,7 +4678,7 @@ bool CVerifyDB::VerifyDB( int reportDone = 0; LogPrintf("[0%%]..."); /* Continued */ - const bool is_snapshot_cs{!chainstate.m_from_snapshot_blockhash}; + const bool is_snapshot_cs{chainstate.m_from_snapshot_blockhash}; for (pindex = chainstate.m_chain.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); diff --git a/src/validation.h b/src/validation.h index 9b2541fd933a5..b29fcf6df3f5d 100644 --- a/src/validation.h +++ b/src/validation.h @@ -104,7 +104,7 @@ static const bool DEFAULT_SYNC_MEMPOOL = true; /** Default for -stopatheight */ static const int DEFAULT_STOPATHEIGHT = 0; -/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ::ChainActive().Tip() will not be pruned. */ +/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pruned. */ static const unsigned int MIN_BLOCKS_TO_KEEP = 288; static const signed int DEFAULT_CHECKBLOCKS = 6; static const unsigned int DEFAULT_CHECKLEVEL = 3; diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 9f1ebb49fda76..04afc44e24a52 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -81,6 +81,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) result.time = wtx.GetTxTime(); result.value_map = wtx.mapValue; result.is_coinbase = wtx.IsCoinBase(); + result.is_platform_transfer = wtx.IsPlatformTransfer(); // The determination of is_denominate is based on simplified checks here because in this part of the code // we only want to know about mixing transactions belonging to this specific wallet. result.is_denominate = wtx.tx->vin.size() == wtx.tx->vout.size() && // Number of inputs is same as number of outputs diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2107cec953014..984e701da1544 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -167,6 +167,8 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa entry.pushKV("chainlock", chainlock); if (wtx.IsCoinBase()) entry.pushKV("generated", true); + if (wtx.IsPlatformTransfer()) + entry.pushKV("platform-transfer", true); if (confirms > 0) { entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex()); @@ -1419,6 +1421,10 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx, else entry.pushKV("category", "generate"); } + else if (wtx.IsPlatformTransfer()) + { + entry.pushKV("category", "platform-transfer"); + } else { entry.pushKV("category", "receive"); @@ -1483,7 +1489,8 @@ static RPCHelpMan listtransactions() "\"receive\" Non-coinbase transactions received.\n" "\"generate\" Coinbase transactions received with more than 100 confirmations.\n" "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n" - "\"orphan\" Orphaned coinbase transactions received.\n"}, + "\"orphan\" Orphaned coinbase transactions received.\n" + "\"platform-transfer\" Platform Transfer transactions received.\n"}, {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n" "for all other categories"}, {RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"}, @@ -1599,7 +1606,8 @@ static RPCHelpMan listsinceblock() "\"receive\" Non-coinbase transactions received.\n" "\"generate\" Coinbase transactions received with more than 100 confirmations.\n" "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n" - "\"orphan\" Orphaned coinbase transactions received.\n"}, + "\"orphan\" Orphaned coinbase transactions received.\n" + "\"platform-transfer\" Platform Transfer transactions received.\n"}, {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n" "for all other categories"}, {RPCResult::Type::NUM, "vout", "the vout value"}, @@ -1740,7 +1748,8 @@ static RPCHelpMan gettransaction() "\"receive\" Non-coinbase transactions received.\n" "\"generate\" Coinbase transactions received with more than 100 confirmations.\n" "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n" - "\"orphan\" Orphaned coinbase transactions received.\n"}, + "\"orphan\" Orphaned coinbase transactions received.\n" + "\"platform-transfer\" Platform Transfer transactions received.\n"}, {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT}, {RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"}, {RPCResult::Type::NUM, "vout", "the vout value"}, diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index c6fc807db18fb..fd10162ec6a28 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -526,8 +526,10 @@ static void TestWatchOnlyPubKey(LegacyScriptPubKeyMan* spk_man, const CPubKey& a // Cryptographically invalidate a PubKey whilst keeping length and first byte static void PollutePubKey(CPubKey& pubkey) { - std::vector pubkey_raw(pubkey.begin(), pubkey.end()); - std::fill(pubkey_raw.begin()+1, pubkey_raw.end(), 0); + assert(pubkey.size() >= 1); + std::vector pubkey_raw; + pubkey_raw.push_back(pubkey[0]); + pubkey_raw.insert(pubkey_raw.end(), pubkey.size() - 1, 0); pubkey = CPubKey(pubkey_raw); assert(!pubkey.IsFullyValid()); assert(pubkey.IsValid()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 36cdf3f1717ad..32e4201bba0e3 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1313,7 +1313,7 @@ void CWallet::updatedBlockTip() void CWallet::BlockUntilSyncedToCurrentChain() const { AssertLockNotHeld(cs_wallet); // Skip the queue-draining stuff if we know we're caught up with - // chainActive.Tip(), otherwise put a callback in the validation interface queue and wait + // chain().Tip(), otherwise put a callback in the validation interface queue and wait // for the queue to drain enough to execute it (indicating we are caught up // at least with the time we entered this function). uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0ac966698905d..b29a010dbe0e8 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -591,6 +591,7 @@ class CWalletTx void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; } const uint256& GetHash() const { return tx->GetHash(); } bool IsCoinBase() const { return tx->IsCoinBase(); } + bool IsPlatformTransfer() const { return tx->IsPlatformTransfer(); } bool IsImmatureCoinBase() const; // Disable copying of CWalletTx objects to prevent bugs where instances get diff --git a/test/functional/feature_asset_locks.py b/test/functional/feature_asset_locks.py index c4a1b030bedef..66b2985a3b6f6 100755 --- a/test/functional/feature_asset_locks.py +++ b/test/functional/feature_asset_locks.py @@ -30,12 +30,9 @@ from test_framework.script import ( CScript, OP_CHECKSIG, - OP_DUP, - OP_EQUALVERIFY, - OP_HASH160, OP_RETURN, - hash160, ) +from test_framework.script_util import key_to_p2pkh_script from test_framework.test_framework import DashTestFramework from test_framework.util import ( assert_equal, @@ -44,6 +41,7 @@ get_bip9_details, hex_str_to_bytes, ) +from test_framework.wallet_util import bytes_to_wif llmq_type_test = 106 # LLMQType::LLMQ_TEST_PLATFORM tiny_amount = int(Decimal("0.0007") * COIN) @@ -66,8 +64,8 @@ def create_assetlock(self, coin, amount, pubkey): tmp_amount = amount if tmp_amount > COIN: tmp_amount -= COIN - credit_outputs.append(CTxOut(COIN, CScript([OP_DUP, OP_HASH160, hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG]))) - credit_outputs.append(CTxOut(tmp_amount, CScript([OP_DUP, OP_HASH160, hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG]))) + credit_outputs.append(CTxOut(COIN, key_to_p2pkh_script(pubkey))) + credit_outputs.append(CTxOut(tmp_amount, key_to_p2pkh_script(pubkey))) lockTx_payload = CAssetLockTx(1, credit_outputs) @@ -260,6 +258,8 @@ def run_test(self): key = ECKey() key.generate() + privkey = bytes_to_wif(key.get_bytes()) + node_wallet.importprivkey(privkey) pubkey = key.get_pubkey().get_bytes() self.test_asset_locks(node_wallet, node, pubkey) @@ -281,7 +281,11 @@ def test_asset_locks(self, node_wallet, node, pubkey): self.check_mempool_result(tx=asset_lock_tx, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}}) self.validate_credit_pool_balance(0) txid_in_block = self.send_tx(asset_lock_tx) - assert "assetLockTx" in node.getrawtransaction(txid_in_block, 1) + rpc_tx = node.getrawtransaction(txid_in_block, 1) + assert_equal(len(rpc_tx["assetLockTx"]["creditOutputs"]), 2) + assert_equal(rpc_tx["assetLockTx"]["creditOutputs"][0]["valueSat"] + rpc_tx["assetLockTx"]["creditOutputs"][1]["valueSat"], locked_1) + assert_equal(rpc_tx["assetLockTx"]["creditOutputs"][0]["scriptPubKey"]["hex"], key_to_p2pkh_script(pubkey).hex()) + assert_equal(rpc_tx["assetLockTx"]["creditOutputs"][1]["scriptPubKey"]["hex"], key_to_p2pkh_script(pubkey).hex()) self.validate_credit_pool_balance(0) node.generate(1) assert_equal(self.get_credit_pool_balance(node=node), locked_1) @@ -361,6 +365,7 @@ def test_asset_unlocks(self, node_wallet, node, pubkey): self.wait_for_sporks_same() txid = self.send_tx(asset_unlock_tx) + assert_equal(node.getmempoolentry(txid)['fee'], Decimal("0.0007")) is_id = node_wallet.sendtoaddress(node_wallet.getnewaddress(), 1) for node in self.nodes: self.wait_for_instantlock(is_id, node) @@ -399,6 +404,9 @@ def test_asset_unlocks(self, node_wallet, node, pubkey): self.mempool_size -= 2 self.check_mempool_size() block_asset_unlock = node.getrawtransaction(asset_unlock_tx.rehash(), 1)['blockhash'] + self.log.info("Checking rpc `getblock` and `getblockstats` succeeds as they use own fee calculation mechanism") + assert_equal(node.getblockstats(node.getblockcount())['maxfee'], tiny_amount) + node.getblock(block_asset_unlock, 2) self.send_tx(asset_unlock_tx, expected_error = "Transaction already in block chain", @@ -477,15 +485,31 @@ def test_withdrawal_limits(self, node_wallet, node, pubkey): self.check_mempool_result(tx=asset_unlock_tx_full, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}}) txid_in_block = self.send_tx(asset_unlock_tx_full) + expected_balance = (Decimal(self.get_credit_pool_balance()) - Decimal(tiny_amount)) node.generate(1) self.sync_all() - self.log.info("Check txid_in_block was mined...") + self.log.info("Check txid_in_block was mined") block = node.getblock(node.getbestblockhash()) assert txid_in_block in block['tx'] self.validate_credit_pool_balance(0) + self.log.info(f"Check status of withdrawal and try to spend it") + withdrawal_status = node_wallet.gettransaction(txid_in_block) + assert_equal(withdrawal_status['amount'] * COIN, expected_balance) + assert_equal(withdrawal_status['details'][0]['category'], 'platform-transfer') + + spend_withdrawal_hex = node_wallet.createrawtransaction([{'txid': txid_in_block, 'vout' : 0}], { node_wallet.getnewaddress() : (expected_balance - Decimal(tiny_amount)) / COIN}) + spend_withdrawal_hex = node_wallet.signrawtransactionwithwallet(spend_withdrawal_hex)['hex'] + spend_withdrawal = tx_from_hex(spend_withdrawal_hex) + self.check_mempool_result(tx=spend_withdrawal, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}}) + spend_txid_in_block = self.send_tx(spend_withdrawal) + + node.generate(1) + block = node.getblock(node.getbestblockhash()) + assert spend_txid_in_block in block['tx'] + self.log.info("Fast forward to the next day to reset all current unlock limits...") - self.slowly_generate_batch(blocks_in_one_day + 1) + self.slowly_generate_batch(blocks_in_one_day) self.mine_quorum(llmq_type_name="llmq_test_platform", llmq_type=106) total = self.get_credit_pool_balance() diff --git a/test/functional/feature_llmq_evo.py b/test/functional/feature_llmq_evo.py index 6543b9fa6ab91..c847ab8268312 100755 --- a/test/functional/feature_llmq_evo.py +++ b/test/functional/feature_llmq_evo.py @@ -17,7 +17,7 @@ QuorumId, ser_uint256 from test_framework.test_framework import DashTestFramework from test_framework.util import ( - assert_equal, p2p_port + assert_equal, assert_greater_than_or_equal, p2p_port ) @@ -46,7 +46,7 @@ def getmnlistdiff(self, baseBlockHash, blockHash): class LLMQEvoNodesTest(DashTestFramework): def set_test_params(self): - self.set_dash_test_params(5, 4, fast_dip3_enforcement=True, evo_count=7) + self.set_dash_test_params(5, 4, fast_dip3_enforcement=True, evo_count=5) self.set_dash_llmq_test_params(4, 4) def run_test(self): @@ -92,7 +92,7 @@ def run_test(self): self.mine_cycle_quorum(llmq_type_name='llmq_test_dip0024', llmq_type=103) evo_protxhash_list = list() - for i in range(5): + for i in range(self.evo_count): evo_info = self.dynamically_add_masternode(evo=True) evo_protxhash_list.append(evo_info.proTxHash) self.nodes[0].generate(8) @@ -115,6 +115,7 @@ def run_test(self): self.log.info("Test that EvoNodes are paid 4x blocks in a row") self.test_evo_payments(window_analysis=48) + self.test_masternode_winners() self.activate_v20() self.activate_mn_rr() @@ -127,6 +128,7 @@ def run_test(self): self.log.info("Test that EvoNodes are paid 1 block in a row after MN RewardReallocation activation") self.test_evo_payments(window_analysis=48, v20active=True) + self.test_masternode_winners(mn_rr_active=True) self.log.info(self.nodes[0].masternodelist()) @@ -248,6 +250,40 @@ def test_masternode_count(self, expected_mns_count, expected_evo_count): assert_equal(detailed_count['regular']['total'], expected_mns_count) assert_equal(detailed_count['evo']['total'], expected_evo_count) + def test_masternode_winners(self, mn_rr_active=False): + # ignore recent winners, test future ones only + # we get up to 21 entries here: tip + up to 20 future payees + winners = self.nodes[0].masternode('winners', '0') + weighted_count = self.mn_count + self.evo_count * (1 if mn_rr_active else 4) + assert_equal(len(winners.keys()) - 1, 20 if weighted_count > 20 else weighted_count) + consecutive_payments = 0 + full_consecutive_payments_found = 0 + payment_cycles = 0 + first_payee = None + prev_winner = None + for height in winners.keys(): + winner = winners[height] + if mn_rr_active: + assert_equal(prev_winner == winner, False) + else: + if prev_winner == winner: + consecutive_payments += 1 + else: + if consecutive_payments == 3: + full_consecutive_payments_found += 1 + consecutive_payments = 0 + assert_greater_than_or_equal(3, consecutive_payments) + if consecutive_payments == 0 and winner == first_payee: + payment_cycles += 1 + if first_payee is None: + first_payee = winner + prev_winner = winner + if mn_rr_active: + assert_equal(full_consecutive_payments_found, 0) + else: + assert_greater_than_or_equal(full_consecutive_payments_found, (len(winners.keys()) - 1 - self.mn_count) // 4 - 1) + assert_equal(payment_cycles, (len(winners.keys()) - 1) // weighted_count) + def test_getmnlistdiff(self, baseBlockHash, blockHash, baseMNList, expectedDeleted, expectedUpdated): d = self.test_getmnlistdiff_base(baseBlockHash, blockHash)