mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Merge #6339: chore: release v21.1.1
d627a6ee52
chore: bump version to 21.1.1 (pasta)5f9700c69a
docs: release notes for v21.1.1 (pasta)1c00726aca
Merge #6277: chore: add builder key for kittywhiskers (pasta)a2bc0f1b1b
Merge #6290: chore: update pasta gpg key to reflect new subkeys (pasta)167608c7c7
Merge #6338: ci: attest results of guix builds (pasta)6fb4e49ae5
Merge #6197: ci: always build guix, save artifacts (pasta)c0ca93cf7a
Merge #6340: fix: make 6336 compile in v21.1.x branch, using older CHECK_NONFATAL functionality (pasta)bb96df428f
Merge #6336: fix: rpc getblock and getblockstats for blocks with withdrawal transactions (asset unlock) (pasta)8e70262db4
Merge #6131: feat: make a support of Qt app to show Platform transfer Tx (pasta)80ed27914e
Merge #6328: backport: bitcoin/bitcoin#30131, #23258, #30504 - fix bild for Ubuntu 24.10 + clang (pasta)bd772fbe8f
Merge #6229: fix: `creditOutputs` in AssetLock tx json output should be an array of objects, not debug strings (pasta)9bf39a93d3
Merge #6222: fix: adjust payee predictions after mn_rr activation, add tests (pasta)87bebfc246
Merge #6219: fix: correct is_snapshot_cs in VerifyDB (pasta)a4e6b8a993
Merge #6208: fix: persist coinjoin denoms options from gui over restarts (pasta) Pull request description: ## Issue being fixed or feature implemented See commits, backports, release notes, version bump ## What was done? ## How Has This Been Tested? ## Breaking Changes ## Checklist: _Go over all the following points, and put an `x` in all the boxes that apply._ - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [ ] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ACKs for top commit: knst: utACKd627a6ee52
kwvg: ACKd627a6ee52
UdjinM6: utACKd627a6ee52
ogabrielides: utACKd627a6e
Tree-SHA512: cde7e40760e16e9f48da8149c3742d18a34029b057405e4d55b87110da96acbcd19b47280451dd7b5ad1ccfc91fde655452cf5f0f0d1e01a41b4c685337c64b8
This commit is contained in:
commit
0fcc1561f1
106
.github/workflows/guix-build.yml
vendored
106
.github/workflows/guix-build.yml
vendored
@ -1,15 +1,20 @@
|
|||||||
name: Guix Build
|
name: Guix Build
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request_target:
|
||||||
types: [ labeled ]
|
push:
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build-image:
|
||||||
runs-on: [ "self-hosted", "linux", "x64", "ubuntu-core" ]
|
runs-on: ubuntu-latest
|
||||||
if: contains(github.event.pull_request.labels.*.name, 'guix-build')
|
outputs:
|
||||||
timeout-minutes: 480
|
image-tag: ${{ steps.prepare.outputs.image-tag }}
|
||||||
|
repo-name: ${{ steps.prepare.outputs.repo-name }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -22,37 +27,72 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Commit variables
|
- name: Commit variables
|
||||||
id: dockerfile
|
id: prepare
|
||||||
run: |
|
run: |
|
||||||
echo "hash=$(sha256sum ./dash/contrib/containers/guix/Dockerfile | cut -d ' ' -f1)" >> $GITHUB_OUTPUT
|
echo "hash=$(sha256sum ./dash/contrib/containers/guix/Dockerfile | cut -d ' ' -f1)" >> $GITHUB_OUTPUT
|
||||||
echo "host_user_id=$(id -u)" >> $GITHUB_OUTPUT
|
echo "host_user_id=$(id -u)" >> $GITHUB_OUTPUT
|
||||||
echo "host_group_id=$(id -g)" >> $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
|
- name: Build Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: ${{ github.workspace }}/dash
|
context: ${{ github.workspace }}/dash
|
||||||
build-args: |
|
build-args: |
|
||||||
USER_ID=${{ steps.dockerfile.outputs.host_user_id }}
|
USER_ID=${{ steps.prepare.outputs.host_user_id }}
|
||||||
GROUP_ID=${{ steps.dockerfile.outputs.host_group_id }}
|
GROUP_ID=${{ steps.prepare.outputs.host_group_id }}
|
||||||
build-contexts: |
|
build-contexts: |
|
||||||
docker_root=${{ github.workspace }}/dash/contrib/containers/guix
|
docker_root=${{ github.workspace }}/dash/contrib/containers/guix
|
||||||
file: ./dash/contrib/containers/guix/Dockerfile
|
file: ./dash/contrib/containers/guix/Dockerfile
|
||||||
load: true
|
push: true
|
||||||
tags: guix_ubuntu:latest
|
tags: |
|
||||||
cache-from: type=gha
|
ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder:${{ steps.prepare.outputs.image-tag }}
|
||||||
cache-to: type=gha,mode=max
|
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
|
||||||
|
|
||||||
- name: Restore Guix cache and depends
|
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: Cache Guix and depends
|
||||||
id: guix-cache-restore
|
id: guix-cache-restore
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
${{ github.workspace }}/.cache
|
${{ github.workspace }}/.cache
|
||||||
${{ github.workspace }}/dash/depends/built
|
${{ github.workspace }}/dash/depends/built
|
||||||
${{ github.workspace }}/dash/depends/sources
|
${{ github.workspace }}/dash/depends/sources
|
||||||
${{ github.workspace }}/dash/depends/work
|
${{ 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
|
- name: Create .cache folder if missing
|
||||||
if: steps.guix-cache-restore.outputs.cache-hit != 'true'
|
if: steps.guix-cache-restore.outputs.cache-hit != 'true'
|
||||||
@ -67,8 +107,8 @@ jobs:
|
|||||||
-v ${{ github.workspace }}/dash:/src/dash \
|
-v ${{ github.workspace }}/dash:/src/dash \
|
||||||
-v ${{ github.workspace }}/.cache:/home/ubuntu/.cache \
|
-v ${{ github.workspace }}/.cache:/home/ubuntu/.cache \
|
||||||
-w /src/dash \
|
-w /src/dash \
|
||||||
guix_ubuntu:latest && \
|
ghcr.io/${{ needs.build-image.outputs.repo-name }}/dashcore-guix-builder:${{ needs.build-image.outputs.image-tag }} && \
|
||||||
docker exec guix-daemon bash -c '/usr/local/bin/guix-start'
|
docker exec guix-daemon bash -c 'HOSTS=${{ matrix.build_target }} /usr/local/bin/guix-start'
|
||||||
|
|
||||||
- name: Ensure build passes
|
- name: Ensure build passes
|
||||||
run: |
|
run: |
|
||||||
@ -77,17 +117,19 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Save Guix cache and depends
|
|
||||||
id: guix-cache-save
|
|
||||||
uses: actions/cache/save@v3
|
|
||||||
with:
|
|
||||||
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 }}
|
|
||||||
|
|
||||||
- name: Compute SHA256 checksums
|
- name: Compute SHA256 checksums
|
||||||
|
continue-on-error: true # It will complain on depending on only some hosts
|
||||||
run: |
|
run: |
|
||||||
./dash/contrib/containers/guix/scripts/guix-check ${{ github.workspace }}/dash
|
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 }}/dash/guix-build*/output/${{ matrix.build_target }}/
|
||||||
|
|
||||||
|
- name: Attest build provenance
|
||||||
|
uses: actions/attest-build-provenance@v1
|
||||||
|
with:
|
||||||
|
subject-path: ${{ github.workspace }}/dash/guix-build*/output/${{ matrix.build_target }}/*
|
||||||
|
@ -2,7 +2,7 @@ AC_PREREQ([2.69])
|
|||||||
dnl Don't forget to push a corresponding tag when updating any of _CLIENT_VERSION_* numbers
|
dnl Don't forget to push a corresponding tag when updating any of _CLIENT_VERSION_* numbers
|
||||||
define(_CLIENT_VERSION_MAJOR, 21)
|
define(_CLIENT_VERSION_MAJOR, 21)
|
||||||
define(_CLIENT_VERSION_MINOR, 1)
|
define(_CLIENT_VERSION_MINOR, 1)
|
||||||
define(_CLIENT_VERSION_BUILD, 0)
|
define(_CLIENT_VERSION_BUILD, 1)
|
||||||
define(_CLIENT_VERSION_IS_RELEASE, true)
|
define(_CLIENT_VERSION_IS_RELEASE, true)
|
||||||
define(_COPYRIGHT_YEAR, 2024)
|
define(_COPYRIGHT_YEAR, 2024)
|
||||||
define(_COPYRIGHT_HOLDERS,[The %s developers])
|
define(_COPYRIGHT_HOLDERS,[The %s developers])
|
||||||
|
32
contrib/builder-keys/kittywhiskers.pgp
Normal file
32
contrib/builder-keys/kittywhiskers.pgp
Normal file
@ -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-----
|
@ -24,53 +24,143 @@ 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
|
||||||
u+HE6D2rqvc0CA1wAreY5+lD96PbmOAjnA==
|
N+Y0nqxwpCVq6RAJGdjYcT4BCfNTwjdYKqBEPRfK5JP+VZ6RZ6nBfZxUTfzomWWF
|
||||||
=lPi0
|
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
|
||||||
|
t8FIucvlOdt4EqKaSmoBQZk0Aj/N5q4=
|
||||||
|
=vjZr
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
@ -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 nodes.
|
||||||
This release is optional but recommended for all other nodes.
|
|
||||||
|
|
||||||
Please report bugs using the issue tracker at GitHub:
|
Please report bugs using the issue tracker at GitHub:
|
||||||
|
|
||||||
@ -34,18 +33,13 @@ reindex or re-sync the whole chain.
|
|||||||
|
|
||||||
# Notable changes
|
# Notable changes
|
||||||
|
|
||||||
Allow EHF Resigning
|
- 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)
|
||||||
During implementation, the values for requestID and msgHash for EHF signing were switched. As a result, a masternode
|
- `creditOutputs` entries in various RPCs that output transaction JSON are shown as objects now instead of being shown as strings (#6229)
|
||||||
which participated in an earlier failed attempt to form an EHF message is unable to participate in subsequent
|
- Updated PGP key for builder 'pasta' to reflect new subkeys. You may need to reimport this key to validate signatures. (#6290)
|
||||||
attempts. This is because the LLMQ Signing System requires that the requestID be unique, and that a node will not
|
- Build failures on Ubuntu 24.10 / clang 19.1.1 resolved (#6328)
|
||||||
sign two different msgHash for the same requestID. See the [forum post](https://www.dash.org/forum/index.php?threads/ehf-activation-issues.55146/)
|
- RPC errors in `masternode payments`, `getblock`, `getblockstats` related to Asset Unlock parsing have been fixed (#6336)
|
||||||
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
|
# 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:
|
Thanks to everyone who directly contributed to this release:
|
||||||
|
|
||||||
|
- Kittywhiskers Van Gogh
|
||||||
- Konstantin Akimov
|
- Konstantin Akimov
|
||||||
- PastaPastaPasta
|
- PastaPastaPasta
|
||||||
- UdjinM6
|
- UdjinM6
|
||||||
- ogabrielides
|
|
||||||
|
|
||||||
As well as everyone that submitted issues, reviewed pull requests and helped
|
As well as everyone that submitted issues, reviewed pull requests and helped
|
||||||
debug the release candidates.
|
debug the release candidates.
|
||||||
@ -67,6 +61,7 @@ debug the release candidates.
|
|||||||
|
|
||||||
These release are considered obsolete. Old release notes can be found here:
|
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.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
|
- [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.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.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
|
- [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
|
||||||
|
121
doc/release-notes/dash/release-notes-21.1.0.md
Normal file
121
doc/release-notes/dash/release-notes-21.1.0.md
Normal file
@ -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:
|
||||||
|
|
||||||
|
<https://github.com/dashpay/dash/issues>
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -334,7 +334,12 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, bool include_add
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (calculate_fee) {
|
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<CAssetUnlockPayload>(tx);
|
||||||
|
CHECK_NONFATAL(payload);
|
||||||
|
fee = payload->getFee();
|
||||||
|
}
|
||||||
CHECK_NONFATAL(MoneyRange(fee));
|
CHECK_NONFATAL(MoneyRange(fee));
|
||||||
entry.pushKV("fee", ValueFromAmount(fee));
|
entry.pushKV("fee", ValueFromAmount(fee));
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,10 @@ namespace llmq {
|
|||||||
class CQuorumManager;
|
class CQuorumManager;
|
||||||
} // namespace llmq
|
} // 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
|
class CAssetLockPayload
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -51,14 +55,18 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] UniValue ToJson() const
|
[[nodiscard]] UniValue ToJson() const
|
||||||
{
|
{
|
||||||
UniValue obj;
|
UniValue outputs(UniValue::VARR);
|
||||||
obj.setObject();
|
for (const CTxOut& credit_output : creditOutputs) {
|
||||||
obj.pushKV("version", int(nVersion));
|
UniValue out(UniValue::VOBJ);
|
||||||
UniValue outputs;
|
out.pushKV("value", ValueFromAmount(credit_output.nValue));
|
||||||
outputs.setArray();
|
out.pushKV("valueSat", credit_output.nValue);
|
||||||
for (const CTxOut& out : creditOutputs) {
|
UniValue spk(UniValue::VOBJ);
|
||||||
outputs.push_back(out.ToString());
|
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);
|
obj.pushKV("creditOutputs", outputs);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,9 @@ std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(gsl
|
|||||||
if (nCount < 0 ) {
|
if (nCount < 0 ) {
|
||||||
return {};
|
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));
|
nCount = std::min(nCount, int(weighted_count));
|
||||||
|
|
||||||
std::vector<CDeterministicMNCPtr> result;
|
std::vector<CDeterministicMNCPtr> result;
|
||||||
@ -223,7 +225,6 @@ std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(gsl
|
|||||||
|
|
||||||
int remaining_evo_payments{0};
|
int remaining_evo_payments{0};
|
||||||
CDeterministicMNCPtr evo_to_be_skipped{nullptr};
|
CDeterministicMNCPtr evo_to_be_skipped{nullptr};
|
||||||
const bool isMNRewardReallocation{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR)};
|
|
||||||
if (!isMNRewardReallocation) {
|
if (!isMNRewardReallocation) {
|
||||||
ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) {
|
ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) {
|
||||||
if (dmn->pdmnState->nLastPaidHeight == nHeight) {
|
if (dmn->pdmnState->nLastPaidHeight == nHeight) {
|
||||||
@ -242,7 +243,7 @@ std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(gsl
|
|||||||
|
|
||||||
ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) {
|
ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) {
|
||||||
if (dmn == evo_to_be_skipped) return;
|
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);
|
result.emplace_back(dmn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -328,7 +328,7 @@ bool BaseIndex::BlockUntilSyncedToCurrentChain() const
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Skip the queue-draining stuff if we know we're caught up with
|
// Skip the queue-draining stuff if we know we're caught up with
|
||||||
// ::ChainActive().Tip().
|
// m_chain.Tip().
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip();
|
const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip();
|
||||||
const CBlockIndex* best_block_index = m_best_block_index.load();
|
const CBlockIndex* best_block_index = m_best_block_index.load();
|
||||||
|
@ -408,6 +408,7 @@ struct WalletTx
|
|||||||
int64_t time;
|
int64_t time;
|
||||||
std::map<std::string, std::string> value_map;
|
std::map<std::string, std::string> value_map;
|
||||||
bool is_coinbase;
|
bool is_coinbase;
|
||||||
|
bool is_platform_transfer{false};
|
||||||
bool is_denominate;
|
bool is_denominate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -554,7 +554,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
|
|||||||
if (txHeight != nBestSeenHeight) {
|
if (txHeight != nBestSeenHeight) {
|
||||||
// Ignore side chains and re-orgs; assuming they are random they don't
|
// 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.
|
// 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.
|
// It will be synced next time a block is processed.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -264,6 +264,11 @@ public:
|
|||||||
return nVersion >= SPECIAL_VERSION;
|
return nVersion >= SPECIAL_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsPlatformTransfer() const noexcept
|
||||||
|
{
|
||||||
|
return IsSpecialTxVersion() && nType == TRANSACTION_ASSET_UNLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
bool HasExtraPayloadField() const noexcept
|
bool HasExtraPayloadField() const noexcept
|
||||||
{
|
{
|
||||||
return IsSpecialTxVersion() && nType != TRANSACTION_NORMAL;
|
return IsSpecialTxVersion() && nType != TRANSACTION_NORMAL;
|
||||||
|
@ -224,6 +224,8 @@ void OptionsModel::Init(bool resetSettings)
|
|||||||
// CoinJoin
|
// CoinJoin
|
||||||
if (!settings.contains("nCoinJoinSessions"))
|
if (!settings.contains("nCoinJoinSessions"))
|
||||||
settings.setValue("nCoinJoinSessions", DEFAULT_COINJOIN_SESSIONS);
|
settings.setValue("nCoinJoinSessions", DEFAULT_COINJOIN_SESSIONS);
|
||||||
|
if (!gArgs.SoftSetArg("-coinjoinsessions", settings.value("nCoinJoinSessions").toString().toStdString()))
|
||||||
|
addOverriddenOption("-coinjoinsessions");
|
||||||
|
|
||||||
if (!settings.contains("nCoinJoinRounds"))
|
if (!settings.contains("nCoinJoinRounds"))
|
||||||
settings.setValue("nCoinJoinRounds", DEFAULT_COINJOIN_ROUNDS);
|
settings.setValue("nCoinJoinRounds", DEFAULT_COINJOIN_ROUNDS);
|
||||||
@ -247,9 +249,13 @@ void OptionsModel::Init(bool resetSettings)
|
|||||||
|
|
||||||
if (!settings.contains("nCoinJoinDenomsGoal"))
|
if (!settings.contains("nCoinJoinDenomsGoal"))
|
||||||
settings.setValue("nCoinJoinDenomsGoal", DEFAULT_COINJOIN_DENOMS_GOAL);
|
settings.setValue("nCoinJoinDenomsGoal", DEFAULT_COINJOIN_DENOMS_GOAL);
|
||||||
|
if (!gArgs.SoftSetArg("-coinjoindenomsgoal", settings.value("nCoinJoinDenomsGoal").toString().toStdString()))
|
||||||
|
addOverriddenOption("-coinjoindenomsgoal");
|
||||||
|
|
||||||
if (!settings.contains("nCoinJoinDenomsHardCap"))
|
if (!settings.contains("nCoinJoinDenomsHardCap"))
|
||||||
settings.setValue("nCoinJoinDenomsHardCap", DEFAULT_COINJOIN_DENOMS_HARDCAP);
|
settings.setValue("nCoinJoinDenomsHardCap", DEFAULT_COINJOIN_DENOMS_HARDCAP);
|
||||||
|
if (!gArgs.SoftSetArg("-coinjoindenomshardcap", settings.value("nCoinJoinDenomsHardCap").toString().toStdString()))
|
||||||
|
addOverriddenOption("-coinjoindenomshardcap");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Network
|
// Network
|
||||||
|
@ -93,6 +93,10 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
|
|||||||
{
|
{
|
||||||
strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
|
strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
|
||||||
}
|
}
|
||||||
|
else if (wtx.is_platform_transfer)
|
||||||
|
{
|
||||||
|
strHTML += "<b>" + tr("Source") + ":</b> " + tr("Platform Transfer") + "<br>";
|
||||||
|
}
|
||||||
else if (wtx.value_map.count("from") && !wtx.value_map["from"].empty())
|
else if (wtx.value_map.count("from") && !wtx.value_map["from"].empty())
|
||||||
{
|
{
|
||||||
// Online transaction
|
// Online transaction
|
||||||
|
@ -39,7 +39,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Wal
|
|||||||
auto node = interfaces::MakeNode();
|
auto node = interfaces::MakeNode();
|
||||||
auto& coinJoinOptions = node->coinJoinOptions();
|
auto& coinJoinOptions = node->coinJoinOptions();
|
||||||
|
|
||||||
if (nNet > 0 || wtx.is_coinbase)
|
if (nNet > 0 || wtx.is_coinbase || wtx.is_platform_transfer)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Credit
|
// Credit
|
||||||
@ -74,6 +74,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Wal
|
|||||||
// Generated
|
// Generated
|
||||||
sub.type = TransactionRecord::Generated;
|
sub.type = TransactionRecord::Generated;
|
||||||
}
|
}
|
||||||
|
if (wtx.is_platform_transfer)
|
||||||
|
{
|
||||||
|
// Withdrawal from platform
|
||||||
|
sub.type = TransactionRecord::PlatformTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
parts.append(sub);
|
parts.append(sub);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,8 @@ public:
|
|||||||
CoinJoinCollateralPayment,
|
CoinJoinCollateralPayment,
|
||||||
CoinJoinMakeCollaterals,
|
CoinJoinMakeCollaterals,
|
||||||
CoinJoinCreateDenominations,
|
CoinJoinCreateDenominations,
|
||||||
CoinJoinSend
|
CoinJoinSend,
|
||||||
|
PlatformTransfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Number of confirmation recommended for accepting a transaction */
|
/** Number of confirmation recommended for accepting a transaction */
|
||||||
|
@ -431,6 +431,8 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const
|
|||||||
return tr("Payment to yourself");
|
return tr("Payment to yourself");
|
||||||
case TransactionRecord::Generated:
|
case TransactionRecord::Generated:
|
||||||
return tr("Mined");
|
return tr("Mined");
|
||||||
|
case TransactionRecord::PlatformTransfer:
|
||||||
|
return tr("Platform Transfer");
|
||||||
|
|
||||||
case TransactionRecord::CoinJoinMixing:
|
case TransactionRecord::CoinJoinMixing:
|
||||||
return tr("%1 Mixing").arg(QString::fromStdString(gCoinJoinName));
|
return tr("%1 Mixing").arg(QString::fromStdString(gCoinJoinName));
|
||||||
@ -443,9 +445,10 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const
|
|||||||
case TransactionRecord::CoinJoinSend:
|
case TransactionRecord::CoinJoinSend:
|
||||||
return tr("%1 Send").arg(QString::fromStdString(gCoinJoinName));
|
return tr("%1 Send").arg(QString::fromStdString(gCoinJoinName));
|
||||||
|
|
||||||
default:
|
case TransactionRecord::Other:
|
||||||
return QString();
|
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
|
QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx) const
|
||||||
@ -473,14 +476,20 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b
|
|||||||
case TransactionRecord::SendToAddress:
|
case TransactionRecord::SendToAddress:
|
||||||
case TransactionRecord::Generated:
|
case TransactionRecord::Generated:
|
||||||
case TransactionRecord::CoinJoinSend:
|
case TransactionRecord::CoinJoinSend:
|
||||||
|
case TransactionRecord::PlatformTransfer:
|
||||||
return formatAddressLabel(wtx->strAddress, wtx->label, tooltip) + watchAddress;
|
return formatAddressLabel(wtx->strAddress, wtx->label, tooltip) + watchAddress;
|
||||||
case TransactionRecord::SendToOther:
|
case TransactionRecord::SendToOther:
|
||||||
return QString::fromStdString(wtx->strAddress) + watchAddress;
|
return QString::fromStdString(wtx->strAddress) + watchAddress;
|
||||||
case TransactionRecord::SendToSelf:
|
case TransactionRecord::SendToSelf:
|
||||||
return formatAddressLabel(wtx->strAddress, wtx->label, tooltip) + watchAddress;
|
return formatAddressLabel(wtx->strAddress, wtx->label, tooltip) + watchAddress;
|
||||||
default:
|
case TransactionRecord::CoinJoinMixing:
|
||||||
return tr("(n/a)") + watchAddress;
|
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
|
QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
|
||||||
@ -491,6 +500,7 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
|
|||||||
case TransactionRecord::RecvWithAddress:
|
case TransactionRecord::RecvWithAddress:
|
||||||
case TransactionRecord::SendToAddress:
|
case TransactionRecord::SendToAddress:
|
||||||
case TransactionRecord::Generated:
|
case TransactionRecord::Generated:
|
||||||
|
case TransactionRecord::PlatformTransfer:
|
||||||
case TransactionRecord::CoinJoinSend:
|
case TransactionRecord::CoinJoinSend:
|
||||||
case TransactionRecord::RecvWithCoinJoin:
|
case TransactionRecord::RecvWithCoinJoin:
|
||||||
{
|
{
|
||||||
@ -504,9 +514,11 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
|
|||||||
case TransactionRecord::CoinJoinMakeCollaterals:
|
case TransactionRecord::CoinJoinMakeCollaterals:
|
||||||
case TransactionRecord::CoinJoinCollateralPayment:
|
case TransactionRecord::CoinJoinCollateralPayment:
|
||||||
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::BAREADDRESS);
|
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::BAREADDRESS);
|
||||||
default:
|
case TransactionRecord::SendToOther:
|
||||||
|
case TransactionRecord::RecvFromOther:
|
||||||
|
case TransactionRecord::Other:
|
||||||
break;
|
break;
|
||||||
}
|
} // no default case, so the compiler can warn about missing cases
|
||||||
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::DEFAULT);
|
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,6 +542,7 @@ QVariant TransactionTableModel::amountColor(const TransactionRecord *rec) const
|
|||||||
case TransactionRecord::RecvWithCoinJoin:
|
case TransactionRecord::RecvWithCoinJoin:
|
||||||
case TransactionRecord::RecvWithAddress:
|
case TransactionRecord::RecvWithAddress:
|
||||||
case TransactionRecord::RecvFromOther:
|
case TransactionRecord::RecvFromOther:
|
||||||
|
case TransactionRecord::PlatformTransfer:
|
||||||
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::GREEN);
|
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::GREEN);
|
||||||
case TransactionRecord::CoinJoinSend:
|
case TransactionRecord::CoinJoinSend:
|
||||||
case TransactionRecord::SendToAddress:
|
case TransactionRecord::SendToAddress:
|
||||||
|
@ -90,6 +90,7 @@ TransactionView::TransactionView(QWidget* parent) :
|
|||||||
typeWidget->addItem(tr("%1 Collateral Payment").arg(strCoinJoinName), TransactionFilterProxy::TYPE(TransactionRecord::CoinJoinCollateralPayment));
|
typeWidget->addItem(tr("%1 Collateral Payment").arg(strCoinJoinName), TransactionFilterProxy::TYPE(TransactionRecord::CoinJoinCollateralPayment));
|
||||||
typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
|
typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
|
||||||
typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
|
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->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
|
||||||
typeWidget->setCurrentIndex(settings.value("transactionType").toInt());
|
typeWidget->setCurrentIndex(settings.value("transactionType").toInt());
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include <versionbits.h>
|
#include <versionbits.h>
|
||||||
#include <warnings.h>
|
#include <warnings.h>
|
||||||
|
|
||||||
|
#include <evo/assetlocktx.h>
|
||||||
#include <evo/cbtx.h>
|
#include <evo/cbtx.h>
|
||||||
#include <evo/evodb.h>
|
#include <evo/evodb.h>
|
||||||
#include <evo/mnhftx.h>
|
#include <evo/mnhftx.h>
|
||||||
@ -2423,6 +2424,13 @@ static RPCHelpMan getblockstats()
|
|||||||
}
|
}
|
||||||
|
|
||||||
CAmount txfee = tx_total_in - tx_total_out;
|
CAmount txfee = tx_total_in - tx_total_out;
|
||||||
|
|
||||||
|
if (tx->IsPlatformTransfer()) {
|
||||||
|
auto payload = GetTxPayload<CAssetUnlockPayload>(*tx);
|
||||||
|
CHECK_NONFATAL(payload);
|
||||||
|
txfee = payload->getFee();
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_NONFATAL(MoneyRange(txfee));
|
CHECK_NONFATAL(MoneyRange(txfee));
|
||||||
if (do_medianfee) {
|
if (do_medianfee) {
|
||||||
fee_array.push_back(txfee);
|
fee_array.push_back(txfee);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
|
#include <evo/assetlocktx.h>
|
||||||
#include <evo/chainhelper.h>
|
#include <evo/chainhelper.h>
|
||||||
#include <evo/deterministicmns.h>
|
#include <evo/deterministicmns.h>
|
||||||
#include <governance/classes.h>
|
#include <governance/classes.h>
|
||||||
@ -409,6 +410,13 @@ static RPCHelpMan masternode_payments()
|
|||||||
if (tx->IsCoinBase()) {
|
if (tx->IsCoinBase()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (tx->IsPlatformTransfer()) {
|
||||||
|
auto payload = GetTxPayload<CAssetUnlockPayload>(*tx);
|
||||||
|
CHECK_NONFATAL(payload);
|
||||||
|
nBlockFees += payload->getFee();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
CAmount nValueIn{0};
|
CAmount nValueIn{0};
|
||||||
for (const auto& txin : tx->vin) {
|
for (const auto& txin : tx->vin) {
|
||||||
uint256 blockHashTmp;
|
uint256 blockHashTmp;
|
||||||
|
@ -524,17 +524,14 @@ public:
|
|||||||
* that are guarded by it.
|
* that are guarded by it.
|
||||||
*
|
*
|
||||||
* @par Consistency guarantees
|
* @par Consistency guarantees
|
||||||
*
|
|
||||||
* By design, it is guaranteed that:
|
* By design, it is guaranteed that:
|
||||||
*
|
|
||||||
* 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool
|
* 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
|
* `CoinsTip()`) and is fully populated. Fully populated means that if the
|
||||||
* current active chain is missing transactions that were present in a
|
* current active chain is missing transactions that were present in a
|
||||||
* previously active chain, all the missing transactions will have been
|
* previously active chain, all the missing transactions will have been
|
||||||
* re-added to the mempool and should be present if they meet size and
|
* re-added to the mempool and should be present if they meet size and
|
||||||
* consistency constraints.
|
* consistency constraints.
|
||||||
*
|
|
||||||
* 2. Locking `mempool.cs` without `cs_main` will give a view of a mempool
|
* 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
|
* 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
|
* locked, and that is fully populated as described above. It is ok for
|
||||||
|
@ -4678,7 +4678,7 @@ bool CVerifyDB::VerifyDB(
|
|||||||
int reportDone = 0;
|
int reportDone = 0;
|
||||||
LogPrintf("[0%%]..."); /* Continued */
|
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) {
|
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))));
|
const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
|
||||||
|
@ -104,7 +104,7 @@ static const bool DEFAULT_SYNC_MEMPOOL = true;
|
|||||||
|
|
||||||
/** Default for -stopatheight */
|
/** Default for -stopatheight */
|
||||||
static const int DEFAULT_STOPATHEIGHT = 0;
|
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 unsigned int MIN_BLOCKS_TO_KEEP = 288;
|
||||||
static const signed int DEFAULT_CHECKBLOCKS = 6;
|
static const signed int DEFAULT_CHECKBLOCKS = 6;
|
||||||
static const unsigned int DEFAULT_CHECKLEVEL = 3;
|
static const unsigned int DEFAULT_CHECKLEVEL = 3;
|
||||||
|
@ -81,6 +81,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
|
|||||||
result.time = wtx.GetTxTime();
|
result.time = wtx.GetTxTime();
|
||||||
result.value_map = wtx.mapValue;
|
result.value_map = wtx.mapValue;
|
||||||
result.is_coinbase = wtx.IsCoinBase();
|
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
|
// 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.
|
// 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
|
result.is_denominate = wtx.tx->vin.size() == wtx.tx->vout.size() && // Number of inputs is same as number of outputs
|
||||||
|
@ -167,6 +167,8 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa
|
|||||||
entry.pushKV("chainlock", chainlock);
|
entry.pushKV("chainlock", chainlock);
|
||||||
if (wtx.IsCoinBase())
|
if (wtx.IsCoinBase())
|
||||||
entry.pushKV("generated", true);
|
entry.pushKV("generated", true);
|
||||||
|
if (wtx.IsPlatformTransfer())
|
||||||
|
entry.pushKV("platform-transfer", true);
|
||||||
if (confirms > 0)
|
if (confirms > 0)
|
||||||
{
|
{
|
||||||
entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
|
entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
|
||||||
@ -1419,6 +1421,10 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
|||||||
else
|
else
|
||||||
entry.pushKV("category", "generate");
|
entry.pushKV("category", "generate");
|
||||||
}
|
}
|
||||||
|
else if (wtx.IsPlatformTransfer())
|
||||||
|
{
|
||||||
|
entry.pushKV("category", "platform-transfer");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entry.pushKV("category", "receive");
|
entry.pushKV("category", "receive");
|
||||||
@ -1483,7 +1489,8 @@ static RPCHelpMan listtransactions()
|
|||||||
"\"receive\" Non-coinbase transactions received.\n"
|
"\"receive\" Non-coinbase transactions received.\n"
|
||||||
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
|
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
|
||||||
"\"immature\" Coinbase transactions received with 100 or fewer 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"
|
{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"},
|
"for all other categories"},
|
||||||
{RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
|
{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"
|
"\"receive\" Non-coinbase transactions received.\n"
|
||||||
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
|
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
|
||||||
"\"immature\" Coinbase transactions received with 100 or fewer 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"
|
{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"},
|
"for all other categories"},
|
||||||
{RPCResult::Type::NUM, "vout", "the vout value"},
|
{RPCResult::Type::NUM, "vout", "the vout value"},
|
||||||
@ -1740,7 +1748,8 @@ static RPCHelpMan gettransaction()
|
|||||||
"\"receive\" Non-coinbase transactions received.\n"
|
"\"receive\" Non-coinbase transactions received.\n"
|
||||||
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
|
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
|
||||||
"\"immature\" Coinbase transactions received with 100 or fewer 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_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
|
||||||
{RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
|
{RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
|
||||||
{RPCResult::Type::NUM, "vout", "the vout value"},
|
{RPCResult::Type::NUM, "vout", "the vout value"},
|
||||||
|
@ -526,8 +526,10 @@ static void TestWatchOnlyPubKey(LegacyScriptPubKeyMan* spk_man, const CPubKey& a
|
|||||||
// Cryptographically invalidate a PubKey whilst keeping length and first byte
|
// Cryptographically invalidate a PubKey whilst keeping length and first byte
|
||||||
static void PollutePubKey(CPubKey& pubkey)
|
static void PollutePubKey(CPubKey& pubkey)
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> pubkey_raw(pubkey.begin(), pubkey.end());
|
assert(pubkey.size() >= 1);
|
||||||
std::fill(pubkey_raw.begin()+1, pubkey_raw.end(), 0);
|
std::vector<unsigned char> pubkey_raw;
|
||||||
|
pubkey_raw.push_back(pubkey[0]);
|
||||||
|
pubkey_raw.insert(pubkey_raw.end(), pubkey.size() - 1, 0);
|
||||||
pubkey = CPubKey(pubkey_raw);
|
pubkey = CPubKey(pubkey_raw);
|
||||||
assert(!pubkey.IsFullyValid());
|
assert(!pubkey.IsFullyValid());
|
||||||
assert(pubkey.IsValid());
|
assert(pubkey.IsValid());
|
||||||
|
@ -1313,7 +1313,7 @@ void CWallet::updatedBlockTip()
|
|||||||
void CWallet::BlockUntilSyncedToCurrentChain() const {
|
void CWallet::BlockUntilSyncedToCurrentChain() const {
|
||||||
AssertLockNotHeld(cs_wallet);
|
AssertLockNotHeld(cs_wallet);
|
||||||
// Skip the queue-draining stuff if we know we're caught up with
|
// 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
|
// for the queue to drain enough to execute it (indicating we are caught up
|
||||||
// at least with the time we entered this function).
|
// at least with the time we entered this function).
|
||||||
uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
|
uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
|
||||||
|
@ -591,6 +591,7 @@ public:
|
|||||||
void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; }
|
void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; }
|
||||||
const uint256& GetHash() const { return tx->GetHash(); }
|
const uint256& GetHash() const { return tx->GetHash(); }
|
||||||
bool IsCoinBase() const { return tx->IsCoinBase(); }
|
bool IsCoinBase() const { return tx->IsCoinBase(); }
|
||||||
|
bool IsPlatformTransfer() const { return tx->IsPlatformTransfer(); }
|
||||||
bool IsImmatureCoinBase() const;
|
bool IsImmatureCoinBase() const;
|
||||||
|
|
||||||
// Disable copying of CWalletTx objects to prevent bugs where instances get
|
// Disable copying of CWalletTx objects to prevent bugs where instances get
|
||||||
|
@ -30,12 +30,9 @@ from test_framework.messages import (
|
|||||||
from test_framework.script import (
|
from test_framework.script import (
|
||||||
CScript,
|
CScript,
|
||||||
OP_CHECKSIG,
|
OP_CHECKSIG,
|
||||||
OP_DUP,
|
|
||||||
OP_EQUALVERIFY,
|
|
||||||
OP_HASH160,
|
|
||||||
OP_RETURN,
|
OP_RETURN,
|
||||||
hash160,
|
|
||||||
)
|
)
|
||||||
|
from test_framework.script_util import key_to_p2pkh_script
|
||||||
from test_framework.test_framework import DashTestFramework
|
from test_framework.test_framework import DashTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
@ -44,6 +41,7 @@ from test_framework.util import (
|
|||||||
get_bip9_details,
|
get_bip9_details,
|
||||||
hex_str_to_bytes,
|
hex_str_to_bytes,
|
||||||
)
|
)
|
||||||
|
from test_framework.wallet_util import bytes_to_wif
|
||||||
|
|
||||||
llmq_type_test = 106 # LLMQType::LLMQ_TEST_PLATFORM
|
llmq_type_test = 106 # LLMQType::LLMQ_TEST_PLATFORM
|
||||||
tiny_amount = int(Decimal("0.0007") * COIN)
|
tiny_amount = int(Decimal("0.0007") * COIN)
|
||||||
@ -66,8 +64,8 @@ class AssetLocksTest(DashTestFramework):
|
|||||||
tmp_amount = amount
|
tmp_amount = amount
|
||||||
if tmp_amount > COIN:
|
if tmp_amount > COIN:
|
||||||
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(COIN, key_to_p2pkh_script(pubkey)))
|
||||||
credit_outputs.append(CTxOut(tmp_amount, CScript([OP_DUP, OP_HASH160, hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG])))
|
credit_outputs.append(CTxOut(tmp_amount, key_to_p2pkh_script(pubkey)))
|
||||||
|
|
||||||
lockTx_payload = CAssetLockTx(1, credit_outputs)
|
lockTx_payload = CAssetLockTx(1, credit_outputs)
|
||||||
|
|
||||||
@ -260,6 +258,8 @@ class AssetLocksTest(DashTestFramework):
|
|||||||
|
|
||||||
key = ECKey()
|
key = ECKey()
|
||||||
key.generate()
|
key.generate()
|
||||||
|
privkey = bytes_to_wif(key.get_bytes())
|
||||||
|
node_wallet.importprivkey(privkey)
|
||||||
pubkey = key.get_pubkey().get_bytes()
|
pubkey = key.get_pubkey().get_bytes()
|
||||||
|
|
||||||
self.test_asset_locks(node_wallet, node, pubkey)
|
self.test_asset_locks(node_wallet, node, pubkey)
|
||||||
@ -281,7 +281,11 @@ class AssetLocksTest(DashTestFramework):
|
|||||||
self.check_mempool_result(tx=asset_lock_tx, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}})
|
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)
|
self.validate_credit_pool_balance(0)
|
||||||
txid_in_block = self.send_tx(asset_lock_tx)
|
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)
|
self.validate_credit_pool_balance(0)
|
||||||
node.generate(1)
|
node.generate(1)
|
||||||
assert_equal(self.get_credit_pool_balance(node=node), locked_1)
|
assert_equal(self.get_credit_pool_balance(node=node), locked_1)
|
||||||
@ -361,6 +365,7 @@ class AssetLocksTest(DashTestFramework):
|
|||||||
self.wait_for_sporks_same()
|
self.wait_for_sporks_same()
|
||||||
|
|
||||||
txid = self.send_tx(asset_unlock_tx)
|
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)
|
is_id = node_wallet.sendtoaddress(node_wallet.getnewaddress(), 1)
|
||||||
for node in self.nodes:
|
for node in self.nodes:
|
||||||
self.wait_for_instantlock(is_id, node)
|
self.wait_for_instantlock(is_id, node)
|
||||||
@ -399,6 +404,9 @@ class AssetLocksTest(DashTestFramework):
|
|||||||
self.mempool_size -= 2
|
self.mempool_size -= 2
|
||||||
self.check_mempool_size()
|
self.check_mempool_size()
|
||||||
block_asset_unlock = node.getrawtransaction(asset_unlock_tx.rehash(), 1)['blockhash']
|
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,
|
self.send_tx(asset_unlock_tx,
|
||||||
expected_error = "Transaction already in block chain",
|
expected_error = "Transaction already in block chain",
|
||||||
@ -477,15 +485,31 @@ class AssetLocksTest(DashTestFramework):
|
|||||||
self.check_mempool_result(tx=asset_unlock_tx_full, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}})
|
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)
|
txid_in_block = self.send_tx(asset_unlock_tx_full)
|
||||||
|
expected_balance = (Decimal(self.get_credit_pool_balance()) - Decimal(tiny_amount))
|
||||||
node.generate(1)
|
node.generate(1)
|
||||||
self.sync_all()
|
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())
|
block = node.getblock(node.getbestblockhash())
|
||||||
assert txid_in_block in block['tx']
|
assert txid_in_block in block['tx']
|
||||||
self.validate_credit_pool_balance(0)
|
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.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)
|
self.mine_quorum(llmq_type_name="llmq_test_platform", llmq_type=106)
|
||||||
|
|
||||||
total = self.get_credit_pool_balance()
|
total = self.get_credit_pool_balance()
|
||||||
|
@ -17,7 +17,7 @@ from test_framework.messages import CBlock, CBlockHeader, CCbTx, CMerkleBlock, f
|
|||||||
QuorumId, ser_uint256
|
QuorumId, ser_uint256
|
||||||
from test_framework.test_framework import DashTestFramework
|
from test_framework.test_framework import DashTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
assert_equal, p2p_port
|
assert_equal, assert_greater_than_or_equal, p2p_port
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class TestP2PConn(P2PInterface):
|
|||||||
|
|
||||||
class LLMQEvoNodesTest(DashTestFramework):
|
class LLMQEvoNodesTest(DashTestFramework):
|
||||||
def set_test_params(self):
|
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)
|
self.set_dash_llmq_test_params(4, 4)
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
@ -92,7 +92,7 @@ class LLMQEvoNodesTest(DashTestFramework):
|
|||||||
self.mine_cycle_quorum(llmq_type_name='llmq_test_dip0024', llmq_type=103)
|
self.mine_cycle_quorum(llmq_type_name='llmq_test_dip0024', llmq_type=103)
|
||||||
|
|
||||||
evo_protxhash_list = list()
|
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_info = self.dynamically_add_masternode(evo=True)
|
||||||
evo_protxhash_list.append(evo_info.proTxHash)
|
evo_protxhash_list.append(evo_info.proTxHash)
|
||||||
self.nodes[0].generate(8)
|
self.nodes[0].generate(8)
|
||||||
@ -115,6 +115,7 @@ class LLMQEvoNodesTest(DashTestFramework):
|
|||||||
|
|
||||||
self.log.info("Test that EvoNodes are paid 4x blocks in a row")
|
self.log.info("Test that EvoNodes are paid 4x blocks in a row")
|
||||||
self.test_evo_payments(window_analysis=48)
|
self.test_evo_payments(window_analysis=48)
|
||||||
|
self.test_masternode_winners()
|
||||||
|
|
||||||
self.activate_v20()
|
self.activate_v20()
|
||||||
self.activate_mn_rr()
|
self.activate_mn_rr()
|
||||||
@ -127,6 +128,7 @@ class LLMQEvoNodesTest(DashTestFramework):
|
|||||||
|
|
||||||
self.log.info("Test that EvoNodes are paid 1 block in a row after MN RewardReallocation activation")
|
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_evo_payments(window_analysis=48, v20active=True)
|
||||||
|
self.test_masternode_winners(mn_rr_active=True)
|
||||||
|
|
||||||
self.log.info(self.nodes[0].masternodelist())
|
self.log.info(self.nodes[0].masternodelist())
|
||||||
|
|
||||||
@ -248,6 +250,40 @@ class LLMQEvoNodesTest(DashTestFramework):
|
|||||||
assert_equal(detailed_count['regular']['total'], expected_mns_count)
|
assert_equal(detailed_count['regular']['total'], expected_mns_count)
|
||||||
assert_equal(detailed_count['evo']['total'], expected_evo_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):
|
def test_getmnlistdiff(self, baseBlockHash, blockHash, baseMNList, expectedDeleted, expectedUpdated):
|
||||||
d = self.test_getmnlistdiff_base(baseBlockHash, blockHash)
|
d = self.test_getmnlistdiff_base(baseBlockHash, blockHash)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user