Merge remote-tracking branch 'origin/long_lived/atari' into dl_offer_hooks

This commit is contained in:
Matt Hauff 2022-08-01 09:51:14 -05:00
commit e27f48159f
No known key found for this signature in database
GPG Key ID: 3CBA6CFC81A00E46
46 changed files with 1416 additions and 772 deletions

View File

@ -29,6 +29,7 @@ jobs:
python-version: [ 3.9 ]
env:
CHIA_ROOT: ${{ github.workspace }}/.chia/mainnet
BLOCKS_AND_PLOTS_VERSION: 0.29.0
steps:
- name: Clean workspace
@ -62,7 +63,7 @@ jobs:
with:
repository: 'Chia-Network/test-cache'
path: '.chia'
ref: '0.29.0'
ref: ${{ env.BLOCKS_AND_PLOTS_VERSION }}
fetch-depth: 1
- name: Run install script

View File

@ -97,6 +97,7 @@ jobs:
env:
CHIA_ROOT: ${{ github.workspace }}/.chia/mainnet
JOB_FILE_NAME: tests_${{ matrix.os.file_name }}_python-${{ matrix.python.file_name }}_${{ matrix.configuration.name }}
BLOCKS_AND_PLOTS_VERSION: 0.29.0
steps:
- name: Configure git
@ -152,21 +153,21 @@ jobs:
path: |
${{ github.workspace }}/.chia/blocks
${{ github.workspace }}/.chia/test-plots
key: 0.29.0
key: ${{ env.BLOCKS_AND_PLOTS_VERSION }}
- name: Checkout test blocks and plots (macOS, Ubuntu)
if: steps.test-blocks-plots.outputs.cache-hit != 'true' && (matrix.os.matrix == 'ubuntu' || matrix.os.matrix == 'macos')
run: |
wget -qO- https://github.com/Chia-Network/test-cache/archive/refs/tags/0.29.0.tar.gz | tar xzf -
wget -qO- https://github.com/Chia-Network/test-cache/archive/refs/tags/${{ env.BLOCKS_AND_PLOTS_VERSION }}.tar.gz | tar xzf -
mkdir ${{ github.workspace }}/.chia
mv ${{ github.workspace }}/test-cache-0.29.0/* ${{ github.workspace }}/.chia
mv ${{ github.workspace }}/test-cache-${{ env.BLOCKS_AND_PLOTS_VERSION }}/* ${{ github.workspace }}/.chia
- name: Checkout test blocks and plots (Windows)
if: steps.test-blocks-plots.outputs.cache-hit != 'true' && matrix.os.matrix == 'windows'
run: |
Invoke-WebRequest -OutFile blocks_and_plots.zip https://github.com/Chia-Network/test-cache/archive/refs/tags/0.29.0.zip; Expand-Archive blocks_and_plots.zip -DestinationPath .
Invoke-WebRequest -OutFile blocks_and_plots.zip https://github.com/Chia-Network/test-cache/archive/refs/tags/${{ env.BLOCKS_AND_PLOTS_VERSION }}.zip; Expand-Archive blocks_and_plots.zip -DestinationPath .
mkdir ${{ github.workspace }}/.chia
mv ${{ github.workspace }}/test-cache-0.29.0/* ${{ github.workspace }}/.chia
mv ${{ github.workspace }}/test-cache-${{ env.BLOCKS_AND_PLOTS_VERSION }}/* ${{ github.workspace }}/.chia
- name: Install boost (macOS)
if: matrix.os.matrix == 'macos'

View File

@ -5194,9 +5194,9 @@
}
},
"node_modules/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"node_modules/minimist-options": {
"version": "4.1.0",
@ -5385,14 +5385,22 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"node_modules/node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
@ -12155,9 +12163,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"minimist-options": {
"version": "4.1.0",
@ -12298,9 +12306,9 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
},

View File

@ -5036,9 +5036,9 @@
}
},
"node_modules/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"node_modules/minimist-options": {
"version": "4.1.0",
@ -5227,14 +5227,22 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"node_modules/node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
@ -6058,9 +6066,9 @@
}
},
"node_modules/plist": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz",
"integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==",
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz",
"integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==",
"dependencies": {
"base64-js": "^1.5.1",
"xmlbuilder": "^9.0.7"
@ -11851,9 +11859,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"minimist-options": {
"version": "4.1.0",
@ -11994,9 +12002,9 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
},
@ -12624,9 +12632,9 @@
}
},
"plist": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz",
"integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==",
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz",
"integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==",
"requires": {
"base64-js": "^1.5.1",
"xmlbuilder": "^9.0.7"

View File

@ -6158,9 +6158,9 @@
}
},
"node_modules/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"node_modules/minimist-options": {
"version": "4.1.0",
@ -6372,14 +6372,22 @@
"optional": true
},
"node_modules/node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
@ -14054,9 +14062,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"minimist-options": {
"version": "4.1.0",
@ -14220,9 +14228,9 @@
"optional": true
},
"node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
},

View File

@ -6133,9 +6133,9 @@
}
},
"node_modules/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"node_modules/minimist-options": {
"version": "4.1.0",
@ -6344,14 +6344,22 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node_modules/node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
@ -13989,9 +13997,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"minimist-options": {
"version": "4.1.0",
@ -14152,9 +14160,9 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
},

View File

@ -4974,9 +4974,9 @@
}
},
"node_modules/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"node_modules/minimist-options": {
"version": "4.1.0",
@ -5165,14 +5165,22 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"node_modules/node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
@ -11722,9 +11730,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"minimist-options": {
"version": "4.1.0",
@ -11865,9 +11873,9 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
},

View File

@ -12,9 +12,9 @@ def passphrase_cmd():
@passphrase_cmd.command(
"set",
help="""Sets or updates the keyring passphrase. If --passphrase-file and/or --current-passphrase-file options are provided,
the passphrases will be read from the specified files. Otherwise, a prompt will be provided to enter the
passphrase.""",
help="""Sets or updates the keyring passphrase. If --passphrase-file and/or --current-passphrase-file options are
provided, the passphrases will be read from the specified files. Otherwise, a prompt will be provided to
enter the passphrase.""",
short_help="Set or update the keyring passphrase",
)
@click.option("--passphrase-file", type=click.File("r"), help="File or descriptor to read the passphrase from")
@ -70,8 +70,8 @@ def set_cmd(
@passphrase_cmd.command(
"remove",
help="""Remove the keyring passphrase. If the --current-passphrase-file option is provided, the passphrase will be read from
the specified file. Otherwise, a prompt will be provided to enter the passphrase.""",
help="""Remove the keyring passphrase. If the --current-passphrase-file option is provided, the passphrase will be
read from the specified file. Otherwise, a prompt will be provided to enter the passphrase.""",
short_help="Remove the keyring passphrase",
)
@click.option(

View File

@ -71,7 +71,7 @@ class BlockchainInterface:
return None
async def persist_sub_epoch_challenge_segments(
self, sub_epoch_summary_height: bytes32, segments: List[SubEpochChallengeSegment]
self, sub_epoch_summary_hash: bytes32, segments: List[SubEpochChallengeSegment]
) -> None:
pass

View File

@ -244,7 +244,6 @@ class WebSocketServer:
self.log.error(f"Unexpected exception trying to send to websocket: {e} {tb}")
self.remove_connection(socket)
await socket.close()
break
else:
service_name = "Unknown"
if ws in self.remote_address_map:

View File

@ -180,7 +180,7 @@ class PoolWallet:
raise ValueError(f"Invalid internal Pool State: {err}: {initial_target_state}")
async def get_spend_history(self) -> List[Tuple[uint32, CoinSpend]]:
return self.wallet_state_manager.pool_store.get_spends_for_wallet(self.wallet_id)
return await self.wallet_state_manager.pool_store.get_spends_for_wallet(self.wallet_id)
async def get_current_state(self) -> PoolWalletInfo:
history: List[Tuple[uint32, CoinSpend]] = await self.get_spend_history()
@ -228,7 +228,7 @@ class PoolWallet:
return await self.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(self.wallet_id)
async def get_tip(self) -> Tuple[uint32, CoinSpend]:
return self.wallet_state_manager.pool_store.get_spends_for_wallet(self.wallet_id)[-1]
return (await self.wallet_state_manager.pool_store.get_spends_for_wallet(self.wallet_id))[-1]
async def update_pool_config(self) -> None:
current_state: PoolWalletInfo = await self.get_current_state()
@ -286,7 +286,9 @@ class PoolWallet:
self.log.info(f"New PoolWallet singleton tip_coin: {tip_spend} farmed at height {block_height}")
# If we have reached the target state, resets it to None. Loops back to get current state
for _, added_spend in reversed(self.wallet_state_manager.pool_store.get_spends_for_wallet(self.wallet_id)):
for _, added_spend in reversed(
await self.wallet_state_manager.pool_store.get_spends_for_wallet(self.wallet_id)
):
latest_state: Optional[PoolState] = solution_to_pool_state(added_spend)
if latest_state is not None:
if self.target_state == latest_state:
@ -303,9 +305,9 @@ class PoolWallet:
Returns True if the wallet should be removed.
"""
try:
history: List[Tuple[uint32, CoinSpend]] = self.wallet_state_manager.pool_store.get_spends_for_wallet(
history: List[Tuple[uint32, CoinSpend]] = await self.wallet_state_manager.pool_store.get_spends_for_wallet(
self.wallet_id
).copy()
)
prev_state: PoolWalletInfo = await self.get_current_state()
await self.wallet_state_manager.pool_store.rollback(block_height, self.wallet_id, in_transaction)

View File

@ -1,7 +1,7 @@
import ipaddress
from typing import Any, Dict, List, Optional
from chia.rpc.rpc_server import Endpoint
from chia.rpc.rpc_server import Endpoint, EndpointResult
from chia.seeder.crawler import Crawler
from chia.util.ws_message import WsRpcMessage, create_payload_dict
@ -28,7 +28,7 @@ class CrawlerRpcApi:
return payloads
async def get_peer_counts(self, _request: Dict) -> Dict[str, Any]:
async def get_peer_counts(self, _request: Dict) -> EndpointResult:
ipv6_addresses_count = 0
for host in self.service.best_timestamp_per_peer.keys():
try:
@ -52,7 +52,7 @@ class CrawlerRpcApi:
}
return data
async def get_ips_after_timestamp(self, _request: Dict) -> Dict[str, Any]:
async def get_ips_after_timestamp(self, _request: Dict) -> EndpointResult:
after = _request.get("after", None)
if after is None:
raise ValueError("`after` is required and must be a unix timestamp")

View File

@ -4,7 +4,7 @@ from pathlib import Path
from chia.data_layer.data_layer import DataLayer
from chia.data_layer.data_layer_util import Side, Subscription
from chia.rpc.rpc_server import Endpoint
from chia.rpc.rpc_server import Endpoint, EndpointResult
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.byte_types import hexstr_to_bytes
@ -73,20 +73,20 @@ class DataLayerRpcApi:
"/add_missing_files": self.add_missing_files,
}
async def create_data_store(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def create_data_store(self, request: Dict[str, Any]) -> EndpointResult:
if self.service is None:
raise Exception("Data layer not created")
fee = get_fee(self.service.config, request)
txs, value = await self.service.create_store(uint64(fee))
return {"txs": txs, "id": value.hex()}
async def get_owned_stores(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_owned_stores(self, request: Dict[str, Any]) -> EndpointResult:
if self.service is None:
raise Exception("Data layer not created")
singleton_records = await self.service.get_owned_stores()
return {"store_ids": [singleton.launcher_id.hex() for singleton in singleton_records]}
async def get_value(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_value(self, request: Dict[str, Any]) -> EndpointResult:
store_id = bytes32.from_hexstr(request["id"])
key = hexstr_to_bytes(request["key"])
if self.service is None:
@ -97,7 +97,7 @@ class DataLayerRpcApi:
hex = value.hex()
return {"value": hex}
async def get_keys_values(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_keys_values(self, request: Dict[str, Any]) -> EndpointResult:
store_id = bytes32(hexstr_to_bytes(request["id"]))
root_hash = request.get("root_hash")
if root_hash is not None:
@ -111,7 +111,7 @@ class DataLayerRpcApi:
json_nodes.append(json)
return {"keys_values": json_nodes}
async def get_ancestors(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_ancestors(self, request: Dict[str, Any]) -> EndpointResult:
store_id = bytes32(hexstr_to_bytes(request["id"]))
node_hash = bytes32.from_hexstr(request["hash"])
if self.service is None:
@ -119,7 +119,7 @@ class DataLayerRpcApi:
value = await self.service.get_ancestors(node_hash, store_id)
return {"ancestors": value}
async def batch_update(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def batch_update(self, request: Dict[str, Any]) -> EndpointResult:
"""
id - the id of the store we are operating on
changelist - a list of changes to apply on store
@ -135,7 +135,7 @@ class DataLayerRpcApi:
raise Exception(f"Batch update failed for: {store_id}")
return {"tx_id": transaction_record.name}
async def insert(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def insert(self, request: Dict[str, Any]) -> EndpointResult:
"""
rows_to_add a list of clvm objects as bytes to add to talbe
rows_to_remove a list of row hashes to remove
@ -151,7 +151,7 @@ class DataLayerRpcApi:
transaction_record = await self.service.batch_update(store_id, changelist, uint64(fee))
return {"tx_id": transaction_record.name}
async def delete_key(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def delete_key(self, request: Dict[str, Any]) -> EndpointResult:
"""
rows_to_add a list of clvm objects as bytes to add to talbe
rows_to_remove a list of row hashes to remove
@ -166,7 +166,7 @@ class DataLayerRpcApi:
transaction_record = await self.service.batch_update(store_id, changelist, uint64(fee))
return {"tx_id": transaction_record.name}
async def get_root(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_root(self, request: Dict[str, Any]) -> EndpointResult:
"""get hash of latest tree root"""
store_id = bytes32(hexstr_to_bytes(request["id"]))
# todo input checks
@ -177,7 +177,7 @@ class DataLayerRpcApi:
raise Exception(f"Failed to get root for {store_id.hex()}")
return {"hash": rec.root, "confirmed": rec.confirmed, "timestamp": rec.timestamp}
async def get_local_root(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_local_root(self, request: Dict[str, Any]) -> EndpointResult:
"""get hash of latest tree root saved in our local datastore"""
store_id = bytes32(hexstr_to_bytes(request["id"]))
# todo input checks
@ -186,7 +186,7 @@ class DataLayerRpcApi:
res = await self.service.get_local_root(store_id)
return {"hash": res}
async def get_roots(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_roots(self, request: Dict[str, Any]) -> EndpointResult:
"""
get state hashes for a list of roots
"""
@ -202,7 +202,7 @@ class DataLayerRpcApi:
roots.append({"id": id_bytes, "hash": rec.root, "confirmed": rec.confirmed, "timestamp": rec.timestamp})
return {"root_hashes": roots}
async def subscribe(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def subscribe(self, request: Dict[str, Any]) -> EndpointResult:
"""
subscribe to singleton
"""
@ -217,7 +217,7 @@ class DataLayerRpcApi:
await self.service.subscribe(store_id=store_id_bytes, urls=urls)
return {}
async def unsubscribe(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def unsubscribe(self, request: Dict[str, Any]) -> EndpointResult:
"""
unsubscribe from singleton
"""
@ -230,7 +230,7 @@ class DataLayerRpcApi:
await self.service.unsubscribe(store_id_bytes)
return {}
async def subscriptions(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def subscriptions(self, request: Dict[str, Any]) -> EndpointResult:
"""
List current subscriptions
"""
@ -239,7 +239,7 @@ class DataLayerRpcApi:
subscriptions: List[Subscription] = await self.service.get_subscriptions()
return {"store_ids": [sub.tree_id.hex() for sub in subscriptions]}
async def add_missing_files(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def add_missing_files(self, request: Dict[str, Any]) -> EndpointResult:
"""
complete the data server files.
"""
@ -257,7 +257,7 @@ class DataLayerRpcApi:
await self.service.add_missing_files(tree_id, override, foldername)
return {}
async def get_root_history(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_root_history(self, request: Dict[str, Any]) -> EndpointResult:
"""
get history of state hashes for a store
"""
@ -271,7 +271,7 @@ class DataLayerRpcApi:
res.insert(0, {"root_hash": rec.root, "confirmed": rec.confirmed, "timestamp": rec.timestamp})
return {"root_history": res}
async def get_kv_diff(self, request: Dict[str, Any]) -> Dict[str, Any]:
async def get_kv_diff(self, request: Dict[str, Any]) -> EndpointResult:
"""
get kv diff between two root hashes
"""

View File

@ -7,7 +7,7 @@ from typing_extensions import Protocol
from chia.farmer.farmer import Farmer
from chia.plot_sync.receiver import Receiver
from chia.protocols.harvester_protocol import Plot
from chia.rpc.rpc_server import Endpoint
from chia.rpc.rpc_server import Endpoint, EndpointResult
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.byte_types import hexstr_to_bytes
from chia.util.ints import uint32
@ -161,7 +161,7 @@ class FarmerRpcApi:
return payloads
async def get_signage_point(self, request: Dict) -> Dict:
async def get_signage_point(self, request: Dict) -> EndpointResult:
sp_hash = hexstr_to_bytes(request["sp_hash"])
for _, sps in self.service.sps.items():
for sp in sps:
@ -180,7 +180,7 @@ class FarmerRpcApi:
}
raise ValueError(f"Signage point {sp_hash.hex()} not found")
async def get_signage_points(self, _: Dict) -> Dict[str, Any]:
async def get_signage_points(self, _: Dict) -> EndpointResult:
result: List[Dict[str, Any]] = []
for sps in self.service.sps.values():
for sp in sps:
@ -200,12 +200,12 @@ class FarmerRpcApi:
)
return {"signage_points": result}
async def get_reward_targets(self, request: Dict) -> Dict:
async def get_reward_targets(self, request: Dict) -> EndpointResult:
search_for_private_key = request["search_for_private_key"]
max_ph_to_search = request.get("max_ph_to_search", 500)
return await self.service.get_reward_targets(search_for_private_key, max_ph_to_search)
async def set_reward_targets(self, request: Dict) -> Dict:
async def set_reward_targets(self, request: Dict) -> EndpointResult:
farmer_target, pool_target = None, None
if "farmer_target" in request:
farmer_target = request["farmer_target"]
@ -223,7 +223,7 @@ class FarmerRpcApi:
)
return plot_count
async def get_pool_state(self, _: Dict) -> Dict:
async def get_pool_state(self, _: Dict) -> EndpointResult:
pools_list = []
for p2_singleton_puzzle_hash, pool_dict in self.service.pool_state.items():
pool_state = pool_dict.copy()
@ -232,18 +232,18 @@ class FarmerRpcApi:
pools_list.append(pool_state)
return {"pool_state": pools_list}
async def set_payout_instructions(self, request: Dict) -> Dict:
async def set_payout_instructions(self, request: Dict) -> EndpointResult:
launcher_id: bytes32 = bytes32.from_hexstr(request["launcher_id"])
await self.service.set_payout_instructions(launcher_id, request["payout_instructions"])
return {}
async def get_harvesters(self, _: Dict):
async def get_harvesters(self, _: Dict) -> EndpointResult:
return await self.service.get_harvesters(False)
async def get_harvesters_summary(self, _: Dict[str, object]) -> Dict[str, object]:
async def get_harvesters_summary(self, _: Dict[str, object]) -> EndpointResult:
return await self.service.get_harvesters(True)
async def get_harvester_plots_valid(self, request_dict: Dict[str, object]) -> Dict[str, object]:
async def get_harvester_plots_valid(self, request_dict: Dict[str, object]) -> EndpointResult:
# TODO: Consider having a extra List[PlotInfo] in Receiver to avoid rebuilding the list for each call
request = PlotInfoRequestData.from_json_dict(request_dict)
plot_list = list(self.service.get_receiver(request.node_id).plots().values())
@ -271,16 +271,16 @@ class FarmerRpcApi:
source = sorted(source, reverse=request.reverse)
return paginated_plot_request(source, request)
async def get_harvester_plots_invalid(self, request_dict: Dict[str, object]) -> Dict[str, object]:
async def get_harvester_plots_invalid(self, request_dict: Dict[str, object]) -> EndpointResult:
return self.paginated_plot_path_request(Receiver.invalid, request_dict)
async def get_harvester_plots_keys_missing(self, request_dict: Dict[str, object]) -> Dict[str, object]:
async def get_harvester_plots_keys_missing(self, request_dict: Dict[str, object]) -> EndpointResult:
return self.paginated_plot_path_request(Receiver.keys_missing, request_dict)
async def get_harvester_plots_duplicates(self, request_dict: Dict[str, object]) -> Dict[str, object]:
async def get_harvester_plots_duplicates(self, request_dict: Dict[str, object]) -> EndpointResult:
return self.paginated_plot_path_request(Receiver.duplicates, request_dict)
async def get_pool_login_link(self, request: Dict) -> Dict:
async def get_pool_login_link(self, request: Dict) -> EndpointResult:
launcher_id: bytes32 = bytes32(hexstr_to_bytes(request["launcher_id"]))
login_link: Optional[str] = await self.service.generate_login_link(launcher_id)
if login_link is None:

View File

@ -4,7 +4,7 @@ from chia.consensus.block_record import BlockRecord
from chia.consensus.pos_quality import UI_ACTUAL_SPACE_CONSTANT_FACTOR
from chia.full_node.full_node import FullNode
from chia.full_node.mempool_check_conditions import get_puzzle_and_solution_for_coin
from chia.rpc.rpc_server import Endpoint
from chia.rpc.rpc_server import Endpoint, EndpointResult
from chia.types.blockchain_format.program import Program, SerializedProgram
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.coin_record import CoinRecord
@ -96,11 +96,11 @@ class FullNodeRpcApi:
# this function is just here for backwards-compatibility. It will probably
# be removed in the future
async def get_initial_freeze_period(self, _: Dict):
async def get_initial_freeze_period(self, _: Dict) -> EndpointResult:
# Mon May 03 2021 17:00:00 GMT+0000
return {"INITIAL_FREEZE_END_TIMESTAMP": 1620061200}
async def get_blockchain_state(self, _request: Dict):
async def get_blockchain_state(self, _request: Dict) -> EndpointResult:
"""
Returns a summary of the node's view of the blockchain.
"""
@ -214,12 +214,12 @@ class FullNodeRpcApi:
self.cached_blockchain_state = dict(response["blockchain_state"])
return response
async def get_network_info(self, request: Dict):
async def get_network_info(self, request: Dict) -> EndpointResult:
network_name = self.service.config["selected_network"]
address_prefix = self.service.config["network_overrides"]["config"][network_name]["address_prefix"]
return {"network_name": network_name, "network_prefix": address_prefix}
async def get_recent_signage_point_or_eos(self, request: Dict):
async def get_recent_signage_point_or_eos(self, request: Dict) -> EndpointResult:
if "sp_hash" not in request:
challenge_hash: bytes32 = bytes32.from_hexstr(request["challenge_hash"])
# This is the case of getting an end of slot
@ -308,7 +308,7 @@ class FullNodeRpcApi:
return {"signage_point": sp, "time_received": time_received, "reverted": True}
async def get_block(self, request: Dict) -> Dict[str, object]:
async def get_block(self, request: Dict) -> EndpointResult:
if "header_hash" not in request:
raise ValueError("No header_hash in request")
header_hash = bytes32.from_hexstr(request["header_hash"])
@ -319,7 +319,7 @@ class FullNodeRpcApi:
return {"block": block}
async def get_blocks(self, request: Dict) -> Dict[str, object]:
async def get_blocks(self, request: Dict) -> EndpointResult:
if "start" not in request:
raise ValueError("No start in request")
if "end" not in request:
@ -349,7 +349,7 @@ class FullNodeRpcApi:
json_blocks.append(json)
return {"blocks": json_blocks}
async def get_block_count_metrics(self, request: Dict):
async def get_block_count_metrics(self, request: Dict) -> EndpointResult:
compact_blocks = 0
uncompact_blocks = 0
with log_exceptions(self.service.log, consume=True):
@ -369,7 +369,7 @@ class FullNodeRpcApi:
}
}
async def get_block_records(self, request: Dict) -> Dict[str, object]:
async def get_block_records(self, request: Dict) -> EndpointResult:
if "start" not in request:
raise ValueError("No start in request")
if "end" not in request:
@ -399,7 +399,7 @@ class FullNodeRpcApi:
records.append(record)
return {"block_records": records}
async def get_block_record_by_height(self, request: Dict) -> Dict[str, object]:
async def get_block_record_by_height(self, request: Dict) -> EndpointResult:
if "height" not in request:
raise ValueError("No height in request")
height = request["height"]
@ -418,7 +418,7 @@ class FullNodeRpcApi:
raise ValueError(f"Block {header_hash} does not exist")
return {"block_record": record}
async def get_block_record(self, request: Dict):
async def get_block_record(self, request: Dict) -> EndpointResult:
if "header_hash" not in request:
raise ValueError("header_hash not in request")
header_hash_str = request["header_hash"]
@ -432,7 +432,7 @@ class FullNodeRpcApi:
return {"block_record": record}
async def get_unfinished_block_headers(self, request: Dict) -> Dict[str, object]:
async def get_unfinished_block_headers(self, request: Dict) -> EndpointResult:
peak: Optional[BlockRecord] = self.service.blockchain.get_peak()
if peak is None:
@ -453,7 +453,7 @@ class FullNodeRpcApi:
response_headers.append(unfinished_header_block)
return {"headers": response_headers}
async def get_network_space(self, request: Dict) -> Dict[str, object]:
async def get_network_space(self, request: Dict) -> EndpointResult:
"""
Retrieves an estimate of total space validating the chain
between two block header hashes.
@ -493,7 +493,7 @@ class FullNodeRpcApi:
)
return {"space": uint128(int(network_space_bytes_estimate))}
async def get_coin_records_by_puzzle_hash(self, request: Dict) -> Dict[str, object]:
async def get_coin_records_by_puzzle_hash(self, request: Dict) -> EndpointResult:
"""
Retrieves the coins for a given puzzlehash, by default returns unspent coins.
"""
@ -512,7 +512,7 @@ class FullNodeRpcApi:
return {"coin_records": [coin_record_dict_backwards_compat(cr.to_json_dict()) for cr in coin_records]}
async def get_coin_records_by_puzzle_hashes(self, request: Dict) -> Dict[str, object]:
async def get_coin_records_by_puzzle_hashes(self, request: Dict) -> EndpointResult:
"""
Retrieves the coins for a given puzzlehash, by default returns unspent coins.
"""
@ -534,7 +534,7 @@ class FullNodeRpcApi:
return {"coin_records": [coin_record_dict_backwards_compat(cr.to_json_dict()) for cr in coin_records]}
async def get_coin_record_by_name(self, request: Dict) -> Dict[str, object]:
async def get_coin_record_by_name(self, request: Dict) -> EndpointResult:
"""
Retrieves a coin record by it's name.
"""
@ -548,7 +548,7 @@ class FullNodeRpcApi:
return {"coin_record": coin_record_dict_backwards_compat(coin_record.to_json_dict())}
async def get_coin_records_by_names(self, request: Dict) -> Dict[str, object]:
async def get_coin_records_by_names(self, request: Dict) -> EndpointResult:
"""
Retrieves the coins for given coin IDs, by default returns unspent coins.
"""
@ -570,7 +570,7 @@ class FullNodeRpcApi:
return {"coin_records": [coin_record_dict_backwards_compat(cr.to_json_dict()) for cr in coin_records]}
async def get_coin_records_by_parent_ids(self, request: Dict) -> Dict[str, object]:
async def get_coin_records_by_parent_ids(self, request: Dict) -> EndpointResult:
"""
Retrieves the coins for given parent coin IDs, by default returns unspent coins.
"""
@ -592,7 +592,7 @@ class FullNodeRpcApi:
return {"coin_records": [coin_record_dict_backwards_compat(cr.to_json_dict()) for cr in coin_records]}
async def get_coin_records_by_hint(self, request: Dict) -> Dict[str, object]:
async def get_coin_records_by_hint(self, request: Dict) -> EndpointResult:
"""
Retrieves coins by hint, by default returns unspent coins.
"""
@ -621,7 +621,7 @@ class FullNodeRpcApi:
return {"coin_records": [coin_record_dict_backwards_compat(cr.to_json_dict()) for cr in coin_records]}
async def push_tx(self, request: Dict) -> Dict[str, object]:
async def push_tx(self, request: Dict) -> EndpointResult:
if "spend_bundle" not in request:
raise ValueError("Spend bundle not in request")
@ -646,7 +646,7 @@ class FullNodeRpcApi:
"status": status.name,
}
async def get_puzzle_and_solution(self, request: Dict) -> Dict[str, object]:
async def get_puzzle_and_solution(self, request: Dict) -> EndpointResult:
coin_name: bytes32 = bytes32.from_hexstr(request["coin_id"])
height = request["height"]
coin_record = await self.service.coin_store.get_coin_record(coin_name)
@ -672,7 +672,7 @@ class FullNodeRpcApi:
solution_ser: SerializedProgram = SerializedProgram.from_program(Program.to(solution))
return {"coin_solution": CoinSpend(coin_record.coin, puzzle_ser, solution_ser)}
async def get_additions_and_removals(self, request: Dict) -> Dict[str, object]:
async def get_additions_and_removals(self, request: Dict) -> EndpointResult:
if "header_hash" not in request:
raise ValueError("No header_hash in request")
header_hash = bytes32.from_hexstr(request["header_hash"])
@ -692,17 +692,17 @@ class FullNodeRpcApi:
"removals": [coin_record_dict_backwards_compat(cr.to_json_dict()) for cr in removals],
}
async def get_all_mempool_tx_ids(self, request: Dict) -> Dict[str, object]:
async def get_all_mempool_tx_ids(self, request: Dict) -> EndpointResult:
ids = list(self.service.mempool_manager.mempool.spends.keys())
return {"tx_ids": ids}
async def get_all_mempool_items(self, request: Dict) -> Dict[str, object]:
async def get_all_mempool_items(self, request: Dict) -> EndpointResult:
spends = {}
for tx_id, item in self.service.mempool_manager.mempool.spends.items():
spends[tx_id.hex()] = item
return {"mempool_items": spends}
async def get_mempool_item_by_tx_id(self, request: Dict) -> Dict[str, object]:
async def get_mempool_item_by_tx_id(self, request: Dict) -> EndpointResult:
if "tx_id" not in request:
raise ValueError("No tx_id in request")
tx_id: bytes32 = bytes32.from_hexstr(request["tx_id"])

View File

@ -1,7 +1,7 @@
from typing import Any, Dict, List
from chia.harvester.harvester import Harvester
from chia.rpc.rpc_server import Endpoint
from chia.rpc.rpc_server import Endpoint, EndpointResult
from chia.util.ws_message import WsRpcMessage, create_payload_dict
@ -36,7 +36,7 @@ class HarvesterRpcApi:
return payloads
async def get_plots(self, request: Dict) -> Dict:
async def get_plots(self, request: Dict) -> EndpointResult:
plots, failed_to_open, not_found = self.service.get_plots()
return {
"plots": plots,
@ -44,27 +44,27 @@ class HarvesterRpcApi:
"not_found_filenames": not_found,
}
async def refresh_plots(self, request: Dict) -> Dict:
async def refresh_plots(self, request: Dict) -> EndpointResult:
self.service.plot_manager.trigger_refresh()
return {}
async def delete_plot(self, request: Dict) -> Dict:
async def delete_plot(self, request: Dict) -> EndpointResult:
filename = request["filename"]
if self.service.delete_plot(filename):
return {}
raise ValueError(f"Not able to delete file {filename}")
async def add_plot_directory(self, request: Dict) -> Dict:
async def add_plot_directory(self, request: Dict) -> EndpointResult:
directory_name = request["dirname"]
if await self.service.add_plot_directory(directory_name):
return {}
raise ValueError(f"Did not add plot directory {directory_name}")
async def get_plot_directories(self, request: Dict) -> Dict:
async def get_plot_directories(self, request: Dict) -> EndpointResult:
plot_dirs = await self.service.get_plot_directories()
return {"directories": plot_dirs}
async def remove_plot_directory(self, request: Dict) -> Dict:
async def remove_plot_directory(self, request: Dict) -> EndpointResult:
directory_name = request["dirname"]
if await self.service.remove_plot_directory(directory_name):
return {}

View File

@ -26,7 +26,8 @@ log = logging.getLogger(__name__)
max_message_size = 50 * 1024 * 1024 # 50MB
Endpoint = Callable[[Dict[str, object]], Awaitable[Dict[str, object]]]
EndpointResult = Dict[str, Any]
Endpoint = Callable[[Dict[str, object]], Awaitable[EndpointResult]]
class RpcApiProtocol(Protocol):
@ -112,13 +113,13 @@ class RpcServer:
"/healthz": self.healthz,
}
async def _get_routes(self, request: Dict[str, Any]) -> Dict[str, object]:
async def _get_routes(self, request: Dict[str, Any]) -> EndpointResult:
return {
"success": "true",
"routes": list(self.get_routes().keys()),
}
async def get_connections(self, request: Dict[str, Any]) -> Dict[str, object]:
async def get_connections(self, request: Dict[str, Any]) -> EndpointResult:
request_node_type: Optional[NodeType] = None
if "node_type" in request:
request_node_type = NodeType(request["node_type"])
@ -174,7 +175,7 @@ class RpcServer:
]
return {"connections": con_info}
async def open_connection(self, request: Dict[str, Any]) -> Dict[str, object]:
async def open_connection(self, request: Dict[str, Any]) -> EndpointResult:
host = request["host"]
port = request["port"]
target_node: PeerInfo = PeerInfo(host, uint16(int(port)))
@ -187,7 +188,7 @@ class RpcServer:
raise ValueError("Start client failed, or server is not set")
return {}
async def close_connection(self, request: Dict[str, Any]) -> Dict[str, object]:
async def close_connection(self, request: Dict[str, Any]) -> EndpointResult:
node_id = hexstr_to_bytes(request["node_id"])
if self.rpc_api.service.server is None:
raise web.HTTPInternalServerError()
@ -198,7 +199,7 @@ class RpcServer:
await connection.close()
return {}
async def stop_node(self, request: Dict[str, Any]) -> Dict[str, object]:
async def stop_node(self, request: Dict[str, Any]) -> EndpointResult:
"""
Shuts down the node.
"""
@ -206,19 +207,19 @@ class RpcServer:
self.stop_cb()
return {}
async def healthz(self, request: Dict[str, Any]) -> Dict[str, object]:
async def healthz(self, request: Dict[str, Any]) -> EndpointResult:
return {
"success": "true",
}
async def ws_api(self, message: WsRpcMessage) -> Dict[str, object]:
async def ws_api(self, message: WsRpcMessage) -> Optional[Dict[str, object]]:
"""
This function gets called when new message is received via websocket.
"""
command = message["command"]
if message["ack"]:
return {}
return None
data: Dict[str, object] = {}
if "data" in message:

View File

@ -3,7 +3,7 @@ import dataclasses
import json
import logging
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, Tuple
from typing import Any, Dict, List, Optional, Set, Tuple, Union
from blspy import G1Element, G2Element, PrivateKey
@ -13,7 +13,7 @@ from chia.pools.pool_wallet import PoolWallet
from chia.pools.pool_wallet_info import FARMING_TO_POOL, PoolState, PoolWalletInfo, create_pool_state
from chia.protocols.protocol_message_types import ProtocolMessageTypes
from chia.protocols.wallet_protocol import CoinState
from chia.rpc.rpc_server import Endpoint
from chia.rpc.rpc_server import Endpoint, EndpointResult
from chia.server.outbound_message import NodeType, make_msg
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
from chia.types.announcement import Announcement
@ -206,7 +206,7 @@ class WalletRpcApi:
# Key management
##########################################################################################
async def log_in(self, request):
async def log_in(self, request) -> EndpointResult:
"""
Logs in the wallet with a specific key.
"""
@ -223,10 +223,10 @@ class WalletRpcApi:
return {"success": False, "error": "Unknown Error"}
async def get_logged_in_fingerprint(self, request: Dict):
async def get_logged_in_fingerprint(self, request: Dict) -> EndpointResult:
return {"fingerprint": self.service.logged_in_fingerprint}
async def get_public_keys(self, request: Dict):
async def get_public_keys(self, request: Dict) -> EndpointResult:
try:
fingerprints = [
sk.get_g1().get_fingerprint() for (sk, seed) in await self.service.keychain_proxy.get_all_private_keys()
@ -248,7 +248,7 @@ class WalletRpcApi:
log.error(f"Failed to get private key by fingerprint: {e}")
return None, None
async def get_private_key(self, request):
async def get_private_key(self, request) -> EndpointResult:
fingerprint = request["fingerprint"]
sk, seed = await self._get_private_key(fingerprint)
if sk is not None:
@ -265,10 +265,10 @@ class WalletRpcApi:
}
return {"success": False, "private_key": {"fingerprint": fingerprint}}
async def generate_mnemonic(self, request: Dict):
async def generate_mnemonic(self, request: Dict) -> EndpointResult:
return {"mnemonic": generate_mnemonic().split(" ")}
async def add_key(self, request):
async def add_key(self, request) -> EndpointResult:
if "mnemonic" not in request:
raise ValueError("Mnemonic not in request")
@ -300,7 +300,7 @@ class WalletRpcApi:
return {"fingerprint": fingerprint}
raise ValueError("Failed to start")
async def delete_key(self, request):
async def delete_key(self, request) -> EndpointResult:
await self._stop_wallet()
fingerprint = request["fingerprint"]
try:
@ -340,7 +340,7 @@ class WalletRpcApi:
return found_farmer, found_pool
async def check_delete_key(self, request):
async def check_delete_key(self, request) -> EndpointResult:
"""Check the key use prior to possible deletion
checks whether key is used for either farm or pool rewards
checks if any wallets have a non-zero balance
@ -379,7 +379,7 @@ class WalletRpcApi:
"wallet_balance": walletBalance,
}
async def delete_all_keys(self, request: Dict):
async def delete_all_keys(self, request: Dict) -> EndpointResult:
await self._stop_wallet()
try:
await self.service.keychain_proxy.delete_all_keys()
@ -395,28 +395,28 @@ class WalletRpcApi:
# Wallet Node
##########################################################################################
async def get_sync_status(self, request: Dict):
async def get_sync_status(self, request: Dict) -> EndpointResult:
syncing = self.service.wallet_state_manager.sync_mode
synced = await self.service.wallet_state_manager.synced()
return {"synced": synced, "syncing": syncing, "genesis_initialized": True}
async def get_height_info(self, request: Dict):
async def get_height_info(self, request: Dict) -> EndpointResult:
height = await self.service.wallet_state_manager.blockchain.get_finished_sync_up_to()
return {"height": height}
async def get_network_info(self, request: Dict):
async def get_network_info(self, request: Dict) -> EndpointResult:
network_name = self.service.config["selected_network"]
address_prefix = self.service.config["network_overrides"]["config"][network_name]["address_prefix"]
return {"network_name": network_name, "network_prefix": address_prefix}
async def push_tx(self, request: Dict):
async def push_tx(self, request: Dict) -> EndpointResult:
nodes = self.service.server.get_full_node_connections()
if len(nodes) == 0:
raise ValueError("Wallet is not currently connected to any full node peers")
await self.service.push_tx(SpendBundle.from_bytes(hexstr_to_bytes(request["spend_bundle"])))
return {}
async def farm_block(self, request):
async def farm_block(self, request) -> EndpointResult:
raw_puzzle_hash = decode_puzzle_hash(request["address"])
request = FarmNewBlockProtocol(raw_puzzle_hash)
msg = make_msg(ProtocolMessageTypes.farm_new_block, request)
@ -428,7 +428,7 @@ class WalletRpcApi:
# Wallet Management
##########################################################################################
async def get_wallets(self, request: Dict):
async def get_wallets(self, request: Dict) -> EndpointResult:
include_data: bool = request.get("include_data", True)
wallet_type: Optional[WalletType] = None
if "type" in request:
@ -442,7 +442,7 @@ class WalletRpcApi:
wallets = result
return {"wallets": wallets}
async def create_new_wallet(self, request: Dict):
async def create_new_wallet(self, request: Dict) -> EndpointResult:
wallet_state_manager = self.service.wallet_state_manager
if await self.service.wallet_state_manager.synced() is False:
@ -652,13 +652,14 @@ class WalletRpcApi:
else: # undefined wallet_type
pass
return None
# TODO: rework this function to report detailed errors for each error case
return {"success": False, "error": "invalid request"}
##########################################################################################
# Wallet
##########################################################################################
async def get_wallet_balance(self, request: Dict) -> Dict:
async def get_wallet_balance(self, request: Dict) -> EndpointResult:
wallet_id = uint32(int(request["wallet_id"]))
wallet = self.service.wallet_state_manager.wallets[wallet_id]
@ -710,7 +711,7 @@ class WalletRpcApi:
return {"wallet_balance": wallet_balance}
async def get_transaction(self, request: Dict) -> Dict:
async def get_transaction(self, request: Dict) -> EndpointResult:
transaction_id: bytes32 = bytes32(hexstr_to_bytes(request["transaction_id"]))
tr: Optional[TransactionRecord] = await self.service.wallet_state_manager.get_transaction(transaction_id)
if tr is None:
@ -721,7 +722,7 @@ class WalletRpcApi:
"transaction_id": tr.name,
}
async def get_transactions(self, request: Dict) -> Dict:
async def get_transactions(self, request: Dict) -> EndpointResult:
wallet_id = int(request["wallet_id"])
start = request.get("start", 0)
@ -745,7 +746,7 @@ class WalletRpcApi:
"wallet_id": wallet_id,
}
async def get_transaction_count(self, request: Dict) -> Dict:
async def get_transaction_count(self, request: Dict) -> EndpointResult:
wallet_id = int(request["wallet_id"])
count = await self.service.wallet_state_manager.tx_store.get_transaction_count_for_wallet(wallet_id)
return {
@ -755,11 +756,11 @@ class WalletRpcApi:
# this function is just here for backwards-compatibility. It will probably
# be removed in the future
async def get_initial_freeze_period(self, _: Dict):
async def get_initial_freeze_period(self, _: Dict) -> EndpointResult:
# Mon May 03 2021 17:00:00 GMT+0000
return {"INITIAL_FREEZE_END_TIMESTAMP": 1620061200}
async def get_next_address(self, request: Dict) -> Dict:
async def get_next_address(self, request: Dict) -> EndpointResult:
"""
Returns a new address
"""
@ -785,11 +786,11 @@ class WalletRpcApi:
"address": address,
}
async def send_transaction(self, request):
async def send_transaction(self, request) -> EndpointResult:
if await self.service.wallet_state_manager.synced() is False:
raise ValueError("Wallet needs to be fully synced before sending transactions")
wallet_id = int(request["wallet_id"])
wallet_id = uint32(request["wallet_id"])
wallet = self.service.wallet_state_manager.wallets[wallet_id]
if wallet.type() == WalletType.CAT:
@ -823,7 +824,7 @@ class WalletRpcApi:
"transaction_id": tx.name,
}
async def send_transaction_multi(self, request) -> Dict:
async def send_transaction_multi(self, request) -> EndpointResult:
if await self.service.wallet_state_manager.synced() is False:
raise ValueError("Wallet needs to be fully synced before sending transactions")
@ -838,7 +839,7 @@ class WalletRpcApi:
# Transaction may not have been included in the mempool yet. Use get_transaction to check.
return {"transaction": transaction, "transaction_id": tr.name}
async def delete_unconfirmed_transactions(self, request):
async def delete_unconfirmed_transactions(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
if wallet_id not in self.service.wallet_state_manager.wallets:
raise ValueError(f"Wallet id {wallet_id} does not exist")
@ -854,7 +855,7 @@ class WalletRpcApi:
await self.service.wallet_state_manager.tx_store.db_wrapper.commit_transaction()
return {}
async def select_coins(self, request) -> Dict[str, object]:
async def select_coins(self, request) -> EndpointResult:
if await self.service.wallet_state_manager.synced() is False:
raise ValueError("Wallet needs to be fully synced before selecting coins")
@ -871,22 +872,22 @@ class WalletRpcApi:
# CATs and Trading
##########################################################################################
async def get_cat_list(self, request):
async def get_cat_list(self, request) -> EndpointResult:
return {"cat_list": list(DEFAULT_CATS.values())}
async def cat_set_name(self, request):
wallet_id = int(request["wallet_id"])
async def cat_set_name(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: CATWallet = self.service.wallet_state_manager.wallets[wallet_id]
await wallet.set_name(str(request["name"]))
return {"wallet_id": wallet_id}
async def cat_get_name(self, request):
wallet_id = int(request["wallet_id"])
async def cat_get_name(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: CATWallet = self.service.wallet_state_manager.wallets[wallet_id]
name: str = await wallet.get_name()
return {"wallet_id": wallet_id, "name": name}
async def get_stray_cats(self, request):
async def get_stray_cats(self, request) -> EndpointResult:
"""
Get a list of all unacknowledged CATs
:param request: RPC request
@ -895,10 +896,10 @@ class WalletRpcApi:
cats = await self.service.wallet_state_manager.interested_store.get_unacknowledged_tokens()
return {"stray_cats": cats}
async def cat_spend(self, request):
async def cat_spend(self, request) -> EndpointResult:
if await self.service.wallet_state_manager.synced() is False:
raise ValueError("Wallet needs to be fully synced.")
wallet_id = int(request["wallet_id"])
wallet_id = uint32(request["wallet_id"])
wallet: CATWallet = self.service.wallet_state_manager.wallets[wallet_id]
puzzle_hash: bytes32 = decode_puzzle_hash(request["inner_address"])
@ -914,7 +915,7 @@ class WalletRpcApi:
else:
fee = uint64(0)
async with self.service.wallet_state_manager.lock:
txs: TransactionRecord = await wallet.generate_signed_transaction(
txs: List[TransactionRecord] = await wallet.generate_signed_transaction(
[amount], [puzzle_hash], fee, memos=[memos]
)
for tx in txs:
@ -925,13 +926,13 @@ class WalletRpcApi:
"transaction_id": tx.name,
}
async def cat_get_asset_id(self, request):
wallet_id = int(request["wallet_id"])
async def cat_get_asset_id(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: CATWallet = self.service.wallet_state_manager.wallets[wallet_id]
asset_id: str = wallet.get_asset_id()
return {"asset_id": asset_id, "wallet_id": wallet_id}
async def cat_asset_id_to_name(self, request):
async def cat_asset_id_to_name(self, request) -> EndpointResult:
wallet = await self.service.wallet_state_manager.get_wallet_for_asset_id(request["asset_id"])
if wallet is None:
if request["asset_id"] in DEFAULT_CATS:
@ -941,7 +942,7 @@ class WalletRpcApi:
else:
return {"wallet_id": wallet.id(), "name": (await wallet.get_name())}
async def create_offer_for_ids(self, request):
async def create_offer_for_ids(self, request) -> EndpointResult:
offer: Dict[str, int] = request["offer"]
fee: uint64 = uint64(request.get("fee", 0))
validate_only: bool = request.get("validate_only", False)
@ -962,7 +963,7 @@ class WalletRpcApi:
for key, value in driver_dict_str.items():
driver_dict[bytes32.from_hexstr(key)] = PuzzleInfo(value)
modified_offer = {}
modified_offer: Dict[Union[int, bytes32], int] = {}
for key in offer:
try:
modified_offer[bytes32.from_hexstr(key)] = offer[key]
@ -970,21 +971,18 @@ class WalletRpcApi:
modified_offer[int(key)] = offer[key]
async with self.service.wallet_state_manager.lock:
(
success,
trade_record,
error,
) = await self.service.wallet_state_manager.trade_manager.create_offer_for_ids(
modified_offer, driver_dict, request.get("solver", {}), fee=fee, validate_only=validate_only
result = await self.service.wallet_state_manager.trade_manager.create_offer_for_ids(
modified_offer, driver_dict, fee=fee, validate_only=validate_only
)
if success:
if result[0]:
success, trade_record, error = result
return {
"offer": Offer.from_bytes(trade_record.offer).to_bech32(),
"trade_record": trade_record.to_json_dict_convenience(),
}
raise ValueError(error)
raise ValueError(result[2])
async def get_offer_summary(self, request):
async def get_offer_summary(self, request) -> EndpointResult:
offer_hex: str = request["offer"]
offer = Offer.from_bech32(offer_hex)
offered, requested, infos = offer.summary()
@ -996,26 +994,25 @@ class WalletRpcApi:
else:
return {"summary": await self.service.wallet_state_manager.trade_manager.get_offer_summary(offer)}
async def check_offer_validity(self, request):
async def check_offer_validity(self, request) -> EndpointResult:
offer_hex: str = request["offer"]
offer = Offer.from_bech32(offer_hex)
return {"valid": (await self.service.wallet_state_manager.trade_manager.check_offer_validity(offer))}
async def take_offer(self, request):
async def take_offer(self, request) -> EndpointResult:
offer_hex: str = request["offer"]
offer = Offer.from_bech32(offer_hex)
fee: uint64 = uint64(request.get("fee", 0))
async with self.service.wallet_state_manager.lock:
(success, trade_record, error,) = await self.service.wallet_state_manager.trade_manager.respond_to_offer(
offer, request.get("solver", {}), fee=fee
)
if not success:
raise ValueError(error)
result = await self.service.wallet_state_manager.trade_manager.respond_to_offer(offer, fee=fee)
if not result[0]:
raise ValueError(result[2])
success, trade_record, error = result
return {"trade_record": trade_record.to_json_dict_convenience()}
async def get_offer(self, request: Dict):
async def get_offer(self, request: Dict) -> EndpointResult:
trade_mgr = self.service.wallet_state_manager.trade_manager
trade_id = bytes32.from_hexstr(request["trade_id"])
@ -1028,7 +1025,7 @@ class WalletRpcApi:
offer_value: Optional[str] = Offer.from_bytes(offer_to_return).to_bech32() if file_contents else None
return {"trade_record": trade_record.to_json_dict_convenience(), "offer": offer_value}
async def get_all_offers(self, request: Dict):
async def get_all_offers(self, request: Dict) -> EndpointResult:
trade_mgr = self.service.wallet_state_manager.trade_manager
start: int = request.get("start", 0)
@ -1059,14 +1056,14 @@ class WalletRpcApi:
return {"trade_records": result, "offers": offer_values}
async def get_offers_count(self, request: Dict):
async def get_offers_count(self, request: Dict) -> EndpointResult:
trade_mgr = self.service.wallet_state_manager.trade_manager
(total, my_offers_count, taken_offers_count) = await trade_mgr.trade_store.get_trades_count()
return {"total": total, "my_offers_count": my_offers_count, "taken_offers_count": taken_offers_count}
async def cancel_offer(self, request: Dict):
async def cancel_offer(self, request: Dict) -> EndpointResult:
wsm = self.service.wallet_state_manager
secure = request["secure"]
trade_id = bytes32.from_hexstr(request["trade_id"])
@ -1083,7 +1080,7 @@ class WalletRpcApi:
# Distributed Identities
##########################################################################################
async def did_set_wallet_name(self, request):
async def did_set_wallet_name(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
if wallet.type() == WalletType.DECENTRALIZED_ID:
@ -1092,13 +1089,13 @@ class WalletRpcApi:
else:
return {"success": False, "error": f"Wallet id {wallet_id} is not a DID wallet"}
async def did_get_wallet_name(self, request):
async def did_get_wallet_name(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
name: str = await wallet.get_name()
return {"success": True, "wallet_id": wallet_id, "name": name}
async def did_update_recovery_ids(self, request):
async def did_update_recovery_ids(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
recovery_list = []
@ -1108,7 +1105,7 @@ class WalletRpcApi:
if "num_verifications_required" in request:
new_amount_verifications_required = uint64(request["num_verifications_required"])
else:
new_amount_verifications_required = len(recovery_list)
new_amount_verifications_required = uint64(len(recovery_list))
async with self.service.wallet_state_manager.lock:
update_success = await wallet.update_recovery_list(recovery_list, new_amount_verifications_required)
# Update coin with new ID info
@ -1118,7 +1115,7 @@ class WalletRpcApi:
success = True
return {"success": success}
async def did_update_metadata(self, request):
async def did_update_metadata(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
if wallet.type() != WalletType.DECENTRALIZED_ID.value:
@ -1138,7 +1135,7 @@ class WalletRpcApi:
else:
return {"success": False, "error": f"Couldn't update metadata with input: {metadata}"}
async def did_get_did(self, request):
async def did_get_did(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
my_did: str = encode_puzzle_hash(bytes32.fromhex(wallet.get_my_DID()), DID_HRP)
@ -1150,7 +1147,7 @@ class WalletRpcApi:
coin = coins.pop()
return {"success": True, "wallet_id": wallet_id, "my_did": my_did, "coin_id": coin.name()}
async def did_get_recovery_list(self, request):
async def did_get_recovery_list(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
recovery_list = wallet.did_info.backup_ids
@ -1164,7 +1161,7 @@ class WalletRpcApi:
"num_required": wallet.did_info.num_of_backup_ids_needed,
}
async def did_get_metadata(self, request):
async def did_get_metadata(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
metadata = json.loads(wallet.did_info.metadata)
@ -1174,7 +1171,7 @@ class WalletRpcApi:
"metadata": metadata,
}
async def did_recovery_spend(self, request):
async def did_recovery_spend(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
if len(request["attest_data"]) < wallet.did_info.num_of_backup_ids_needed:
@ -1193,13 +1190,14 @@ class WalletRpcApi:
pubkey = wallet.did_info.temp_pubkey
if "puzhash" in request:
puzhash = hexstr_to_bytes(request["puzhash"])
puzhash = bytes32.from_hexstr(request["puzhash"])
else:
assert wallet.did_info.temp_puzhash is not None
puzhash = wallet.did_info.temp_puzhash
# TODO: this ignore should be dealt with
spend_bundle = await wallet.recovery_spend(
wallet.did_info.temp_coin,
wallet.did_info.temp_coin, # type: ignore[arg-type]
puzhash,
info_list,
pubkey,
@ -1210,13 +1208,13 @@ class WalletRpcApi:
else:
return {"success": False}
async def did_get_pubkey(self, request):
async def did_get_pubkey(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
pubkey = bytes((await wallet.wallet_state_manager.get_unused_derivation_record(wallet_id)).pubkey).hex()
return {"success": True, "pubkey": pubkey}
async def did_create_attest(self, request):
async def did_create_attest(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
async with self.service.wallet_state_manager.lock:
@ -1238,11 +1236,12 @@ class WalletRpcApi:
else:
return {"success": False}
async def did_get_information_needed_for_recovery(self, request):
async def did_get_information_needed_for_recovery(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
did_wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
my_did = encode_puzzle_hash(bytes32.from_hexstr(did_wallet.get_my_DID()), DID_HRP)
coin_name = did_wallet.did_info.temp_coin.name().hex()
# TODO: this ignore should be dealt with
coin_name = did_wallet.did_info.temp_coin.name().hex() # type: ignore[union-attr]
return {
"success": True,
"wallet_id": wallet_id,
@ -1253,7 +1252,7 @@ class WalletRpcApi:
"backup_dids": did_wallet.did_info.backup_ids,
}
async def did_get_current_coin_info(self, request):
async def did_get_current_coin_info(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
did_wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
my_did = encode_puzzle_hash(bytes32.from_hexstr(did_wallet.get_my_DID()), DID_HRP)
@ -1269,12 +1268,12 @@ class WalletRpcApi:
"did_amount": did_coin_threeple[2],
}
async def did_create_backup_file(self, request):
async def did_create_backup_file(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
did_wallet: DIDWallet = self.service.wallet_state_manager.wallets[wallet_id]
return {"wallet_id": wallet_id, "success": True, "backup_data": did_wallet.create_backup()}
async def did_transfer_did(self, request):
async def did_transfer_did(self, request) -> EndpointResult:
if await self.service.wallet_state_manager.synced() is False:
raise ValueError("Wallet needs to be fully synced.")
wallet_id = uint32(request["wallet_id"])
@ -1295,7 +1294,7 @@ class WalletRpcApi:
# NFT Wallet
##########################################################################################
async def nft_mint_nft(self, request) -> Dict:
async def nft_mint_nft(self, request) -> EndpointResult:
log.debug("Got minting RPC request: %s", request)
wallet_id = uint32(request["wallet_id"])
assert self.service.wallet_state_manager
@ -1354,7 +1353,7 @@ class WalletRpcApi:
)
return {"wallet_id": wallet_id, "success": True, "spend_bundle": spend_bundle}
async def nft_get_nfts(self, request) -> Dict:
async def nft_get_nfts(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
nft_wallet: NFTWallet = self.service.wallet_state_manager.wallets[wallet_id]
nfts = nft_wallet.get_current_nfts()
@ -1382,7 +1381,7 @@ class WalletRpcApi:
log.exception(f"Failed to set DID on NFT: {e}")
return {"success": False, "error": f"Failed to set DID on NFT: {e}"}
async def nft_get_by_did(self, request) -> Dict:
async def nft_get_by_did(self, request) -> EndpointResult:
did_id: Optional[bytes32] = None
if "did_id" in request:
did_id = decode_puzzle_hash(request["did_id"])
@ -1391,7 +1390,7 @@ class WalletRpcApi:
return {"wallet_id": wallet.wallet_id, "success": True}
return {"error": f"Cannot find a NFT wallet DID = {did_id}", "success": False}
async def nft_get_wallet_did(self, request) -> Dict:
async def nft_get_wallet_did(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
nft_wallet: NFTWallet = self.service.wallet_state_manager.wallets[wallet_id]
if nft_wallet is not None:
@ -1404,7 +1403,7 @@ class WalletRpcApi:
return {"success": True, "did_id": None if len(did_id) == 0 else did_id}
return {"success": False, "error": f"Wallet {wallet_id} not found"}
async def nft_get_wallets_with_dids(self, request) -> Dict:
async def nft_get_wallets_with_dids(self, request) -> EndpointResult:
all_wallets = self.service.wallet_state_manager.wallets.values()
did_wallets_by_did_id: Dict[bytes32, uint32] = {
wallet.did_info.origin_coin.name(): wallet.id()
@ -1429,7 +1428,7 @@ class WalletRpcApi:
)
return {"success": True, "nft_wallets": did_nft_wallets}
async def nft_set_nft_status(self, request) -> Dict:
async def nft_set_nft_status(self, request) -> EndpointResult:
try:
wallet_id: uint32 = uint32(request["wallet_id"])
coin_id: bytes32 = bytes32.from_hexstr(request["coin_id"])
@ -1443,7 +1442,7 @@ class WalletRpcApi:
except Exception as e:
return {"success": False, "error": f"Cannot change the status of the NFT.{e}"}
async def nft_transfer_nft(self, request):
async def nft_transfer_nft(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
address = request["target_address"]
if isinstance(address, str):
@ -1478,7 +1477,7 @@ class WalletRpcApi:
log.exception(f"Failed to transfer NFT: {e}")
return {"success": False, "error": str(e)}
async def nft_get_info(self, request: Dict) -> Dict[str, object]:
async def nft_get_info(self, request: Dict) -> EndpointResult:
if "coin_id" not in request:
return {"success": False, "error": "Coin ID is required."}
coin_id = request["coin_id"]
@ -1486,13 +1485,8 @@ class WalletRpcApi:
coin_id = decode_puzzle_hash(coin_id)
else:
coin_id = bytes32.from_hexstr(coin_id)
peer = self.service.wallet_state_manager.wallet_node.get_full_node_peer()
if peer is None:
return {"success": False, "error": "Cannot find a full node peer."}
# Get coin state
coin_state_list: List[CoinState] = await self.service.wallet_state_manager.wallet_node.get_coin_state(
[coin_id], peer=peer
)
coin_state_list: List[CoinState] = await self.service.wallet_state_manager.wallet_node.get_coin_state([coin_id])
if coin_state_list is None or len(coin_state_list) < 1:
return {"success": False, "error": f"Coin record 0x{coin_id.hex()} not found"}
coin_state: CoinState = coin_state_list[0]
@ -1500,7 +1494,7 @@ class WalletRpcApi:
# Find the unspent coin
while coin_state.spent_height is not None:
coin_state_list = await self.service.wallet_state_manager.wallet_node.fetch_children(
peer, coin_state.coin.name()
coin_state.coin.name()
)
odd_coin = 0
for coin in coin_state_list:
@ -1513,7 +1507,7 @@ class WalletRpcApi:
coin_state = coin_state_list[0]
# Get parent coin
parent_coin_state_list: List[CoinState] = await self.service.wallet_state_manager.wallet_node.get_coin_state(
[coin_state.coin.parent_coin_info], peer=peer
[coin_state.coin.parent_coin_info]
)
if parent_coin_state_list is None or len(parent_coin_state_list) < 1:
return {
@ -1522,7 +1516,7 @@ class WalletRpcApi:
}
parent_coin_state: CoinState = parent_coin_state_list[0]
coin_spend: CoinSpend = await self.service.wallet_state_manager.wallet_node.fetch_puzzle_solution(
peer, parent_coin_state.spent_height, parent_coin_state.coin
parent_coin_state.spent_height, parent_coin_state.coin
)
# convert to NFTInfo
try:
@ -1549,7 +1543,7 @@ class WalletRpcApi:
# Get launcher coin
launcher_coin: List[CoinState] = await self.service.wallet_state_manager.wallet_node.get_coin_state(
[uncurried_nft.singleton_launcher_id], peer=peer
[uncurried_nft.singleton_launcher_id]
)
if launcher_coin is None or len(launcher_coin) < 1 or launcher_coin[0].spent_height is None:
return {
@ -1570,7 +1564,7 @@ class WalletRpcApi:
else:
return {"success": True, "nft_info": nft_info}
async def nft_add_uri(self, request) -> Dict:
async def nft_add_uri(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
# Note metadata updater can only add one uri for one field per spend.
# If you want to add multiple uris for one field, you need to spend multiple times.
@ -1595,7 +1589,7 @@ class WalletRpcApi:
# Rate Limited Wallet
##########################################################################################
async def rl_set_user_info(self, request):
async def rl_set_user_info(self, request) -> EndpointResult:
wallet_id = uint32(int(request["wallet_id"]))
rl_user = self.service.wallet_state_manager.wallets[wallet_id]
origin = request["origin"]
@ -1610,8 +1604,8 @@ class WalletRpcApi:
)
return {}
async def send_clawback_transaction(self, request):
wallet_id = int(request["wallet_id"])
async def send_clawback_transaction(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: RLWallet = self.service.wallet_state_manager.wallets[wallet_id]
fee = int(request["fee"])
@ -1625,7 +1619,7 @@ class WalletRpcApi:
"transaction_id": tx.name,
}
async def add_rate_limited_funds(self, request):
async def add_rate_limited_funds(self, request) -> EndpointResult:
wallet_id = uint32(request["wallet_id"])
wallet: RLWallet = self.service.wallet_state_manager.wallets[wallet_id]
puzzle_hash = wallet.rl_get_aggregation_puzzlehash(wallet.rl_info.rl_puzzle_hash)
@ -1633,7 +1627,7 @@ class WalletRpcApi:
await wallet.rl_add_funds(request["amount"], puzzle_hash, request["fee"])
return {"status": "SUCCESS"}
async def get_farmed_amount(self, request):
async def get_farmed_amount(self, request) -> EndpointResult:
tx_records: List[TransactionRecord] = await self.service.wallet_state_manager.tx_store.get_farming_rewards()
amount = 0
pool_reward_amount = 0
@ -1649,6 +1643,11 @@ class WalletRpcApi:
continue
pool_reward_amount += record.amount
height = record.height_farmed(self.service.constants.GENESIS_CHALLENGE)
# .get_farming_rewards() above queries for only confirmed records. This
# could be hinted by making TransactionRecord generic but streamable can't
# handle that presently. Existing code would have raised an exception
# anyways if this were to fail and we already have an assert below.
assert height is not None
if record.type == TransactionType.FEE_REWARD:
fee_amount += record.amount - calculate_base_farmer_reward(height)
farmer_reward_amount += calculate_base_farmer_reward(height)
@ -1665,7 +1664,7 @@ class WalletRpcApi:
"last_height_farmed": last_height_farmed,
}
async def create_signed_transaction(self, request, hold_lock=True) -> Dict:
async def create_signed_transaction(self, request, hold_lock=True) -> EndpointResult:
if "additions" not in request or len(request["additions"]) < 1:
raise ValueError("Specify additions list")
@ -1761,7 +1760,7 @@ class WalletRpcApi:
##########################################################################################
# Pool Wallet
##########################################################################################
async def pw_join_pool(self, request) -> Dict:
async def pw_join_pool(self, request) -> EndpointResult:
fee = uint64(request.get("fee", 0))
wallet_id = uint32(request["wallet_id"])
wallet: PoolWallet = self.service.wallet_state_manager.wallets[wallet_id]
@ -1789,7 +1788,7 @@ class WalletRpcApi:
total_fee, tx, fee_tx = await wallet.join_pool(new_target_state, fee)
return {"total_fee": total_fee, "transaction": tx, "fee_transaction": fee_tx}
async def pw_self_pool(self, request) -> Dict:
async def pw_self_pool(self, request) -> EndpointResult:
# Leaving a pool requires two state transitions.
# First we transition to PoolSingletonState.LEAVING_POOL
# Then we transition to FARMING_TO_POOL or SELF_POOLING
@ -1806,7 +1805,7 @@ class WalletRpcApi:
total_fee, tx, fee_tx = await wallet.self_pool(fee)
return {"total_fee": total_fee, "transaction": tx, "fee_transaction": fee_tx}
async def pw_absorb_rewards(self, request) -> Dict:
async def pw_absorb_rewards(self, request) -> EndpointResult:
"""Perform a sweep of the p2_singleton rewards controlled by the pool wallet singleton"""
if await self.service.wallet_state_manager.synced() is False:
raise ValueError("Wallet needs to be fully synced before collecting rewards")
@ -1822,7 +1821,7 @@ class WalletRpcApi:
state: PoolWalletInfo = await wallet.get_current_state()
return {"state": state.to_json_dict(), "transaction": transaction, "fee_transaction": fee_tx}
async def pw_status(self, request) -> Dict:
async def pw_status(self, request) -> EndpointResult:
"""Return the complete state of the Pool wallet with id `request["wallet_id"]`"""
wallet_id = uint32(request["wallet_id"])
wallet: PoolWallet = self.service.wallet_state_manager.wallets[wallet_id]

View File

@ -16,7 +16,7 @@ from chia.util.default_root import DEFAULT_ROOT_PATH
# See: https://bugs.python.org/issue29288
"".encode("idna")
SERVICE_NAME = "full_node"
SERVICE_NAME = "seeder"
log = logging.getLogger(__name__)
@ -51,7 +51,7 @@ def service_kwargs_for_full_node_crawler(
def main():
config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", "seeder")
config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME)
overrides = config["network_overrides"]["constants"][config["selected_network"]]
updated_constants = DEFAULT_CONSTANTS.replace_str_to_bytes(**overrides)
kwargs = service_kwargs_for_full_node_crawler(DEFAULT_ROOT_PATH, config, updated_constants)

View File

@ -53,8 +53,6 @@ class Service:
rpc_info: Optional[Tuple[type, int]] = None,
parse_cli_args=True,
connect_to_daemon=True,
running_new_process=True,
service_name_prefix="",
max_request_body_size: Optional[int] = None,
override_capabilities: Optional[List[Tuple[uint16, str]]] = None,
) -> None:
@ -71,24 +69,13 @@ class Service:
self._rpc_close_task: Optional[asyncio.Task] = None
self._network_id: str = network_id
self.max_request_body_size = max_request_body_size
self._running_new_process = running_new_process
# when we start this service as a component of an existing process,
# don't change its proctitle
if running_new_process:
proctitle_name = f"chia_{service_name_prefix}{service_name}"
setproctitle(proctitle_name)
self._log = logging.getLogger(service_name)
if parse_cli_args:
service_config = load_config_cli(root_path, "config.yaml", service_name)
self.service_config = load_config_cli(root_path, "config.yaml", service_name)
else:
service_config = load_config(root_path, "config.yaml", service_name)
# only initialize logging once per process
if running_new_process:
initialize_logging(service_name, service_config["logging"], root_path)
self.service_config = load_config(root_path, "config.yaml", service_name)
self._rpc_info = rpc_info
private_ca_crt, private_ca_key = private_ssl_ca_paths(root_path, self.config)
@ -96,7 +83,7 @@ class Service:
inbound_rlp = self.config.get("inbound_rate_limit_percent")
outbound_rlp = self.config.get("outbound_rate_limit_percent")
if node_type == NodeType.WALLET:
inbound_rlp = service_config.get("inbound_rate_limit_percent", inbound_rlp)
inbound_rlp = self.service_config.get("inbound_rate_limit_percent", inbound_rlp)
outbound_rlp = 60
capabilities_to_use: List[Tuple[uint16, str]] = capabilities
if override_capabilities is not None:
@ -114,7 +101,7 @@ class Service:
outbound_rlp,
capabilities_to_use,
root_path,
service_config,
self.service_config,
(private_ca_crt, private_ca_key),
(chia_ca_crt, chia_ca_key),
name=f"{service_name}_server",
@ -154,9 +141,6 @@ class Service:
self._did_start = True
if self._running_new_process:
self._enable_signals()
await self._node._start(**kwargs)
self._node._shut_down = False
@ -201,7 +185,12 @@ class Service:
await self.start()
await self.wait_closed()
def _enable_signals(self) -> None:
async def setup_process_global_state(self) -> None:
# Being async forces this to be run from within an active event loop as is
# needed for the signal handler setup.
proctitle_name = f"chia_{self._service_name}"
setproctitle(proctitle_name)
initialize_logging(self._service_name, self.service_config["logging"], self.root_path)
global main_pid
main_pid = os.getpid()
@ -288,6 +277,7 @@ class Service:
async def async_run_service(*args, **kwargs) -> None:
service = Service(*args, **kwargs)
await service.setup_process_global_state()
return await service.run()

View File

@ -1,7 +1,7 @@
from typing import Dict
from chia.rpc.full_node_rpc_api import FullNodeRpcApi
from chia.rpc.rpc_server import Endpoint
from chia.rpc.rpc_server import Endpoint, EndpointResult
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
from chia.util.bech32m import decode_puzzle_hash
@ -12,7 +12,7 @@ class SimulatorFullNodeRpcApi(FullNodeRpcApi):
routes["/farm_tx_block"] = self.farm_tx_block
return routes
async def farm_tx_block(self, _request: Dict[str, object]) -> Dict[str, object]:
async def farm_tx_block(self, _request: Dict[str, object]) -> EndpointResult:
request_address = str(_request["address"])
ph = decode_puzzle_hash(request_address)
req = FarmNewBlockProtocol(ph)

View File

@ -8,7 +8,7 @@ from blspy import AugSchemeMPL, G2Element
from chia.consensus.default_constants import DEFAULT_CONSTANTS
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.streamable import Streamable, dataclass_from_dict, recurse_jsonify, streamable
from chia.util.streamable import Streamable, streamable_from_dict, recurse_jsonify, streamable
from chia.wallet.util.debug_spend_bundle import debug_spend_bundle
from .coin_spend import CoinSpend
@ -95,7 +95,7 @@ class SpendBundle(Streamable):
warnings.warn("`coin_solutions` is now `coin_spends` in `SpendBundle.from_json_dict`")
else:
raise ValueError("JSON contains both `coin_solutions` and `coin_spends`, just use `coin_spends`")
return dataclass_from_dict(cls, json_dict)
return streamable_from_dict(cls, json_dict)
def to_json_dict(self, include_legacy_keys: bool = True, exclude_modern_keys: bool = True):
if include_legacy_keys is False and exclude_modern_keys is True:

View File

@ -50,7 +50,7 @@ def get_os_passphrase_store() -> Optional[OSPassphraseStore]:
def check_legacy_keyring_keys_present(keyring: LegacyKeyring) -> bool:
from keyring.credentials import SimpleCredential
from keyring.credentials import Credential
from chia.util.keychain import default_keychain_user, default_keychain_service, get_private_key_user, MAX_KEYS
keychain_user: str = default_keychain_user()
@ -58,7 +58,7 @@ def check_legacy_keyring_keys_present(keyring: LegacyKeyring) -> bool:
for index in range(0, MAX_KEYS):
current_user: str = get_private_key_user(keychain_user, index)
credential: Optional[SimpleCredential] = keyring.get_credential(keychain_service, current_user)
credential: Optional[Credential] = keyring.get_credential(keychain_service, current_user)
if credential is not None:
return True
return False

View File

@ -169,7 +169,7 @@ def convert_primitive(f_type: Type[Any], item: Any) -> Any:
raise TypeError(f"Can't convert type {type(item).__name__} to {f_type.__name__}: {e}") from e
def dataclass_from_dict(klass: Type[Any], item: Any) -> Any:
def streamable_from_dict(klass: Type[_T_Streamable], item: Any) -> _T_Streamable:
"""
Converts a dictionary based on a dataclass, into an instance of that dataclass.
Recursively goes through lists, optionals, and dictionaries.
@ -179,22 +179,12 @@ def dataclass_from_dict(klass: Type[Any], item: Any) -> Any:
if not isinstance(item, dict):
raise TypeError(f"expected: dict, actual: {type(item).__name__}")
if klass not in CONVERT_FUNCTIONS_FOR_STREAMABLE_CLASS:
# For non-streamable dataclasses we can't populate the cache on startup, so we do it here for convert
# functions only.
fields = create_fields_cache(klass)
convert_funcs = [function_to_convert_one_item(field.type) for field in fields]
FIELDS_FOR_STREAMABLE_CLASS[klass] = fields
CONVERT_FUNCTIONS_FOR_STREAMABLE_CLASS[klass] = convert_funcs
else:
fields = FIELDS_FOR_STREAMABLE_CLASS[klass]
convert_funcs = CONVERT_FUNCTIONS_FOR_STREAMABLE_CLASS[klass]
fields = FIELDS_FOR_STREAMABLE_CLASS[klass]
try:
return klass(
**{
field.name: convert_func(item[field.name])
for field, convert_func in zip(fields, convert_funcs)
for field, convert_func in zip(fields, CONVERT_FUNCTIONS_FOR_STREAMABLE_CLASS[klass])
if field.name in item
}
)
@ -224,9 +214,6 @@ def function_to_convert_one_item(f_type: Type[Any]) -> ConvertFunctionType:
convert_inner_func = function_to_convert_one_item(inner_type)
# Ignoring for now as the proper solution isn't obvious
return lambda items: convert_list(convert_inner_func, items) # type: ignore[arg-type]
elif dataclasses.is_dataclass(f_type):
# Type is a dataclass, data is a dictionary
return lambda item: dataclass_from_dict(f_type, item)
elif hasattr(f_type, "from_json_dict"):
return lambda item: f_type.from_json_dict(item)
elif issubclass(f_type, bytes):
@ -645,7 +632,7 @@ class Streamable:
stream_func(getattr(self, field.name), f)
def get_hash(self) -> bytes32:
return bytes32(std_hash(bytes(self), skip_bytes_conversion=True))
return std_hash(bytes(self), skip_bytes_conversion=True)
@classmethod
def from_bytes(cls: Any, blob: bytes) -> Any:
@ -670,5 +657,5 @@ class Streamable:
return ret
@classmethod
def from_json_dict(cls: Any, json_dict: Dict[str, Any]) -> Any:
return dataclass_from_dict(cls, json_dict)
def from_json_dict(cls: Type[_T_Streamable], json_dict: Dict[str, Any]) -> _T_Streamable:
return streamable_from_dict(cls, json_dict)

View File

@ -335,22 +335,15 @@ class CATWallet:
lineage = await self.get_lineage_proof_for_coin(coin)
if lineage is None:
for node_id, node in self.wallet_state_manager.wallet_node.server.all_connections.items():
try:
coin_state = await self.wallet_state_manager.wallet_node.get_coin_state(
[coin.parent_coin_info], None, node
)
# check for empty list and continue on to next node
if not coin_state:
continue
assert coin_state[0].coin.name() == coin.parent_coin_info
coin_spend = await self.wallet_state_manager.wallet_node.fetch_puzzle_solution(
node, coin_state[0].spent_height, coin_state[0].coin
)
await self.puzzle_solution_received(coin_spend, parent_coin=coin_state[0].coin)
break
except Exception as e:
self.log.debug(f"Exception: {e}, traceback: {traceback.format_exc()}")
try:
coin_state = await self.wallet_state_manager.wallet_node.get_coin_state([coin.parent_coin_info])
assert coin_state[0].coin.name() == coin.parent_coin_info
coin_spend = await self.wallet_state_manager.wallet_node.fetch_puzzle_solution(
coin_state[0].spent_height, coin_state[0].coin
)
await self.puzzle_solution_received(coin_spend, parent_coin=coin_state[0].coin)
except Exception as e:
self.log.debug(f"Exception: {e}, traceback: {traceback.format_exc()}")
async def puzzle_solution_received(self, coin_spend: CoinSpend, parent_coin: Coin):
coin_name = coin_spend.coin.name()

View File

@ -434,22 +434,21 @@ class DIDWallet:
did_info.origin_coin.name(),
did_wallet_puzzles.metadata_to_program(json.loads(self.did_info.metadata)),
)
node = self.wallet_state_manager.wallet_node.get_full_node_peer()
children = await self.wallet_state_manager.wallet_node.fetch_children(node, did_info.origin_coin.name())
wallet_node = self.wallet_state_manager.wallet_node
parent_coin: Coin = did_info.origin_coin
while True:
children = await wallet_node.fetch_children(parent_coin.name())
if len(children) == 0:
break
children_state: CoinState = children[0]
coin = children_state.coin
name = coin.name()
children = await self.wallet_state_manager.wallet_node.fetch_children(node, name)
child_coin = children_state.coin
future_parent = LineageProof(
coin.parent_coin_info,
child_coin.parent_coin_info,
did_info.current_inner.get_tree_hash(),
uint64(coin.amount),
uint64(child_coin.amount),
)
await self.add_parent(coin.name(), future_parent, True)
await self.add_parent(child_coin.name(), future_parent, True)
if children_state.spent_height != children_state.created_height:
did_info = DIDInfo(
did_info.origin_coin,
@ -457,7 +456,7 @@ class DIDWallet:
did_info.num_of_backup_ids_needed,
self.did_info.parent_info,
did_info.current_inner,
coin,
child_coin,
new_did_inner_puzhash,
new_pubkey,
False,
@ -466,23 +465,19 @@ class DIDWallet:
await self.save_info(did_info, True)
assert children_state.created_height
puzzle_solution_request = wallet_protocol.RequestPuzzleSolution(
coin.parent_coin_info, children_state.created_height
parent_spend = await wallet_node.fetch_puzzle_solution(children_state.created_height, parent_coin)
assert parent_spend is not None
parent_innerpuz = did_wallet_puzzles.get_innerpuzzle_from_puzzle(
parent_spend.puzzle_reveal.to_program()
)
parent_state: CoinState = (
await self.wallet_state_manager.wallet_node.get_coin_state([coin.parent_coin_info])
)[0]
response = await node.request_puzzle_solution(puzzle_solution_request)
req_puz_sol = response.response
assert req_puz_sol.puzzle is not None
parent_innerpuz = did_wallet_puzzles.get_innerpuzzle_from_puzzle(req_puz_sol.puzzle.to_program())
assert parent_innerpuz is not None
parent_info = LineageProof(
parent_state.coin.parent_coin_info,
parent_coin.parent_coin_info,
parent_innerpuz.get_tree_hash(),
uint64(parent_state.coin.amount),
uint64(parent_coin.amount),
)
await self.add_parent(coin.parent_coin_info, parent_info, True)
await self.add_parent(child_coin.parent_coin_info, parent_info, True)
parent_coin = child_coin
assert parent_info is not None
async def create_tandem_xch_tx(

View File

@ -7,8 +7,6 @@ from typing import Any, Dict, List, Optional, Set, Tuple, Type, TypeVar
from blspy import AugSchemeMPL, G2Element
from chia.protocols.wallet_protocol import CoinState
from chia.server.outbound_message import NodeType
from chia.server.ws_connection import WSChiaConnection
from chia.types.announcement import Announcement
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.program import Program
@ -158,22 +156,14 @@ class NFTWallet:
if coin_info.coin == coin:
return
wallet_node = self.wallet_state_manager.wallet_node
server = wallet_node.server
full_nodes: Dict[bytes32, WSChiaConnection] = server.connection_by_type.get(NodeType.FULL_NODE, {})
cs: Optional[CoinSpend] = None
coin_states: Optional[List[CoinState]] = await self.wallet_state_manager.wallet_node.get_coin_state(
[coin.parent_coin_info]
)
coin_states: Optional[List[CoinState]] = await wallet_node.get_coin_state([coin.parent_coin_info])
if not coin_states:
# farm coin
return
assert coin_states
parent_coin = coin_states[0].coin
for node_id in full_nodes:
node = server.all_connections[node_id]
cs = await wallet_node.fetch_puzzle_solution(node, height, parent_coin)
if cs is not None:
break
cs = await wallet_node.fetch_puzzle_solution(height, parent_coin)
assert cs is not None
await self.puzzle_solution_received(cs, in_transaction=in_transaction)

View File

@ -3,6 +3,7 @@ import logging
import time
import traceback
from typing import Any, Dict, List, Optional, Set, Tuple, Union
from typing_extensions import Literal
from chia.data_layer.data_layer_wallet import DataLayerWallet
from chia.protocols.wallet_protocol import CoinState
@ -299,10 +300,12 @@ class TradeManager:
solver: Solver = Solver({}),
fee: uint64 = uint64(0),
validate_only: bool = False,
) -> Tuple[bool, Optional[TradeRecord], Optional[str]]:
success, created_offer, error = await self._create_offer_for_ids(offer, driver_dict, solver, fee=fee)
if not success or created_offer is None:
raise Exception(f"Error creating offer: {error}")
) -> Union[Tuple[Literal[True], TradeRecord, None], Tuple[Literal[False], None, str]]:
result = await self._create_offer_for_ids(offer, driver_dict, solver, fee=fee)
if not result[0] or result[1] is None:
raise Exception(f"Error creating offer: {result[2]}")
success, created_offer, error = result
now = uint64(int(time.time()))
trade_offer: TradeRecord = TradeRecord(
@ -330,7 +333,7 @@ class TradeManager:
driver_dict: Dict[bytes32, PuzzleInfo] = {},
solver: Solver = Solver({}),
fee: uint64 = uint64(0),
) -> Tuple[bool, Optional[Offer], Optional[str]]:
) -> Union[Tuple[Literal[True], Offer, None], Tuple[Literal[False], None, str]]:
"""
Offer is dictionary of wallet ids and amount
"""
@ -587,7 +590,7 @@ class TradeManager:
offer: Offer,
solver: Solver = Solver({}),
fee=uint64(0),
) -> Tuple[bool, Optional[TradeRecord], Optional[str]]:
) -> Union[Tuple[Literal[True], TradeRecord, None], Tuple[Literal[False], None, str]]:
take_offer_dict: Dict[Union[bytes32, int], int] = {}
arbitrage: Dict[Optional[bytes32], int] = offer.arbitrage()
@ -610,11 +613,13 @@ class TradeManager:
valid: bool = await self.check_offer_validity(offer)
if not valid:
return False, None, "This offer is no longer valid"
success, take_offer, error = await self._create_offer_for_ids(
result = await self._create_offer_for_ids(
take_offer_dict, offer.driver_dict, solver, fee=fee
)
if not success or take_offer is None:
return False, None, error
if not result[0] or result[1] is None:
return False, None, result[2]
success, take_offer, error = result
complete_offer = await self.check_for_final_modifications(Offer.aggregate([offer, take_offer]), solver)
assert complete_offer.is_valid()

View File

@ -45,6 +45,8 @@ class TransactionRecord(Streamable):
sent_to: List[Tuple[str, uint8, Optional[str]]]
trade_id: Optional[bytes32]
type: uint32 # TransactionType
# name is also called bundle_id and tx_id
name: bytes32
memos: List[Tuple[bytes32, List[bytes]]]

View File

@ -2,8 +2,8 @@ import enum
class SortKey(enum.Enum):
CONFIRMED_AT_HEIGHT = "order by confirmed_at_height {ASC}"
RELEVANCE = "order by confirmed {ASC}, confirmed_at_height {DESC}, created_at_time {DESC}"
CONFIRMED_AT_HEIGHT = "ORDER BY confirmed_at_height {ASC}"
RELEVANCE = "ORDER BY confirmed {ASC}, confirmed_at_height {DESC}, created_at_time {DESC}"
def ascending(self) -> str:
return self.value.format(ASC="ASC", DESC="DESC")

View File

@ -26,9 +26,7 @@ from chia.protocols.full_node_protocol import RequestProofOfWeight, RespondProof
from chia.protocols.protocol_message_types import ProtocolMessageTypes
from chia.protocols.wallet_protocol import (
CoinState,
RequestSESInfo,
RespondBlockHeader,
RespondSESInfo,
RespondToCoinUpdates,
RespondToPhUpdates,
)
@ -44,7 +42,7 @@ from chia.types.coin_spend import CoinSpend
from chia.types.header_block import HeaderBlock
from chia.types.mempool_inclusion_status import MempoolInclusionStatus
from chia.types.peer_info import PeerInfo
from chia.types.weight_proof import SubEpochData, WeightProof
from chia.types.weight_proof import WeightProof
from chia.util.byte_types import hexstr_to_bytes
from chia.util.chunks import chunks
from chia.util.config import WALLET_PEERS_PATH_KEY_DEPRECATED
@ -514,7 +512,6 @@ class WalletNode:
tb = traceback.format_exc()
self.log.error(f"Exception while perform_atomic_rollback: {e} {tb}")
await self.wallet_state_manager.db_wrapper.rollback_transaction()
await self.wallet_state_manager.pool_store.rebuild_cache()
raise
else:
await self.wallet_state_manager.blockchain.clean_block_records()
@ -715,7 +712,6 @@ class WalletNode:
tb = traceback.format_exc()
self.log.error(f"Exception while adding state: {e} {tb}")
await self.wallet_state_manager.db_wrapper.rollback_transaction()
await self.wallet_state_manager.pool_store.rebuild_cache()
else:
await self.wallet_state_manager.blockchain.clean_block_records()
@ -750,7 +746,6 @@ class WalletNode:
await self.wallet_state_manager.db_wrapper.commit_transaction()
except Exception as e:
await self.wallet_state_manager.db_wrapper.rollback_transaction()
await self.wallet_state_manager.pool_store.rebuild_cache()
tb = traceback.format_exc()
self.log.error(f"Error adding states.. {e} {tb}")
return False
@ -834,13 +829,27 @@ class WalletNode:
request.peak_hash,
)
def get_full_node_peer(self) -> Optional[WSChiaConnection]:
def get_full_node_peer(self, synced_only: bool = False) -> Optional[WSChiaConnection]:
"""
Get a full node, preferring synced & trusted > synced & untrusted > unsynced & trusted > unsynced & untrusted
"""
if self._server is None:
return None
nodes = self.server.get_full_node_connections()
if len(nodes) > 0:
return random.choice(nodes)
synced_peers = set(node for node in nodes if node.peer_node_id in self.synced_peers)
trusted_peers = set(node for node in nodes if self.is_trusted(node))
if len(synced_peers & trusted_peers) > 0:
return random.choice(list(synced_peers & trusted_peers))
elif len(synced_peers) > 0:
return random.choice(list(synced_peers))
elif synced_only:
return None
elif len(trusted_peers) > 0:
return random.choice(list(trusted_peers))
else:
return random.choice(list(nodes))
else:
return None
@ -1348,128 +1357,137 @@ class WalletNode:
self.log.error("Failed validation 1")
return False
return True
# block is not included in wp recent chain
start = block.height + 1
compare_to_recent = False
inserted: int = 0
first_height_recent = weight_proof.recent_chain_data[0].height
if start > first_height_recent - 1000:
# compare up to weight_proof.recent_chain_data[0].height
compare_to_recent = True
end = first_height_recent
else:
start = block.height + 1
compare_to_recent = False
current_ses: Optional[SubEpochData] = None
inserted: Optional[SubEpochData] = None
first_height_recent = weight_proof.recent_chain_data[0].height
if start > first_height_recent - 1000:
compare_to_recent = True
end = first_height_recent
else:
if block.height < self.constants.SUB_EPOCH_BLOCKS:
inserted = weight_proof.sub_epochs[1]
end = self.constants.SUB_EPOCH_BLOCKS + inserted.num_blocks_overflow
else:
request = RequestSESInfo(block.height, block.height + 32)
res_ses: Optional[RespondSESInfo] = peer_request_cache.get_ses_request(block.height)
if res_ses is None:
res_ses = await peer.request_ses_hashes(request)
peer_request_cache.add_to_ses_requests(block.height, res_ses)
assert res_ses is not None
ses_0 = res_ses.reward_chain_hash[0]
last_height = res_ses.heights[0][-1] # Last height in sub epoch
end = last_height
num_sub_epochs = len(weight_proof.sub_epochs)
for idx, ses in enumerate(weight_proof.sub_epochs):
if idx > num_sub_epochs - 3:
break
if ses.reward_chain_hash == ses_0:
current_ses = ses
inserted = weight_proof.sub_epochs[idx + 2]
break
if current_ses is None:
self.log.error("Failed validation 2")
return False
all_peers = self.server.get_full_node_connections()
blocks: Optional[List[HeaderBlock]] = await fetch_header_blocks_in_range(
start, end, peer_request_cache, all_peers
)
if blocks is None:
self.log.error(f"Error fetching blocks {start} {end}")
return False
if compare_to_recent and weight_proof.recent_chain_data[0].header_hash != blocks[-1].header_hash:
self.log.error("Failed validation 3")
return False
if not compare_to_recent:
last = blocks[-1].finished_sub_slots[-1].reward_chain.get_hash()
if inserted is None or last != inserted.reward_chain_hash:
self.log.error("Failed validation 4")
return False
pk_m_sig: List[Tuple[G1Element, bytes32, G2Element]] = []
sigs_to_cache: List[HeaderBlock] = []
blocks_to_cache: List[Tuple[bytes32, uint32]] = []
signatures_to_validate: int = 30
for idx in range(len(blocks)):
en_block = blocks[idx]
if idx < signatures_to_validate and not peer_request_cache.in_block_signatures_validated(en_block):
# Validate that the block is buried in the foliage by checking the signatures
pk_m_sig.append(
(
en_block.reward_chain_block.proof_of_space.plot_public_key,
en_block.foliage.foliage_block_data.get_hash(),
en_block.foliage.foliage_block_data_signature,
)
)
sigs_to_cache.append(en_block)
# This is the reward chain challenge. If this is in the cache, it means the prev block
# has been validated. We must at least check the first block to ensure they are connected
reward_chain_hash: bytes32 = en_block.reward_chain_block.reward_chain_ip_vdf.challenge
if idx != 0 and peer_request_cache.in_blocks_validated(reward_chain_hash):
# As soon as we see a block we have already concluded is in the chain, we can quit.
if idx > signatures_to_validate:
# get ses from wp
start_height = block.height
end_height = block.height + 32
ses_start_height = 0
end = 0
for idx, ses in enumerate(weight_proof.sub_epochs):
if idx == len(weight_proof.sub_epochs) - 1:
break
next_ses_height = (idx + 1) * self.constants.SUB_EPOCH_BLOCKS + weight_proof.sub_epochs[
idx + 1
].num_blocks_overflow
# start_ses_hash
if ses_start_height <= start_height < next_ses_height:
inserted = idx + 1
if ses_start_height < end_height < next_ses_height:
end = next_ses_height
break
else:
# Validate that the block is committed to by the weight proof
if idx == 0:
prev_block_rc_hash: bytes32 = block.reward_chain_block.get_hash()
prev_hash = block.header_hash
else:
prev_block_rc_hash = blocks[idx - 1].reward_chain_block.get_hash()
prev_hash = blocks[idx - 1].header_hash
if idx > len(weight_proof.sub_epochs) - 3:
break
# else add extra ses as request start <-> end spans two ses
end = (idx + 2) * self.constants.SUB_EPOCH_BLOCKS + weight_proof.sub_epochs[
idx + 2
].num_blocks_overflow
inserted += 1
break
ses_start_height = next_ses_height
if not en_block.prev_header_hash == prev_hash:
self.log.error("Failed validation 5")
return False
if end == 0:
self.log.error("Error finding sub epoch")
return False
all_peers = self.server.get_full_node_connections()
blocks: Optional[List[HeaderBlock]] = await fetch_header_blocks_in_range(
start, end, peer_request_cache, all_peers
)
if blocks is None:
self.log.error(f"Error fetching blocks {start} {end}")
return False
if len(en_block.finished_sub_slots) > 0:
reversed_slots = en_block.finished_sub_slots.copy()
reversed_slots.reverse()
for slot_idx, slot in enumerate(reversed_slots[:-1]):
hash_val = reversed_slots[slot_idx + 1].reward_chain.get_hash()
if not hash_val == slot.reward_chain.end_of_slot_vdf.challenge:
self.log.error("Failed validation 6")
return False
if not prev_block_rc_hash == reversed_slots[-1].reward_chain.end_of_slot_vdf.challenge:
self.log.error("Failed validation 7")
return False
else:
if not prev_block_rc_hash == reward_chain_hash:
self.log.error("Failed validation 8")
return False
blocks_to_cache.append((reward_chain_hash, en_block.height))
if compare_to_recent and weight_proof.recent_chain_data[0].header_hash != blocks[-1].header_hash:
self.log.error("Failed validation 3")
return False
agg_sig: G2Element = AugSchemeMPL.aggregate([sig for (_, _, sig) in pk_m_sig])
if not AugSchemeMPL.aggregate_verify(
[pk for (pk, _, _) in pk_m_sig], [m for (_, m, _) in pk_m_sig], agg_sig
):
self.log.error("Failed signature validation")
if not compare_to_recent:
last = blocks[-1].finished_sub_slots[-1].reward_chain.get_hash()
if last != weight_proof.sub_epochs[inserted].reward_chain_hash:
self.log.error("Failed validation 4")
return False
for header_block in sigs_to_cache:
peer_request_cache.add_to_block_signatures_validated(header_block)
for reward_chain_hash, height in blocks_to_cache:
peer_request_cache.add_to_blocks_validated(reward_chain_hash, height)
return True
pk_m_sig: List[Tuple[G1Element, bytes32, G2Element]] = []
sigs_to_cache: List[HeaderBlock] = []
blocks_to_cache: List[Tuple[bytes32, uint32]] = []
async def fetch_puzzle_solution(self, peer: WSChiaConnection, height: uint32, coin: Coin) -> CoinSpend:
signatures_to_validate: int = 30
for idx in range(len(blocks)):
en_block = blocks[idx]
if idx < signatures_to_validate and not peer_request_cache.in_block_signatures_validated(en_block):
# Validate that the block is buried in the foliage by checking the signatures
pk_m_sig.append(
(
en_block.reward_chain_block.proof_of_space.plot_public_key,
en_block.foliage.foliage_block_data.get_hash(),
en_block.foliage.foliage_block_data_signature,
)
)
sigs_to_cache.append(en_block)
# This is the reward chain challenge. If this is in the cache, it means the prev block
# has been validated. We must at least check the first block to ensure they are connected
reward_chain_hash: bytes32 = en_block.reward_chain_block.reward_chain_ip_vdf.challenge
if idx != 0 and peer_request_cache.in_blocks_validated(reward_chain_hash):
# As soon as we see a block we have already concluded is in the chain, we can quit.
if idx > signatures_to_validate:
break
else:
# Validate that the block is committed to by the weight proof
if idx == 0:
prev_block_rc_hash: bytes32 = block.reward_chain_block.get_hash()
prev_hash = block.header_hash
else:
prev_block_rc_hash = blocks[idx - 1].reward_chain_block.get_hash()
prev_hash = blocks[idx - 1].header_hash
if not en_block.prev_header_hash == prev_hash:
self.log.error("Failed validation 5")
return False
if len(en_block.finished_sub_slots) > 0:
reversed_slots = en_block.finished_sub_slots.copy()
reversed_slots.reverse()
for slot_idx, slot in enumerate(reversed_slots[:-1]):
hash_val = reversed_slots[slot_idx + 1].reward_chain.get_hash()
if not hash_val == slot.reward_chain.end_of_slot_vdf.challenge:
self.log.error("Failed validation 6")
return False
if not prev_block_rc_hash == reversed_slots[-1].reward_chain.end_of_slot_vdf.challenge:
self.log.error("Failed validation 7")
return False
else:
if not prev_block_rc_hash == reward_chain_hash:
self.log.error("Failed validation 8")
return False
blocks_to_cache.append((reward_chain_hash, en_block.height))
agg_sig: G2Element = AugSchemeMPL.aggregate([sig for (_, _, sig) in pk_m_sig])
if not AugSchemeMPL.aggregate_verify([pk for (pk, _, _) in pk_m_sig], [m for (_, m, _) in pk_m_sig], agg_sig):
self.log.error("Failed signature validation")
return False
for header_block in sigs_to_cache:
peer_request_cache.add_to_block_signatures_validated(header_block)
for reward_chain_hash, height in blocks_to_cache:
peer_request_cache.add_to_blocks_validated(reward_chain_hash, height)
return True
async def fetch_puzzle_solution(
self, height: uint32, coin: Coin, peer: Optional[WSChiaConnection] = None
) -> CoinSpend:
if peer is None:
peer = self.get_full_node_peer()
if peer is None:
raise ValueError("Could not find any peers to request puzzle and solution from")
solution_response = await peer.request_puzzle_solution(
wallet_protocol.RequestPuzzleSolution(coin.name(), height)
)
@ -1487,23 +1505,11 @@ class WalletNode:
async def get_coin_state(
self, coin_names: List[bytes32], fork_height: Optional[uint32] = None, peer: Optional[WSChiaConnection] = None
) -> List[CoinState]:
all_nodes = self.server.connection_by_type[NodeType.FULL_NODE]
if len(all_nodes.keys()) == 0:
raise ValueError("Not connected to the full node")
# Use supplied if provided, prioritize trusted otherwise
synced_peers = [node for node in all_nodes.values() if node.peer_node_id in self.synced_peers]
if peer is None:
for node in synced_peers:
if self.is_trusted(node):
peer = node
break
if peer is None:
if len(synced_peers) > 0:
peer = synced_peers[0]
else:
peer = list(all_nodes.values())[0]
peer = self.get_full_node_peer()
if peer is None:
raise ValueError("Could not find any peers to request puzzle and solution from")
assert peer is not None
msg = wallet_protocol.RegisterForCoinUpdates(coin_names, uint32(0))
coin_state: Optional[RespondToCoinUpdates] = await peer.register_interest_in_coin(msg)
assert coin_state is not None
@ -1521,8 +1527,12 @@ class WalletNode:
return coin_state.coin_states
async def fetch_children(
self, peer: WSChiaConnection, coin_name: bytes32, fork_height: Optional[uint32] = None
self, coin_name: bytes32, fork_height: Optional[uint32] = None, peer: Optional[WSChiaConnection] = None
) -> List[CoinState]:
if peer is None:
peer = self.get_full_node_peer()
if peer is None:
raise ValueError("Could not find any peers to request puzzle and solution from")
response: Optional[wallet_protocol.RespondChildren] = await peer.request_children(
wallet_protocol.RequestChildren(coin_name)
)

View File

@ -1,5 +1,5 @@
import logging
from typing import List, Tuple, Dict, Optional
from typing import List, Tuple
import aiosqlite
@ -13,7 +13,6 @@ log = logging.getLogger(__name__)
class WalletPoolStore:
db_connection: aiosqlite.Connection
db_wrapper: DBWrapper
_state_transitions_cache: Dict[int, List[Tuple[uint32, CoinSpend]]]
@classmethod
async def create(cls, wrapper: DBWrapper):
@ -23,11 +22,15 @@ class WalletPoolStore:
self.db_wrapper = wrapper
await self.db_connection.execute(
"CREATE TABLE IF NOT EXISTS pool_state_transitions(transition_index integer, wallet_id integer, "
"height bigint, coin_spend blob, PRIMARY KEY(transition_index, wallet_id))"
"CREATE TABLE IF NOT EXISTS pool_state_transitions("
" transition_index integer,"
" wallet_id integer,"
" height bigint,"
" coin_spend blob,"
" PRIMARY KEY(transition_index, wallet_id))"
)
await self.db_connection.commit()
await self.rebuild_cache()
return self
async def _clear_database(self):
@ -51,28 +54,48 @@ class WalletPoolStore:
if not in_transaction:
await self.db_wrapper.lock.acquire()
try:
if wallet_id not in self._state_transitions_cache:
self._state_transitions_cache[wallet_id] = []
all_state_transitions: List[Tuple[uint32, CoinSpend]] = self.get_spends_for_wallet(wallet_id)
# find the most recent transition in wallet_id
rows = list(
await self.db_connection.execute_fetchall(
"SELECT transition_index, height, coin_spend "
"FROM pool_state_transitions "
"WHERE wallet_id=? "
"ORDER BY transition_index DESC "
"LIMIT 1",
(wallet_id,),
)
)
serialized_spend = bytes(spend)
if len(rows) == 0:
transition_index = 0
else:
existing = list(
await self.db_connection.execute_fetchall(
"SELECT COUNT(*) "
"FROM pool_state_transitions "
"WHERE wallet_id=? AND height=? AND coin_spend=?",
(wallet_id, height, serialized_spend),
)
)
if existing[0][0] != 0:
# we already have this transition in the DB
return
if (height, spend) in all_state_transitions:
return
if len(all_state_transitions) > 0:
if height < all_state_transitions[-1][0]:
row = rows[0]
if height < row[1]:
raise ValueError("Height cannot go down")
if spend.coin.parent_coin_info != all_state_transitions[-1][1].coin.name():
prev = CoinSpend.from_bytes(row[2])
if spend.coin.parent_coin_info != prev.coin.name():
raise ValueError("New spend does not extend")
all_state_transitions.append((height, spend))
transition_index = row[0]
cursor = await self.db_connection.execute(
"INSERT OR REPLACE INTO pool_state_transitions VALUES (?, ?, ?, ?)",
"INSERT OR IGNORE INTO pool_state_transitions VALUES (?, ?, ?, ?)",
(
len(all_state_transitions) - 1,
transition_index + 1,
wallet_id,
height,
bytes(spend),
serialized_spend,
),
)
await cursor.close()
@ -81,27 +104,16 @@ class WalletPoolStore:
await self.db_connection.commit()
self.db_wrapper.lock.release()
def get_spends_for_wallet(self, wallet_id: int) -> List[Tuple[uint32, CoinSpend]]:
async def get_spends_for_wallet(self, wallet_id: int) -> List[Tuple[uint32, CoinSpend]]:
"""
Retrieves all entries for a wallet ID from the cache, works even if commit is not called yet.
Retrieves all entries for a wallet ID.
"""
return self._state_transitions_cache.get(wallet_id, [])
async def rebuild_cache(self) -> None:
"""
This resets the cache, and loads all entries from the DB. Any entries in the cache that were not committed
are removed. This can happen if a state transition in wallet_blockchain fails.
"""
cursor = await self.db_connection.execute("SELECT * FROM pool_state_transitions ORDER BY transition_index")
rows = await cursor.fetchall()
await cursor.close()
self._state_transitions_cache = {}
for row in rows:
_, wallet_id, height, coin_spend_bytes = row
coin_spend: CoinSpend = CoinSpend.from_bytes(coin_spend_bytes)
if wallet_id not in self._state_transitions_cache:
self._state_transitions_cache[wallet_id] = []
self._state_transitions_cache[wallet_id].append((height, coin_spend))
rows = await self.db_connection.execute_fetchall(
"SELECT height, coin_spend FROM pool_state_transitions WHERE wallet_id=? ORDER BY transition_index",
(wallet_id,),
)
return [(uint32(row[0]), CoinSpend.from_bytes(row[1])) for row in rows]
async def rollback(self, height: int, wallet_id_arg: int, in_transaction: bool) -> None:
"""
@ -113,14 +125,6 @@ class WalletPoolStore:
if not in_transaction:
await self.db_wrapper.lock.acquire()
try:
for wallet_id, items in self._state_transitions_cache.items():
remove_index_start: Optional[int] = None
for i, (item_block_height, _) in enumerate(items):
if item_block_height > height and wallet_id == wallet_id_arg:
remove_index_start = i
break
if remove_index_start is not None:
del items[remove_index_start:]
cursor = await self.db_connection.execute(
"DELETE FROM pool_state_transitions WHERE height>? AND wallet_id=?", (height, wallet_id_arg)
)

View File

@ -119,7 +119,6 @@ class WalletStateManager:
blockchain: WalletBlockchain
coin_store: WalletCoinStore
sync_store: WalletSyncStore
finished_sync_up_to: uint32
interested_store: WalletInterestedStore
multiprocessing_context: multiprocessing.context.BaseContext
weight_proof_handler: WalletWeightProofHandler
@ -187,7 +186,6 @@ class WalletStateManager:
self.wallet_node = wallet_node
self.sync_mode = False
self.sync_target = uint32(0)
self.finished_sync_up_to = uint32(0)
multiprocessing_start_method = process_config_start_method(config=self.config, log=self.log)
self.multiprocessing_context = multiprocessing.get_context(method=multiprocessing_start_method)
self.weight_proof_handler = WalletWeightProofHandler(
@ -604,7 +602,7 @@ class WalletStateManager:
assert parent_coin_state.spent_height == coin_state.created_height
coin_spend: Optional[CoinSpend] = await self.wallet_node.fetch_puzzle_solution(
peer, parent_coin_state.spent_height, parent_coin_state.coin
parent_coin_state.spent_height, parent_coin_state.coin, peer
)
if coin_spend is None:
return None, None
@ -991,7 +989,7 @@ class WalletStateManager:
)
await self.tx_store.add_transaction_record(tx_record, True)
children = await self.wallet_node.fetch_children(peer, coin_name, fork_height)
children = await self.wallet_node.fetch_children(coin_name, fork_height, peer)
assert children is not None
additions = [state.coin for state in children]
if len(children) > 0:
@ -1068,7 +1066,7 @@ class WalletStateManager:
while curr_coin_state.spent_height is not None:
cs: CoinSpend = await self.wallet_node.fetch_puzzle_solution(
peer, curr_coin_state.spent_height, curr_coin_state.coin
curr_coin_state.spent_height, curr_coin_state.coin, peer
)
success = await wallet.apply_state_transition(cs, curr_coin_state.spent_height)
if not success:
@ -1093,7 +1091,7 @@ class WalletStateManager:
curr_coin_state = new_coin_state[0]
if record.wallet_type == WalletType.DATA_LAYER:
singleton_spend = await self.wallet_node.fetch_puzzle_solution(
peer, coin_state.spent_height, coin_state.coin
coin_state.spent_height, coin_state.coin, peer
)
dl_wallet = self.wallets[uint32(record.wallet_id)]
await dl_wallet.singleton_removed(
@ -1109,7 +1107,7 @@ class WalletStateManager:
# Check if a child is a singleton launcher
if children is None:
children = await self.wallet_node.fetch_children(peer, coin_name, fork_height)
children = await self.wallet_node.fetch_children(coin_name, fork_height, peer)
assert children is not None
for child in children:
if child.coin.puzzle_hash != SINGLETON_LAUNCHER_HASH:
@ -1120,7 +1118,7 @@ class WalletStateManager:
# TODO handle spending launcher later block
continue
launcher_spend: Optional[CoinSpend] = await self.wallet_node.fetch_puzzle_solution(
peer, coin_state.spent_height, child.coin
coin_state.spent_height, child.coin, peer
)
if launcher_spend is None:
continue

View File

@ -210,7 +210,7 @@ class WalletTransactionStore:
await self.add_transaction_record(tx, False)
return True
async def tx_reorged(self, record: TransactionRecord, in_transaction: bool):
async def tx_reorged(self, record: TransactionRecord, in_transaction: bool) -> None:
"""
Updates transaction sent count to 0 and resets confirmation data
"""
@ -246,14 +246,17 @@ class WalletTransactionStore:
return TransactionRecord.from_bytes(rows[0][0])
return None
# TODO: This should probably be split into separate function, one that
# queries the state and one that updates it. Also, include_accepted_txs=True
# might be a separate function too.
# also, the current time should be passed in as a paramter
async def get_not_sent(self, *, include_accepted_txs=False) -> List[TransactionRecord]:
"""
Returns the list of transactions that have not been received by full node yet.
"""
current_time = int(time.time())
rows = await self.db_connection.execute_fetchall(
"SELECT * from transaction_record WHERE confirmed=?",
(0,),
"SELECT * from transaction_record WHERE confirmed=0",
)
records = []
@ -287,29 +290,17 @@ class WalletTransactionStore:
fee_int = TransactionType.FEE_REWARD.value
pool_int = TransactionType.COINBASE_REWARD.value
rows = await self.db_connection.execute_fetchall(
"SELECT * from transaction_record WHERE confirmed=? and (type=? or type=?)", (1, fee_int, pool_int)
"SELECT * from transaction_record WHERE confirmed=1 and (type=? or type=?)", (fee_int, pool_int)
)
records = []
for row in rows:
record = TransactionRecord.from_bytes(row[0])
records.append(record)
return records
return [TransactionRecord.from_bytes(row[0]) for row in rows]
async def get_all_unconfirmed(self) -> List[TransactionRecord]:
"""
Returns the list of all transaction that have not yet been confirmed.
"""
rows = await self.db_connection.execute_fetchall("SELECT * from transaction_record WHERE confirmed=?", (0,))
records = []
for row in rows:
record = TransactionRecord.from_bytes(row[0])
records.append(record)
return records
rows = await self.db_connection.execute_fetchall("SELECT * from transaction_record WHERE confirmed=0")
return [TransactionRecord.from_bytes(row[0]) for row in rows]
async def get_unconfirmed_for_wallet(self, wallet_id: int) -> List[TransactionRecord]:
"""
@ -331,7 +322,7 @@ class WalletTransactionStore:
if to_puzzle_hash is None:
puzz_hash_where = ""
else:
puzz_hash_where = f' and to_puzzle_hash="{to_puzzle_hash.hex()}"'
puzz_hash_where = f' AND to_puzzle_hash="{to_puzzle_hash.hex()}"'
if sort_key is None:
sort_key = "CONFIRMED_AT_HEIGHT"
@ -344,7 +335,7 @@ class WalletTransactionStore:
query_str = SortKey[sort_key].ascending()
rows = await self.db_connection.execute_fetchall(
f"SELECT * from transaction_record where wallet_id=?{puzz_hash_where}"
f"SELECT * from transaction_record WHERE wallet_id=?{puzz_hash_where}"
f" {query_str}, rowid"
f" LIMIT {start}, {limit}",
(wallet_id,),
@ -366,11 +357,11 @@ class WalletTransactionStore:
"""
if type is None:
rows = await self.db_connection.execute_fetchall(
"SELECT * from transaction_record where wallet_id=?", (wallet_id,)
"SELECT * FROM transaction_record WHERE wallet_id=?", (wallet_id,)
)
else:
rows = await self.db_connection.execute_fetchall(
"SELECT * from transaction_record where wallet_id=? and type=?",
"SELECT * FROM transaction_record WHERE wallet_id=? AND type=?",
(
wallet_id,
type,

View File

@ -13,13 +13,13 @@ dependencies = [
"aiohttp==3.8.1", # HTTP server for full node rpc
"aiosqlite==0.17.0", # asyncio wrapper for sqlite, to store blocks
"bitstring==3.1.9", # Binary data management library
"colorama==0.4.4", # Colorizes terminal output
"colorama==0.4.5", # Colorizes terminal output
"colorlog==6.6.0", # Adds color to logs
"concurrent-log-handler==0.9.19", # Concurrently log and rotate logs
"cryptography==36.0.2", # Python cryptography library for TLS - keyring conflict
"fasteners==0.16.3", # For interprocess file locking, expected to be replaced by filelock
"filelock==3.4.2", # For reading and writing config multiprocess and multithread safely (non-reentrant locks)
"keyring==23.0.1", # Store keys in MacOS Keychain, Windows Credential Locker
"fasteners==0.17.3", # For interprocess file locking, expected to be replaced by filelock
"filelock==3.7.1", # For reading and writing config multiprocess and multithread safely (non-reentrant locks)
"keyring==23.6.0", # Store keys in MacOS Keychain, Windows Credential Locker
"keyrings.cryptfile==1.3.4", # Secure storage for keys on Linux (Will be replaced)
# "keyrings.cryptfile==1.3.8", # Secure storage for keys on Linux (Will be replaced)
# See https://github.com/frispete/keyrings.cryptfile/issues/15
@ -31,9 +31,9 @@ dependencies = [
"dnspython==2.2.0", # Query DNS seeds
"watchdog==2.1.9", # Filesystem event watching - watches keyring.yaml
"dnslib==0.9.17", # dns lib
"typing-extensions==4.0.1", # typing backports like Protocol and TypedDict
"typing-extensions==4.3.0", # typing backports like Protocol and TypedDict
"zstd==1.5.0.4",
"packaging==21.0",
"packaging==21.3",
]
upnp_dependencies = [

View File

@ -1,4 +1,5 @@
import asyncio
import contextlib
from pathlib import Path
from typing import AsyncIterator, Dict, List, Tuple, Set
import pytest
@ -32,6 +33,7 @@ nodes = Tuple[WalletNode, FullNodeSimulator]
nodes_with_port = Tuple[WalletNode, FullNodeSimulator, int]
@contextlib.asynccontextmanager
async def init_data_layer(wallet_rpc_port: int, bt: BlockTools, db_path: Path) -> AsyncIterator[DataLayer]:
config = bt.config
config["data_layer"]["wallet_peer"]["port"] = wallet_rpc_port
@ -43,11 +45,13 @@ async def init_data_layer(wallet_rpc_port: int, bt: BlockTools, db_path: Path) -
save_config(bt.root_path, "config.yaml", config)
kwargs = service_kwargs_for_data_layer(root_path=bt.root_path, config=config)
kwargs.update(parse_cli_args=False)
service = Service(**kwargs, running_new_process=False)
service = Service(**kwargs)
await service.start()
yield service._api.data_layer
service.stop()
await service.wait_closed()
try:
yield service._api.data_layer
finally:
service.stop()
await service.wait_closed()
@pytest_asyncio.fixture(scope="function")
@ -94,7 +98,7 @@ async def test_create_insert_get(one_wallet_node_and_rpc: nodes_with_port, bt: B
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
wallet_rpc_api = WalletRpcApi(wallet_node)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
# test insert
data_rpc_api = DataLayerRpcApi(data_layer)
key = b"a"
@ -162,7 +166,7 @@ async def test_upsert(one_wallet_node_and_rpc: nodes_with_port, bt: BlockTools,
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
wallet_rpc_api = WalletRpcApi(wallet_node)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
# test insert
data_rpc_api = DataLayerRpcApi(data_layer)
key = b"a"
@ -207,7 +211,7 @@ async def test_create_double_insert(one_wallet_node_and_rpc: nodes_with_port, bt
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
wallet_rpc_api = WalletRpcApi(wallet_node)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
data_rpc_api = DataLayerRpcApi(data_layer)
res = await data_rpc_api.create_data_store({})
assert res is not None
@ -269,7 +273,7 @@ async def test_keys_values_ancestors(one_wallet_node_and_rpc: nodes_with_port, b
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
wallet_rpc_api = WalletRpcApi(wallet_node)
# TODO: with this being a pseudo context manager'ish thing it doesn't actually handle shutdown
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
data_rpc_api = DataLayerRpcApi(data_layer)
res = await data_rpc_api.create_data_store({})
assert res is not None
@ -352,7 +356,7 @@ async def test_get_roots(one_wallet_node_and_rpc: nodes_with_port, bt: BlockTool
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
wallet_rpc_api = WalletRpcApi(wallet_node)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
data_rpc_api = DataLayerRpcApi(data_layer)
res = await data_rpc_api.create_data_store({})
assert res is not None
@ -426,7 +430,7 @@ async def test_get_root_history(one_wallet_node_and_rpc: nodes_with_port, bt: Bl
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
wallet_rpc_api = WalletRpcApi(wallet_node)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
data_rpc_api = DataLayerRpcApi(data_layer)
res = await data_rpc_api.create_data_store({})
assert res is not None
@ -503,7 +507,7 @@ async def test_get_kv_diff(one_wallet_node_and_rpc: nodes_with_port, bt: BlockTo
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
wallet_rpc_api = WalletRpcApi(wallet_node)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
data_rpc_api = DataLayerRpcApi(data_layer)
res = await data_rpc_api.create_data_store({})
assert res is not None
@ -595,7 +599,7 @@ async def test_batch_update_matches_single_operations(
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
wallet_rpc_api = WalletRpcApi(wallet_node)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
data_rpc_api = DataLayerRpcApi(data_layer)
res = await data_rpc_api.create_data_store({})
assert res is not None
@ -705,7 +709,7 @@ async def test_get_owned_stores(one_wallet_node_and_rpc: nodes_with_port, bt: Bl
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
data_rpc_api = DataLayerRpcApi(data_layer)
expected_store_ids = []
@ -741,7 +745,7 @@ async def test_subscriptions(one_wallet_node_and_rpc: nodes_with_port, bt: Block
)
await time_out_assert(15, wallet_node.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
async for data_layer in init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path):
async with init_data_layer(wallet_rpc_port=wallet_rpc_port, bt=bt, db_path=tmp_path) as data_layer:
data_rpc_api = DataLayerRpcApi(data_layer)
res = await data_rpc_api.create_data_store({})

View File

@ -35,11 +35,11 @@ class TestRateLimits:
# Too many messages
r = RateLimiter(incoming=True)
new_tx_message = make_msg(ProtocolMessageTypes.new_transaction, bytes([1] * 40))
for i in range(4900):
for i in range(4999):
assert r.process_msg_and_check(new_tx_message, rl_v2, rl_v2)
saw_disconnect = False
for i in range(4900):
for i in range(4999):
response = r.process_msg_and_check(new_tx_message, rl_v2, rl_v2)
if not response:
saw_disconnect = True
@ -48,7 +48,7 @@ class TestRateLimits:
# Non-tx message
r = RateLimiter(incoming=True)
new_peak_message = make_msg(ProtocolMessageTypes.new_peak, bytes([1] * 40))
for i in range(20):
for i in range(200):
assert r.process_msg_and_check(new_peak_message, rl_v2, rl_v2)
saw_disconnect = False
@ -80,7 +80,7 @@ class TestRateLimits:
# Too much data
r = RateLimiter(incoming=True)
tx_message = make_msg(ProtocolMessageTypes.respond_transaction, bytes([1] * 500 * 1024))
for i in range(10):
for i in range(40):
assert r.process_msg_and_check(tx_message, rl_v2, rl_v2)
saw_disconnect = False
@ -110,14 +110,14 @@ class TestRateLimits:
message_2 = make_msg(ProtocolMessageTypes.request_blocks, bytes([1] * 64))
message_3 = make_msg(ProtocolMessageTypes.plot_sync_start, bytes([1] * 64))
for i in range(450):
for i in range(500):
assert r.process_msg_and_check(message_1, rl_v2, rl_v2)
for i in range(450):
for i in range(500):
assert r.process_msg_and_check(message_2, rl_v2, rl_v2)
saw_disconnect = False
for i in range(450):
for i in range(500):
response = r.process_msg_and_check(message_3, rl_v2, rl_v2)
if not response:
saw_disconnect = True
@ -158,11 +158,11 @@ class TestRateLimits:
# Counts reset also
r = RateLimiter(True, 5)
new_tx_message = make_msg(ProtocolMessageTypes.new_transaction, bytes([1] * 40))
for i in range(4900):
for i in range(4999):
assert r.process_msg_and_check(new_tx_message, rl_v2, rl_v2)
saw_disconnect = False
for i in range(4900):
for i in range(4999):
response = r.process_msg_and_check(new_tx_message, rl_v2, rl_v2)
if not response:
saw_disconnect = True

View File

@ -19,7 +19,6 @@ from chia.util.ints import uint8, uint32, uint64
from chia.util.streamable import (
DefinitionError,
Streamable,
dataclass_from_dict,
is_type_List,
is_type_SpecificOptional,
is_type_Tuple,
@ -32,6 +31,7 @@ from chia.util.streamable import (
parse_tuple,
parse_uint32,
streamable,
streamable_from_dict,
write_uint32,
)
from tests.block_tools import BlockTools
@ -94,41 +94,27 @@ def test_plain_class_not_supported() -> None:
a: PlainClass
@dataclass
class TestDataclassFromDict1:
a: int
@streamable
@dataclass(frozen=True)
class StreamableFromDict1(Streamable):
a: uint8
b: str
c: G1Element
@dataclass
class TestDataclassFromDict2:
a: TestDataclassFromDict1
b: TestDataclassFromDict1
c: float
@streamable
@dataclass(frozen=True)
class StreamableFromDict2(Streamable):
a: StreamableFromDict1
b: StreamableFromDict1
c: uint64
def test_pure_dataclasses_in_dataclass_from_dict() -> None:
d1_dict = {"a": 1, "b": "2", "c": str(G1Element())}
d1: TestDataclassFromDict1 = dataclass_from_dict(TestDataclassFromDict1, d1_dict)
assert d1.a == 1
assert d1.b == "2"
assert d1.c == G1Element()
d2_dict = {"a": d1, "b": d1_dict, "c": 1.2345}
d2: TestDataclassFromDict2 = dataclass_from_dict(TestDataclassFromDict2, d2_dict)
assert d2.a == d1
assert d2.b == d1
assert d2.c == 1.2345
@dataclass
class ConvertTupleFailures:
a: Tuple[int, int]
b: Tuple[int, Tuple[int, int]]
@streamable
@dataclass(frozen=True)
class ConvertTupleFailures(Streamable):
a: Tuple[uint8, uint8]
b: Tuple[uint8, Tuple[uint8, uint8]]
@pytest.mark.parametrize(
@ -149,13 +135,14 @@ class ConvertTupleFailures:
def test_convert_tuple_failures(input_dict: Dict[str, Any], error: Any) -> None:
with pytest.raises(error):
dataclass_from_dict(ConvertTupleFailures, input_dict)
streamable_from_dict(ConvertTupleFailures, input_dict)
@dataclass
class ConvertListFailures:
a: List[int]
b: List[List[int]]
@streamable
@dataclass(frozen=True)
class ConvertListFailures(Streamable):
a: List[uint8]
b: List[List[uint8]]
@pytest.mark.parametrize(
@ -172,11 +159,12 @@ class ConvertListFailures:
def test_convert_list_failures(input_dict: Dict[str, Any], error: Any) -> None:
with pytest.raises(error):
dataclass_from_dict(ConvertListFailures, input_dict)
streamable_from_dict(ConvertListFailures, input_dict)
@dataclass
class ConvertByteTypeFailures:
@streamable
@dataclass(frozen=True)
class ConvertByteTypeFailures(Streamable):
a: bytes4
b: bytes
@ -201,11 +189,12 @@ class ConvertByteTypeFailures:
def test_convert_byte_type_failures(input_dict: Dict[str, Any], error: Any) -> None:
with pytest.raises(error):
dataclass_from_dict(ConvertByteTypeFailures, input_dict)
streamable_from_dict(ConvertByteTypeFailures, input_dict)
@dataclass
class ConvertUnhashableTypeFailures:
@streamable
@dataclass(frozen=True)
class ConvertUnhashableTypeFailures(Streamable):
a: G1Element
@ -226,7 +215,7 @@ class ConvertUnhashableTypeFailures:
def test_convert_unhashable_type_failures(input_dict: Dict[str, Any], error: Any) -> None:
with pytest.raises(error):
dataclass_from_dict(ConvertUnhashableTypeFailures, input_dict)
streamable_from_dict(ConvertUnhashableTypeFailures, input_dict)
class NoStrClass:
@ -234,9 +223,10 @@ class NoStrClass:
raise RuntimeError("No string")
@dataclass
class ConvertPrimitiveFailures:
a: int
@streamable
@dataclass(frozen=True)
class ConvertPrimitiveFailures(Streamable):
a: uint8
b: uint8
c: str
@ -252,28 +242,28 @@ class ConvertPrimitiveFailures:
def test_convert_primitive_failures(input_dict: Dict[str, Any], error: Any) -> None:
with pytest.raises(error):
dataclass_from_dict(ConvertPrimitiveFailures, input_dict)
streamable_from_dict(ConvertPrimitiveFailures, input_dict)
@pytest.mark.parametrize(
"test_class, input_dict, error",
[
[TestDataclassFromDict1, {"a": "asdf", "b": "2", "c": G1Element()}, TypeError],
[TestDataclassFromDict1, {"a": 1, "b": "2"}, KeyError],
[TestDataclassFromDict1, {"a": 1, "b": "2", "c": "asd"}, TypeError],
[TestDataclassFromDict1, {"a": 1, "b": "2", "c": "00" * G1Element.SIZE}, TypeError],
[TestDataclassFromDict1, {"a": [], "b": "2", "c": G1Element()}, TypeError],
[TestDataclassFromDict1, {"a": {}, "b": "2", "c": G1Element()}, TypeError],
[TestDataclassFromDict2, {"a": "asdf", "b": 1.2345, "c": 1.2345}, TypeError],
[TestDataclassFromDict2, {"a": 1.2345, "b": {"a": 1, "b": "2"}, "c": 1.2345}, TypeError],
[TestDataclassFromDict2, {"a": {"a": 1, "b": "2", "c": G1Element()}, "b": {"a": 1, "b": "2"}}, KeyError],
[TestDataclassFromDict2, {"a": {"a": 1, "b": "2"}, "b": {"a": 1, "b": "2"}, "c": 1.2345}, KeyError],
[StreamableFromDict1, {"a": "asdf", "b": "2", "c": G1Element()}, TypeError],
[StreamableFromDict1, {"a": 1, "b": "2"}, KeyError],
[StreamableFromDict1, {"a": 1, "b": "2", "c": "asd"}, TypeError],
[StreamableFromDict1, {"a": 1, "b": "2", "c": "00" * G1Element.SIZE}, TypeError],
[StreamableFromDict1, {"a": [], "b": "2", "c": G1Element()}, TypeError],
[StreamableFromDict1, {"a": {}, "b": "2", "c": G1Element()}, TypeError],
[StreamableFromDict2, {"a": "asdf", "b": 12345, "c": 12345}, TypeError],
[StreamableFromDict2, {"a": 12345, "b": {"a": 1, "b": "2"}, "c": 12345}, TypeError],
[StreamableFromDict2, {"a": {"a": 1, "b": "2", "c": G1Element()}, "b": {"a": 1, "b": "2"}}, KeyError],
[StreamableFromDict2, {"a": {"a": 1, "b": "2"}, "b": {"a": 1, "b": "2"}, "c": 12345}, KeyError],
],
)
def test_dataclass_from_dict_failures(test_class: Type[Any], input_dict: Dict[str, Any], error: Any) -> None:
def test_streamable_from_dict_failures(test_class: Type[Streamable], input_dict: Dict[str, Any], error: Any) -> None:
with pytest.raises(error):
dataclass_from_dict(test_class, input_dict)
streamable_from_dict(test_class, input_dict)
@streamable

View File

@ -51,38 +51,35 @@ class TestWalletPoolStore:
solution_0_alt: CoinSpend = make_child_solution(None, coin_0_alt)
solution_1: CoinSpend = make_child_solution(solution_0)
assert store.get_spends_for_wallet(0) == []
assert store.get_spends_for_wallet(1) == []
assert await store.get_spends_for_wallet(0) == []
assert await store.get_spends_for_wallet(1) == []
await store.add_spend(1, solution_1, 100, True)
assert store.get_spends_for_wallet(1) == [(100, solution_1)]
assert await store.get_spends_for_wallet(1) == [(100, solution_1)]
# Idempotent
await store.add_spend(1, solution_1, 100, True)
assert store.get_spends_for_wallet(1) == [(100, solution_1)]
assert await store.get_spends_for_wallet(1) == [(100, solution_1)]
with pytest.raises(ValueError):
await store.add_spend(1, solution_1, 101, True)
# Rebuild cache, no longer present
await db_wrapper.rollback_transaction()
await store.rebuild_cache()
assert store.get_spends_for_wallet(1) == []
assert await store.get_spends_for_wallet(1) == []
await store.rebuild_cache()
await store.add_spend(1, solution_1, 100, False)
assert store.get_spends_for_wallet(1) == [(100, solution_1)]
assert await store.get_spends_for_wallet(1) == [(100, solution_1)]
solution_1_alt: CoinSpend = make_child_solution(solution_0_alt)
with pytest.raises(ValueError):
await store.add_spend(1, solution_1_alt, 100, False)
assert store.get_spends_for_wallet(1) == [(100, solution_1)]
assert await store.get_spends_for_wallet(1) == [(100, solution_1)]
solution_2: CoinSpend = make_child_solution(solution_1)
await store.add_spend(1, solution_2, 100, False)
await store.rebuild_cache()
solution_3: CoinSpend = make_child_solution(solution_2)
await store.add_spend(1, solution_3, 100)
solution_4: CoinSpend = make_child_solution(solution_3)
@ -90,21 +87,16 @@ class TestWalletPoolStore:
with pytest.raises(ValueError):
await store.add_spend(1, solution_4, 99)
await store.rebuild_cache()
await store.add_spend(1, solution_4, 101)
await store.rebuild_cache()
await store.rollback(101, 1, False)
await store.rebuild_cache()
assert store.get_spends_for_wallet(1) == [
assert await store.get_spends_for_wallet(1) == [
(100, solution_1),
(100, solution_2),
(100, solution_3),
(101, solution_4),
]
await store.rebuild_cache()
await store.rollback(100, 1, False)
await store.rebuild_cache()
assert store.get_spends_for_wallet(1) == [
assert await store.get_spends_for_wallet(1) == [
(100, solution_1),
(100, solution_2),
(100, solution_3),
@ -116,7 +108,7 @@ class TestWalletPoolStore:
solution_5: CoinSpend = make_child_solution(solution_4)
await store.add_spend(1, solution_5, 105)
await store.rollback(99, 1, False)
assert store.get_spends_for_wallet(1) == []
assert await store.get_spends_for_wallet(1) == []
finally:
await db_connection.close()

View File

@ -118,12 +118,11 @@ async def setup_full_node(
kwargs.update(
parse_cli_args=False,
connect_to_daemon=connect_to_daemon,
service_name_prefix="test_",
)
if disable_capabilities is not None:
kwargs.update(override_capabilities=get_capabilities(disable_capabilities))
service = Service(**kwargs, running_new_process=False)
service = Service(**kwargs)
await service.start()
@ -189,10 +188,9 @@ async def setup_wallet_node(
kwargs.update(
parse_cli_args=False,
connect_to_daemon=False,
service_name_prefix="test_",
)
service = Service(**kwargs, running_new_process=False)
service = Service(**kwargs)
await service.start()
@ -229,10 +227,9 @@ async def setup_harvester(
kwargs.update(
parse_cli_args=False,
connect_to_daemon=False,
service_name_prefix="test_",
)
service = Service(**kwargs, running_new_process=False)
service = Service(**kwargs)
if start_service:
await service.start()
@ -278,10 +275,9 @@ async def setup_farmer(
kwargs.update(
parse_cli_args=False,
connect_to_daemon=False,
service_name_prefix="test_",
)
service = Service(**kwargs, running_new_process=False)
service = Service(**kwargs)
if start_service:
await service.start()
@ -301,10 +297,9 @@ async def setup_introducer(bt: BlockTools, port):
advertised_port=port,
parse_cli_args=False,
connect_to_daemon=False,
service_name_prefix="test_",
)
service = Service(**kwargs, running_new_process=False)
service = Service(**kwargs)
await service.start()
@ -362,10 +357,9 @@ async def setup_timelord(
kwargs.update(
parse_cli_args=False,
connect_to_daemon=False,
service_name_prefix="test_",
)
service = Service(**kwargs, running_new_process=False)
service = Service(**kwargs)
await service.start()

View File

@ -5,7 +5,7 @@ import pytest
from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
from chia.full_node.mempool_manager import MempoolManager
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
from chia.simulator.simulator_protocol import FarmNewBlockProtocol, ReorgProtocol
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.peer_info import PeerInfo
@ -98,6 +98,10 @@ class TestCATWallet:
assert new_cat_wallet.cat_info.my_tail == cat_wallet.cat_info.my_tail
assert await cat_wallet.lineage_store.get_all_lineage_proofs() == all_lineage
height = full_node_api.full_node.blockchain.get_peak_height()
await full_node_api.reorg_from_index_to_new_index(ReorgProtocol(height - num_blocks - 1, height + 1, 32 * b"1"))
await time_out_assert(15, cat_wallet.get_confirmed_balance, 0)
@pytest.mark.asyncio
async def test_cat_creation_unique_lineage_store(self, self_hostname, two_wallet_nodes):
num_blocks = 3
@ -233,12 +237,15 @@ class TestCATWallet:
15, tx_in_pool, True, full_node_api.full_node.mempool_manager, tx_record.spend_bundle.name()
)
for i in range(1, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
await time_out_assert(15, cat_wallet.get_confirmed_balance, 55)
await time_out_assert(15, cat_wallet.get_unconfirmed_balance, 55)
height = full_node_api.full_node.blockchain.get_peak_height()
await full_node_api.reorg_from_index_to_new_index(ReorgProtocol(height - 1, height + 1, 32 * b"1"))
await time_out_assert(15, cat_wallet.get_confirmed_balance, 40)
@pytest.mark.parametrize(
"trusted",
[True, False],

View File

@ -13,6 +13,7 @@ from chia.simulator.simulator_protocol import FarmNewBlockProtocol
from chia.types.blockchain_format.program import Program
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.peer_info import PeerInfo
from chia.types.spend_bundle import SpendBundle
from chia.util.bech32m import encode_puzzle_hash
from chia.util.byte_types import hexstr_to_bytes
from chia.util.ints import uint16, uint32, uint64
@ -50,9 +51,10 @@ async def wait_rpc_state_condition(
return {}
async def make_new_block_with(resp, full_node_api, ph):
async def make_new_block_with(resp: Dict, full_node_api: FullNodeSimulator, ph: bytes32) -> SpendBundle:
assert resp.get("success")
sb = resp["spend_bundle"]
assert isinstance(sb, SpendBundle)
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
return sb
@ -863,8 +865,7 @@ async def test_nft_transfer_nft_with_did(two_wallet_nodes: Any, trusted: Any) ->
spend_bundle = spend_bundle_list[0].spend_bundle
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, spend_bundle.name())
for _ in range(1, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
await time_out_assert(15, wallet_0.get_pending_change_balance, 0)
hex_did_id = did_wallet.get_my_DID()
hmr_did_id = encode_puzzle_hash(bytes32.from_hexstr(hex_did_id), DID_HRP)
@ -886,22 +887,14 @@ async def test_nft_transfer_nft_with_did(two_wallet_nodes: Any, trusted: Any) ->
"fee": fee,
}
)
assert resp.get("success")
sb = resp["spend_bundle"]
# ensure hints are generated
assert compute_memos(sb)
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
for i in range(1, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph1))
await make_new_block_with(resp, full_node_api, ph1)
# Check DID NFT
coins_response = await wait_rpc_state_condition(
5, api_0.nft_get_nfts, [dict(wallet_id=nft_wallet_0_id)], lambda x: x["nft_list"]
)
await time_out_assert(10, wallet_0.get_unconfirmed_balance, 7999999999898)
await time_out_assert(10, wallet_0.get_confirmed_balance, 7999999999898)
await time_out_assert(10, wallet_0.get_unconfirmed_balance, 5999999999898)
await time_out_assert(10, wallet_0.get_confirmed_balance, 5999999999898)
coins = coins_response["nft_list"]
assert len(coins) == 1
assert coins[0].owner_did.hex() == hex_did_id
@ -929,8 +922,8 @@ async def test_nft_transfer_nft_with_did(two_wallet_nodes: Any, trusted: Any) ->
await wait_rpc_state_condition(
5, api_0.nft_get_nfts, [dict(wallet_id=nft_wallet_0_id)], lambda x: not x["nft_list"]
)
await time_out_assert(10, wallet_0.get_unconfirmed_balance, 7999999999798)
await time_out_assert(10, wallet_0.get_confirmed_balance, 7999999999798)
await time_out_assert(10, wallet_0.get_unconfirmed_balance, 5999999999798)
await time_out_assert(10, wallet_0.get_confirmed_balance, 5999999999798)
# wait for all wallets to be created
await time_out_assert(10, len, 3, wallet_1.wallet_state_manager.wallets)
did_wallet_1 = wallet_1.wallet_state_manager.wallets[3]
@ -946,22 +939,19 @@ async def test_nft_transfer_nft_with_did(two_wallet_nodes: Any, trusted: Any) ->
assert coins_response["nft_list"][0].owner_did is None
nft_coin_id = coins_response["nft_list"][0].nft_coin_id
await time_out_assert(10, did_wallet_1.get_spendable_balance, 1)
await time_out_assert(20, did_wallet_1.get_spendable_balance, 1)
# Set DID
resp = await api_1.nft_set_nft_did(
dict(wallet_id=nft_wallet_id_1, did_id=hmr_did_id, nft_coin_id=nft_coin_id.hex(), fee=fee)
)
assert resp.get("success")
for i in range(1, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
await make_new_block_with(resp, full_node_api, ph)
coins_response = await wait_rpc_state_condition(
5, api_1.nft_get_by_did, [dict(did_id=hmr_did_id)], lambda x: x.get("wallet_id", 0) > 0
)
await time_out_assert(10, wallet_1.get_unconfirmed_balance, 12000000000100)
await time_out_assert(10, wallet_1.get_confirmed_balance, 12000000000100)
await time_out_assert(10, wallet_1.get_unconfirmed_balance, 10000000000100)
await time_out_assert(10, wallet_1.get_confirmed_balance, 10000000000100)
nft_wallet_1_id = coins_response.get("wallet_id")
assert nft_wallet_1_id
# Check NFT DID is set now

View File

@ -856,7 +856,14 @@ async def test_nft_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
for _ in range(3):
await farm_transaction_block(full_node_api, wallet_1_node)
await time_out_assert(15, wallet_is_synced, True, wallet_1_node, full_node_api)
nft_wallet: NFTWallet = wallet_1_node.wallet_state_manager.wallets[nft_wallet_id]
def have_nfts():
return len(nft_wallet.get_current_nfts()) > 0
await time_out_assert(15, have_nfts, True)
# Test with the hex version of nft_id
nft_id = nft_wallet.get_current_nfts()[0].coin.name().hex()
nft_info = (await wallet_1_rpc.get_nft_info(nft_id))["nft_info"]
@ -872,6 +879,7 @@ async def test_nft_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
for _ in range(3):
await farm_transaction_block(full_node_api, wallet_1_node)
await time_out_assert(15, wallet_is_synced, True, wallet_1_node, full_node_api)
nft_wallet_id_1 = (
await wallet_2_node.wallet_state_manager.get_all_wallet_info_entries(wallet_type=WalletType.NFT)

View File

@ -160,9 +160,8 @@ class TestWalletSync:
# Tests a reorg with the wallet
num_blocks = 30
blocks_reorg = bt.get_consecutive_blocks(
num_blocks, block_list_input=default_400_blocks[:-5], current_time=True
)
blocks_reorg = bt.get_consecutive_blocks(num_blocks - 1, block_list_input=default_400_blocks[:-5])
blocks_reorg = bt.get_consecutive_blocks(1, blocks_reorg, guarantee_transaction_block=True, current_time=True)
for i in range(1, len(blocks_reorg)):
await full_node_api.full_node.respond_block(full_node_protocol.RespondBlock(blocks_reorg[i]))

View File

@ -0,0 +1,652 @@
import dataclasses
from secrets import token_bytes
from typing import Any, List
import pytest
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.mempool_inclusion_status import MempoolInclusionStatus
from chia.util.errors import Err
from chia.util.ints import uint8, uint32, uint64
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.wallet_transaction_store import WalletTransactionStore, filter_ok_mempool_status
from tests.util.db_connection import DBConnection1
coin_1 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
coin_2 = Coin(token_bytes(32), token_bytes(32), uint64(1234))
coin_3 = Coin(token_bytes(32), token_bytes(32), uint64(12312 - 1234))
tr1 = TransactionRecord(
uint32(0), # confirmed height
uint64(1000), # created_at_time
bytes32(token_bytes(32)), # to_puzzle_hash
uint64(1234), # amount
uint64(12), # fee_amount
False, # confirmed
uint32(0), # sent
None, # Optional[SpendBundle] spend_bundle
[coin_2, coin_3], # additions
[coin_1], # removals
uint32(1), # wallet_id
[], # List[Tuple[str, uint8, Optional[str]]] sent_to
bytes32(token_bytes(32)), # trade_id
uint32(TransactionType.OUTGOING_TX), # type
bytes32(token_bytes(32)), # name
[], # List[Tuple[bytes32, List[bytes]]] memos
)
@pytest.mark.asyncio
async def test_add() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
assert await store.get_transaction_record(tr1.name) is None
await store.add_transaction_record(tr1, False)
assert await store.get_transaction_record(tr1.name) == tr1
@pytest.mark.asyncio
async def test_delete() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
await store.add_transaction_record(tr1, False)
assert await store.get_transaction_record(tr1.name) == tr1
await store.delete_transaction_record(tr1.name)
assert await store.get_transaction_record(tr1.name) is None
@pytest.mark.asyncio
async def test_set_confirmed() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
await store.add_transaction_record(tr1, False)
await store.set_confirmed(tr1.name, uint32(100))
assert await store.get_transaction_record(tr1.name) == dataclasses.replace(
tr1, confirmed=True, confirmed_at_height=uint32(100)
)
@pytest.mark.asyncio
async def test_increment_sent_noop() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
assert (
await store.increment_sent(bytes32(token_bytes(32)), "peer1", MempoolInclusionStatus.PENDING, None) is False
)
@pytest.mark.asyncio
async def test_increment_sent() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
await store.add_transaction_record(tr1, False)
tr = await store.get_transaction_record(tr1.name)
assert tr.sent == 0
assert tr.sent_to == []
assert await store.increment_sent(tr1.name, "peer1", MempoolInclusionStatus.PENDING, None) is True
tr = await store.get_transaction_record(tr1.name)
assert tr.sent == 1
assert tr.sent_to == [("peer1", uint8(2), None)]
assert await store.increment_sent(tr1.name, "peer1", MempoolInclusionStatus.SUCCESS, None) is True
tr = await store.get_transaction_record(tr1.name)
assert tr.sent == 1
assert tr.sent_to == [("peer1", uint8(2), None), ("peer1", uint8(1), None)]
assert await store.increment_sent(tr1.name, "peer2", MempoolInclusionStatus.SUCCESS, None) is True
tr = await store.get_transaction_record(tr1.name)
assert tr.sent == 2
assert tr.sent_to == [("peer1", uint8(2), None), ("peer1", uint8(1), None), ("peer2", uint8(1), None)]
@pytest.mark.asyncio
async def test_increment_sent_error() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
await store.add_transaction_record(tr1, False)
tr = await store.get_transaction_record(tr1.name)
assert tr.sent == 0
assert tr.sent_to == []
await store.increment_sent(tr1.name, "peer1", MempoolInclusionStatus.FAILED, Err.MEMPOOL_NOT_INITIALIZED)
tr = await store.get_transaction_record(tr1.name)
assert tr.sent == 1
assert tr.sent_to == [("peer1", uint8(3), "MEMPOOL_NOT_INITIALIZED")]
def test_filter_ok_mempool_status() -> None:
assert filter_ok_mempool_status([("peer1", uint8(1), None)]) == []
assert filter_ok_mempool_status([("peer1", uint8(2), None)]) == []
assert filter_ok_mempool_status([("peer1", uint8(3), None)]) == [("peer1", uint8(3), None)]
assert filter_ok_mempool_status(
[("peer1", uint8(2), None), ("peer1", uint8(1), None), ("peer1", uint8(3), None)]
) == [("peer1", uint8(3), None)]
assert filter_ok_mempool_status([("peer1", uint8(3), "message does not matter")]) == [
("peer1", uint8(3), "message does not matter")
]
assert filter_ok_mempool_status([("peer1", uint8(2), "message does not matter")]) == []
@pytest.mark.asyncio
async def test_tx_reorged_update() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr = dataclasses.replace(tr1, sent=2, sent_to=[("peer1", uint8(1), None), ("peer2", uint8(1), None)])
await store.add_transaction_record(tr, False)
tr = await store.get_transaction_record(tr.name)
assert tr.sent == 2
assert tr.sent_to == [("peer1", uint8(1), None), ("peer2", uint8(1), None)]
await store.tx_reorged(tr, False)
tr = await store.get_transaction_record(tr1.name)
assert tr.sent == 0
assert tr.sent_to == []
@pytest.mark.asyncio
async def test_tx_reorged_add() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr = dataclasses.replace(tr1, sent=2, sent_to=[("peer1", uint8(1), None), ("peer2", uint8(1), None)])
await store.get_transaction_record(tr.name) is None
await store.tx_reorged(tr, False)
tr = await store.get_transaction_record(tr.name)
assert tr.sent == 0
assert tr.sent_to == []
@pytest.mark.asyncio
async def test_get_tx_record() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr2 = dataclasses.replace(tr1, name=token_bytes(32))
tr3 = dataclasses.replace(tr1, name=token_bytes(32))
assert await store.get_transaction_record(tr1.name) is None
await store.add_transaction_record(tr1, False)
assert await store.get_transaction_record(tr1.name) == tr1
assert await store.get_transaction_record(tr2.name) is None
await store.add_transaction_record(tr2, False)
assert await store.get_transaction_record(tr2.name) == tr2
assert await store.get_transaction_record(tr3.name) is None
await store.add_transaction_record(tr3, False)
assert await store.get_transaction_record(tr3.name) == tr3
assert await store.get_transaction_record(tr1.name) == tr1
assert await store.get_transaction_record(tr2.name) == tr2
assert await store.get_transaction_record(tr3.name) == tr3
@pytest.mark.asyncio
async def test_get_farming_rewards() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
test_trs: List[TransactionRecord] = []
# tr1 is type OUTGOING_TX
for conf in [True, False]:
for type in [
TransactionType.INCOMING_TX,
TransactionType.OUTGOING_TX,
TransactionType.COINBASE_REWARD,
TransactionType.FEE_REWARD,
TransactionType.INCOMING_TRADE,
TransactionType.OUTGOING_TRADE,
]:
test_trs.append(
dataclasses.replace(
tr1,
name=token_bytes(32),
confirmed=conf,
confirmed_at_height=uint32(100 if conf else 0),
type=type,
)
)
for tr in test_trs:
await store.add_transaction_record(tr, False)
assert await store.get_transaction_record(tr.name) == tr
rewards = await store.get_farming_rewards()
assert len(rewards) == 2
assert test_trs[2] in rewards
assert test_trs[3] in rewards
@pytest.mark.asyncio
async def test_get_all_unconfirmed() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr2 = dataclasses.replace(tr1, name=token_bytes(32), confirmed=True, confirmed_at_height=uint32(100))
await store.add_transaction_record(tr1, False)
await store.add_transaction_record(tr2, False)
assert await store.get_all_unconfirmed() == [tr1]
@pytest.mark.asyncio
async def test_get_unconfirmed_for_wallet() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr2 = dataclasses.replace(tr1, name=token_bytes(32), confirmed=True, confirmed_at_height=uint32(100))
tr3 = dataclasses.replace(tr1, name=token_bytes(32), wallet_id=2)
tr4 = dataclasses.replace(tr2, name=token_bytes(32), wallet_id=2)
await store.add_transaction_record(tr1, False)
await store.add_transaction_record(tr2, False)
await store.add_transaction_record(tr3, False)
await store.add_transaction_record(tr4, False)
assert await store.get_unconfirmed_for_wallet(1) == [tr1]
assert await store.get_unconfirmed_for_wallet(2) == [tr3]
@pytest.mark.asyncio
async def test_transaction_count_for_wallet() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr2 = dataclasses.replace(tr1, name=token_bytes(32), wallet_id=2)
# 5 transactions in wallet_id 1
await store.add_transaction_record(tr1, False)
await store.add_transaction_record(dataclasses.replace(tr1, name=token_bytes(32)), False)
await store.add_transaction_record(dataclasses.replace(tr1, name=token_bytes(32)), False)
await store.add_transaction_record(dataclasses.replace(tr1, name=token_bytes(32)), False)
await store.add_transaction_record(dataclasses.replace(tr1, name=token_bytes(32)), False)
# 2 transactions in wallet_id 2
await store.add_transaction_record(tr2, False)
await store.add_transaction_record(dataclasses.replace(tr2, name=token_bytes(32)), False)
assert await store.get_transaction_count_for_wallet(1) == 5
assert await store.get_transaction_count_for_wallet(2) == 2
@pytest.mark.asyncio
async def test_all_transactions_for_wallet() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
test_trs: List[TransactionRecord] = []
for wallet_id in [1, 2]:
for type in [
TransactionType.INCOMING_TX,
TransactionType.OUTGOING_TX,
TransactionType.COINBASE_REWARD,
TransactionType.FEE_REWARD,
TransactionType.INCOMING_TRADE,
TransactionType.OUTGOING_TRADE,
]:
test_trs.append(dataclasses.replace(tr1, name=token_bytes(32), wallet_id=wallet_id, type=type))
for tr in test_trs:
await store.add_transaction_record(tr, False)
assert await store.get_all_transactions_for_wallet(1) == test_trs[:6]
assert await store.get_all_transactions_for_wallet(2) == test_trs[6:]
assert await store.get_all_transactions_for_wallet(1, TransactionType.INCOMING_TX) == [test_trs[0]]
assert await store.get_all_transactions_for_wallet(1, TransactionType.OUTGOING_TX) == [test_trs[1]]
assert await store.get_all_transactions_for_wallet(1, TransactionType.INCOMING_TRADE) == [test_trs[4]]
assert await store.get_all_transactions_for_wallet(1, TransactionType.OUTGOING_TRADE) == [test_trs[5]]
assert await store.get_all_transactions_for_wallet(2, TransactionType.INCOMING_TX) == [test_trs[6]]
assert await store.get_all_transactions_for_wallet(2, TransactionType.OUTGOING_TX) == [test_trs[7]]
assert await store.get_all_transactions_for_wallet(2, TransactionType.INCOMING_TRADE) == [test_trs[10]]
assert await store.get_all_transactions_for_wallet(2, TransactionType.OUTGOING_TRADE) == [test_trs[11]]
def cmp(lhs: List[Any], rhs: List[Any]) -> bool:
if len(rhs) != len(lhs):
return False
for e in lhs:
if e not in rhs:
return False
return True
@pytest.mark.asyncio
async def test_get_all_transactions() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
test_trs: List[TransactionRecord] = []
assert await store.get_all_transactions() == []
for wallet_id in [1, 2, 3, 4]:
test_trs.append(dataclasses.replace(tr1, name=token_bytes(32), wallet_id=wallet_id))
for tr in test_trs:
await store.add_transaction_record(tr, False)
all_trs = await store.get_all_transactions()
assert cmp(all_trs, test_trs)
@pytest.mark.asyncio
async def test_get_transaction_above() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
test_trs: List[TransactionRecord] = []
assert await store.get_transaction_above(uint32(0)) == []
for height in range(10):
test_trs.append(dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(height)))
for tr in test_trs:
await store.add_transaction_record(tr, False)
for height in range(10):
trs = await store.get_transaction_above(uint32(height))
assert cmp(trs, test_trs[height + 1 :])
@pytest.mark.asyncio
async def test_get_tx_by_trade_id() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr2 = dataclasses.replace(tr1, name=token_bytes(32), trade_id=token_bytes(32))
tr3 = dataclasses.replace(tr1, name=token_bytes(32), trade_id=token_bytes(32))
tr4 = dataclasses.replace(tr1, name=token_bytes(32))
assert await store.get_transactions_by_trade_id(tr1.trade_id) == []
await store.add_transaction_record(tr1, False)
assert await store.get_transactions_by_trade_id(tr1.trade_id) == [tr1]
assert await store.get_transactions_by_trade_id(tr2.trade_id) == []
await store.add_transaction_record(tr2, False)
assert await store.get_transactions_by_trade_id(tr2.trade_id) == [tr2]
assert await store.get_transactions_by_trade_id(tr3.trade_id) == []
await store.add_transaction_record(tr3, False)
assert await store.get_transactions_by_trade_id(tr3.trade_id) == [tr3]
# tr1 and tr4 have the same trade_id
assert await store.get_transactions_by_trade_id(tr4.trade_id) == [tr1]
await store.add_transaction_record(tr4, False)
assert cmp(await store.get_transactions_by_trade_id(tr4.trade_id), [tr1, tr4])
assert cmp(await store.get_transactions_by_trade_id(tr1.trade_id), [tr1, tr4])
assert await store.get_transactions_by_trade_id(tr2.trade_id) == [tr2]
assert await store.get_transactions_by_trade_id(tr3.trade_id) == [tr3]
assert cmp(await store.get_transactions_by_trade_id(tr4.trade_id), [tr1, tr4])
@pytest.mark.asyncio
async def test_rollback_to_block() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
test_trs: List[TransactionRecord] = []
for height in range(10):
test_trs.append(dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(height)))
for tr in test_trs:
await store.add_transaction_record(tr, False)
await store.rollback_to_block(uint32(6))
all_trs = await store.get_all_transactions()
assert cmp(all_trs, test_trs[:7])
await store.rollback_to_block(uint32(5))
all_trs = await store.get_all_transactions()
assert cmp(all_trs, test_trs[:6])
@pytest.mark.asyncio
async def test_delete_unconfirmed() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr2 = dataclasses.replace(tr1, name=token_bytes(32), confirmed=True)
tr3 = dataclasses.replace(tr1, name=token_bytes(32), confirmed=True, wallet_id=2)
tr4 = dataclasses.replace(tr1, name=token_bytes(32), wallet_id=2)
await store.add_transaction_record(tr1, False)
await store.add_transaction_record(tr2, False)
await store.add_transaction_record(tr3, False)
await store.add_transaction_record(tr4, False)
assert cmp(await store.get_all_transactions(), [tr1, tr2, tr3, tr4])
await store.delete_unconfirmed_transactions(1)
assert cmp(await store.get_all_transactions(), [tr2, tr3, tr4])
await store.delete_unconfirmed_transactions(2)
assert cmp(await store.get_all_transactions(), [tr2, tr3])
@pytest.mark.asyncio
async def test_get_transactions_between_confirmed() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr2 = dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(1))
tr3 = dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(2))
tr4 = dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(3))
tr5 = dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(4))
await store.add_transaction_record(tr1, False)
await store.add_transaction_record(tr2, False)
await store.add_transaction_record(tr3, False)
await store.add_transaction_record(tr4, False)
await store.add_transaction_record(tr5, False)
# test different limits
assert await store.get_transactions_between(1, 0, 1) == [tr1]
assert await store.get_transactions_between(1, 0, 2) == [tr1, tr2]
assert await store.get_transactions_between(1, 0, 3) == [tr1, tr2, tr3]
assert await store.get_transactions_between(1, 0, 100) == [tr1, tr2, tr3, tr4, tr5]
# test different start offsets
assert await store.get_transactions_between(1, 1, 100) == [tr2, tr3, tr4, tr5]
assert await store.get_transactions_between(1, 2, 100) == [tr3, tr4, tr5]
assert await store.get_transactions_between(1, 3, 100) == [tr4, tr5]
# wallet 2 is empty
assert await store.get_transactions_between(2, 0, 100) == []
# reverse
# test different limits
assert await store.get_transactions_between(1, 0, 1, reverse=True) == [tr5]
assert await store.get_transactions_between(1, 0, 2, reverse=True) == [tr5, tr4]
assert await store.get_transactions_between(1, 0, 3, reverse=True) == [tr5, tr4, tr3]
assert await store.get_transactions_between(1, 0, 100, reverse=True) == [tr5, tr4, tr3, tr2, tr1]
# test different start offsets
assert await store.get_transactions_between(1, 1, 100, reverse=True) == [tr4, tr3, tr2, tr1]
assert await store.get_transactions_between(1, 2, 100, reverse=True) == [tr3, tr2, tr1]
assert await store.get_transactions_between(1, 3, 100, reverse=True) == [tr2, tr1]
@pytest.mark.asyncio
async def test_get_transactions_between_relevance() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
t1 = dataclasses.replace(
tr1, name=token_bytes(32), confirmed=False, confirmed_at_height=uint32(2), created_at_time=1000
)
t2 = dataclasses.replace(
tr1, name=token_bytes(32), confirmed=False, confirmed_at_height=uint32(2), created_at_time=999
)
t3 = dataclasses.replace(
tr1, name=token_bytes(32), confirmed=False, confirmed_at_height=uint32(1), created_at_time=1000
)
t4 = dataclasses.replace(
tr1, name=token_bytes(32), confirmed=False, confirmed_at_height=uint32(1), created_at_time=999
)
t5 = dataclasses.replace(
tr1, name=token_bytes(32), confirmed=True, confirmed_at_height=uint32(2), created_at_time=1000
)
t6 = dataclasses.replace(
tr1, name=token_bytes(32), confirmed=True, confirmed_at_height=uint32(2), created_at_time=999
)
t7 = dataclasses.replace(
tr1, name=token_bytes(32), confirmed=True, confirmed_at_height=uint32(1), created_at_time=1000
)
t8 = dataclasses.replace(
tr1, name=token_bytes(32), confirmed=True, confirmed_at_height=uint32(1), created_at_time=999
)
await store.add_transaction_record(t1, False)
await store.add_transaction_record(t2, False)
await store.add_transaction_record(t3, False)
await store.add_transaction_record(t4, False)
await store.add_transaction_record(t5, False)
await store.add_transaction_record(t6, False)
await store.add_transaction_record(t7, False)
await store.add_transaction_record(t8, False)
# test different limits
assert await store.get_transactions_between(1, 0, 1, sort_key="RELEVANCE") == [t1]
assert await store.get_transactions_between(1, 0, 2, sort_key="RELEVANCE") == [t1, t2]
assert await store.get_transactions_between(1, 0, 3, sort_key="RELEVANCE") == [t1, t2, t3]
assert await store.get_transactions_between(1, 0, 100, sort_key="RELEVANCE") == [t1, t2, t3, t4, t5, t6, t7, t8]
# test different start offsets
assert await store.get_transactions_between(1, 1, 100, sort_key="RELEVANCE") == [t2, t3, t4, t5, t6, t7, t8]
assert await store.get_transactions_between(1, 2, 100, sort_key="RELEVANCE") == [t3, t4, t5, t6, t7, t8]
assert await store.get_transactions_between(1, 3, 100, sort_key="RELEVANCE") == [t4, t5, t6, t7, t8]
assert await store.get_transactions_between(1, 4, 100, sort_key="RELEVANCE") == [t5, t6, t7, t8]
# wallet 2 is empty
assert await store.get_transactions_between(2, 0, 100, sort_key="RELEVANCE") == []
# reverse
# test different limits
assert await store.get_transactions_between(1, 0, 1, sort_key="RELEVANCE", reverse=True) == [t8]
assert await store.get_transactions_between(1, 0, 2, sort_key="RELEVANCE", reverse=True) == [t8, t7]
assert await store.get_transactions_between(1, 0, 3, sort_key="RELEVANCE", reverse=True) == [t8, t7, t6]
assert await store.get_transactions_between(1, 0, 100, sort_key="RELEVANCE", reverse=True) == [
t8,
t7,
t6,
t5,
t4,
t3,
t2,
t1,
]
# test different start offsets
assert await store.get_transactions_between(1, 1, 100, sort_key="RELEVANCE", reverse=True) == [
t7,
t6,
t5,
t4,
t3,
t2,
t1,
]
assert await store.get_transactions_between(1, 2, 100, sort_key="RELEVANCE", reverse=True) == [
t6,
t5,
t4,
t3,
t2,
t1,
]
assert await store.get_transactions_between(1, 3, 100, sort_key="RELEVANCE", reverse=True) == [
t5,
t4,
t3,
t2,
t1,
]
@pytest.mark.asyncio
async def test_get_transactions_between_to_puzzle_hash() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
ph1 = token_bytes(32)
ph2 = token_bytes(32)
tr2 = dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(1), to_puzzle_hash=ph1)
tr3 = dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(2), to_puzzle_hash=ph1)
tr4 = dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(3), to_puzzle_hash=ph2)
tr5 = dataclasses.replace(tr1, name=token_bytes(32), confirmed_at_height=uint32(4), to_puzzle_hash=ph2)
await store.add_transaction_record(tr1, False)
await store.add_transaction_record(tr2, False)
await store.add_transaction_record(tr3, False)
await store.add_transaction_record(tr4, False)
await store.add_transaction_record(tr5, False)
# test different limits
assert await store.get_transactions_between(1, 0, 100, to_puzzle_hash=ph1) == [tr2, tr3]
assert await store.get_transactions_between(1, 0, 100, to_puzzle_hash=ph2) == [tr4, tr5]
# test different start offsets
assert await store.get_transactions_between(1, 1, 100, to_puzzle_hash=ph1) == [tr3]
assert await store.get_transactions_between(1, 1, 100, to_puzzle_hash=ph2) == [tr5]
# reverse
# test different limits
assert await store.get_transactions_between(1, 0, 100, to_puzzle_hash=ph1, reverse=True) == [tr3, tr2]
assert await store.get_transactions_between(1, 0, 100, to_puzzle_hash=ph2, reverse=True) == [tr5, tr4]
# test different start offsets
assert await store.get_transactions_between(1, 1, 100, to_puzzle_hash=ph1, reverse=True) == [tr2]
assert await store.get_transactions_between(1, 1, 100, to_puzzle_hash=ph2, reverse=True) == [tr4]
@pytest.mark.asyncio
async def test_get_not_sent() -> None:
async with DBConnection1() as db_wrapper:
store = await WalletTransactionStore.create(db_wrapper)
tr2 = dataclasses.replace(tr1, name=token_bytes(32), confirmed=True, confirmed_at_height=uint32(1))
tr3 = dataclasses.replace(tr1, name=token_bytes(32))
tr4 = dataclasses.replace(tr1, name=token_bytes(32))
await store.add_transaction_record(tr1, False)
await store.add_transaction_record(tr2, False)
await store.add_transaction_record(tr3, False)
await store.add_transaction_record(tr4, False)
not_sent = await store.get_not_sent()
assert cmp(not_sent, [tr1, tr3, tr4])
not_sent = await store.get_not_sent()
assert cmp(not_sent, [tr1, tr3, tr4])
not_sent = await store.get_not_sent()
assert cmp(not_sent, [tr1, tr3, tr4])
not_sent = await store.get_not_sent()
assert cmp(not_sent, [tr1, tr3, tr4])
not_sent = await store.get_not_sent()
assert cmp(not_sent, [tr1, tr3, tr4])
# the 6th time we call this function, we don't get any unsent txs
not_sent = await store.get_not_sent()
assert cmp(not_sent, [])
# TODO: also cover include_accepted_txs=True

View File

@ -85,7 +85,7 @@ class TestWalletSimulator:
return True
await time_out_assert(20, check_tx_are_pool_farm_rewards, True)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
@pytest.mark.parametrize(
"trusted",
@ -123,7 +123,7 @@ class TestWalletSimulator:
)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds)
tx = await wallet.generate_signed_transaction(
uint64(10),
@ -132,9 +132,9 @@ class TestWalletSimulator:
)
await wallet.push_transaction(tx)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - 10)
await time_out_assert(5, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds - 10)
await time_out_assert(10, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
for i in range(0, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
@ -146,8 +146,8 @@ class TestWalletSimulator:
]
)
await time_out_assert(5, wallet.get_confirmed_balance, new_funds - 10)
await time_out_assert(5, wallet.get_unconfirmed_balance, new_funds - 10)
await time_out_assert(10, wallet.get_confirmed_balance, new_funds - 10)
await time_out_assert(10, wallet.get_unconfirmed_balance, new_funds - 10)
@pytest.mark.parametrize(
"trusted",
@ -193,7 +193,7 @@ class TestWalletSimulator:
]
)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
@pytest.mark.parametrize(
"trusted",
@ -250,7 +250,7 @@ class TestWalletSimulator:
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
)
await time_out_assert(5, wallet_0.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
await time_out_assert(10, wallet_0.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(
uint64(10), bytes32(32 * b"0"), uint64(0)
@ -435,8 +435,8 @@ class TestWalletSimulator:
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds)
assert await wallet.get_confirmed_balance() == funds
assert await wallet.get_unconfirmed_balance() == funds
@ -453,10 +453,10 @@ class TestWalletSimulator:
assert fees == tx_fee
await wallet.push_transaction(tx)
await time_out_assert(5, full_node_1.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
await time_out_assert(20, full_node_1.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - tx_amount - tx_fee)
await time_out_assert(20, wallet.get_confirmed_balance, funds)
await time_out_assert(20, wallet.get_unconfirmed_balance, funds - tx_amount - tx_fee)
for i in range(0, num_blocks):
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
@ -468,8 +468,8 @@ class TestWalletSimulator:
]
)
await time_out_assert(5, wallet.get_confirmed_balance, new_funds - tx_amount - tx_fee)
await time_out_assert(5, wallet.get_unconfirmed_balance, new_funds - tx_amount - tx_fee)
await time_out_assert(10, wallet.get_confirmed_balance, new_funds - tx_amount - tx_fee)
await time_out_assert(10, wallet.get_unconfirmed_balance, new_funds - tx_amount - tx_fee)
@pytest.mark.parametrize(
"trusted",
@ -510,7 +510,7 @@ class TestWalletSimulator:
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(20, wallet.get_confirmed_balance, funds)
primaries: List[AmountWithPuzzlehash] = []
for i in range(0, 60):
@ -615,7 +615,7 @@ class TestWalletSimulator:
)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds)
assert await wallet.get_confirmed_balance() == funds
assert await wallet.get_unconfirmed_balance() == funds
@ -658,8 +658,8 @@ class TestWalletSimulator:
)
await wallet.push_transaction(stolen_tx)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - stolen_cs.coin.amount)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds - stolen_cs.coin.amount)
for i in range(0, num_blocks):
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
@ -718,14 +718,14 @@ class TestWalletSimulator:
assert tx.spend_bundle is not None
await wallet.push_transaction(tx)
await full_node_api.full_node.respond_transaction(tx.spend_bundle, tx.name)
await time_out_assert(5, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(10, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
for i in range(0, 2):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
await time_out_assert(5, wallet_2.get_confirmed_balance, 1000)
await time_out_assert(10, wallet_2.get_confirmed_balance, 1000)
funds -= 1000
await time_out_assert(5, wallet_node.wallet_state_manager.blockchain.get_peak_height, 7)
await time_out_assert(10, wallet_node.wallet_state_manager.blockchain.get_peak_height, 7)
peak = full_node_api.full_node.blockchain.get_peak()
assert peak is not None
peak_height = peak.height
@ -743,8 +743,8 @@ class TestWalletSimulator:
]
)
await time_out_assert(7, full_node_api.full_node.blockchain.get_peak_height, peak_height + 3)
await time_out_assert(7, wallet_node.wallet_state_manager.blockchain.get_peak_height, peak_height + 3)
await time_out_assert(20, full_node_api.full_node.blockchain.get_peak_height, peak_height + 3)
await time_out_assert(20, wallet_node.wallet_state_manager.blockchain.get_peak_height, peak_height + 3)
# Farm a few blocks so we can confirm the resubmitted transaction
for i in range(0, num_blocks):
@ -864,8 +864,8 @@ class TestWalletSimulator:
]
)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds)
AMOUNT_TO_SEND = 4000000000000
coins = await wallet.select_coins(uint64(AMOUNT_TO_SEND))
@ -883,12 +883,12 @@ class TestWalletSimulator:
assert paid_coin.parent_coin_info == coin_list[2].name()
await wallet.push_transaction(tx)
await time_out_assert(5, wallet.get_confirmed_balance, funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - AMOUNT_TO_SEND)
await time_out_assert(5, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
await time_out_assert(10, wallet.get_confirmed_balance, funds)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds - AMOUNT_TO_SEND)
await time_out_assert(10, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
for i in range(0, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32([0] * 32)))
await time_out_assert(5, wallet.get_confirmed_balance, funds - AMOUNT_TO_SEND)
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - AMOUNT_TO_SEND)
await time_out_assert(10, wallet.get_confirmed_balance, funds - AMOUNT_TO_SEND)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds - AMOUNT_TO_SEND)