27 Commits

Author SHA1 Message Date
ardocrat eaefc58c5a wallet: fix scan 2026-05-13 17:38:07 +03:00
ardocrat 2519e68dd5 ci: build checkout submodules 2026-05-13 17:37:45 +03:00
ardocrat 73c0884f95 ci: macos runner 2026-05-08 00:10:14 +03:00
ardocrat f7b2150228 wallet: parse slatepack message at background thread 2026-05-04 14:10:52 +03:00
ardocrat 03924b5300 build: remove unused cpp flags for android 2026-05-04 01:31:35 +03:00
ardocrat a479189135 tx: show message input after copy/share if finalization is needed 2026-05-03 23:34:45 +03:00
ardocrat e691a7b02d ci: fix changelog, update wix upgradecode on every build 2026-05-03 23:05:26 +03:00
ardocrat f2b79cd70d build: add rustfmt hook and config 2026-05-03 10:05:03 +03:00
ardocrat f20d1ee2c2 node: use git hash for user agent 2026-05-02 23:34:42 +03:00
ardocrat 534c4cc86a node: update user-agent, include last fixes for peers from PRs 2026-05-01 12:50:50 +03:00
ardocrat 558ac034b2 txs: fix save with new lmdb, sort to show new on top 2026-05-01 11:42:35 +03:00
ardocrat 13bf8e830c node: reset data from settings 2026-05-01 02:18:47 +03:00
ardocrat 57f319edfc android: include application mime type 2026-04-30 20:36:42 +03:00
ardocrat 748aebffb6 ci: release runner for version and forgejo release 2026-04-30 20:16:12 +03:00
ardocrat b32085a423 node + wallet: update lmdb 2026-04-30 18:27:27 +03:00
ardocrat a9c65546e3 node: update default dns seeds, setup seeds for testnet on launch 2026-04-30 14:14:51 +03:00
ardocrat b94241b82a wallet: select external connection by default on creation if integrated node is not running 2026-04-30 13:53:44 +03:00
ardocrat 8a1a69b739 node: update seeds 2026-04-24 01:14:16 +03:00
ardocrat 01d17e25ee tor: update webtunnel list 2026-04-24 00:12:22 +03:00
ardocrat cab38097fa build: v0.3.5 2026-04-21 13:13:28 +03:00
ardocrat 0026fc3717 build: fix android no_mangle attributes for rust 2024 2026-04-11 23:12:56 +03:00
ardocrat 0fd04f14a4 wallet: save last scanned block info to save progress on scan interruption 2026-04-11 22:52:43 +03:00
ardocrat 3338f51de5 tor: update to arti 0.41 2026-04-11 00:33:41 +03:00
ardocrat 0fa8963bd2 fix: wallet txs selection, wait starting tor service on send 2026-04-10 15:50:58 +03:00
ardocrat 70bba5d7ce pull_to_refresh: refresh when dragged far enough without release 2026-04-10 15:38:43 +03:00
ardocrat 0bb43e1e5d ui: show loader when fee is calculating 2026-04-10 15:18:23 +03:00
ardocrat fd52757549 build: version 0.3.4 2026-04-10 15:09:41 +03:00
39 changed files with 850 additions and 697 deletions
+4 -2
View File
@@ -13,8 +13,10 @@ jobs:
runs-on: ubuntu
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Checkout submodules
run: |
sed -i 's#https://code\.gri\.mw#${{ secrets.REPO_HOST }}#g' .gitmodules
git submodule update --init
- name: Check commit
id: check
run: |
+112 -92
View File
@@ -10,7 +10,7 @@ on:
jobs:
version:
runs-on: ubuntu
runs-on: debian-release
outputs:
v: ${{ steps.version.outputs.v }}
pre: ${{ steps.version.outputs.pre }}
@@ -18,8 +18,10 @@ jobs:
last_tag: ${{ steps.check_prev.outputs.last_tag }}
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Checkout submodules
run: |
sed -i 's#https://code\.gri\.mw#${{ secrets.REPO_HOST }}#g' .gitmodules
git submodule update --init
- name: Get version
id: version
run: |
@@ -52,6 +54,18 @@ jobs:
if: ${{ forgejo.ref_type == 'tag' && steps.check.outputs.exists == 'true' }}
working-directory: release
run: for f in *; do mv "$f" "$(echo "$f" | sed s/-dev-/-/)"; done
- name: Delete dev release
if: ${{ forgejo.ref_type == 'tag' && steps.check.outputs.exists == 'true' }}
uses: actions/delete-release@v1
with:
release_name: "${{ forgejo.ref_name }}-dev"
- name: Check previous release
id: check_prev
run: |
git fetch --tags
[[ ${{ forgejo.ref_type }} == 'tag' ]] && skip=0 || skip=1
last_tag=$(git describe --abbrev=0 --tags $(git rev-list --tags --skip=${skip} --max-count=1)) || true
echo "last_tag=${last_tag}" >> "$FORGEJO_OUTPUT"
- uses: actions/forgejo-release@v2.11.3
if: ${{ forgejo.ref_type == 'tag' && steps.check.outputs.exists == 'true' }}
with:
@@ -62,26 +76,17 @@ jobs:
prerelease: false
release-dir: ./release
release-notes: "Full Changelog: [${{ steps.check_prev.outputs.last_tag }}...${{ steps.version.outputs.v }}](https://code.gri.mw/${{ forgejo.repository }}/compare/${{ steps.check_prev.outputs.last_tag }}...${{ steps.version.outputs.v }})"
- name: Delete dev release
if: ${{ forgejo.ref_type == 'tag' && steps.check.outputs.exists == 'true' }}
uses: actions/delete-release@v1
with:
release_name: "${{ forgejo.ref_name }}-dev"
- name: Check previous release
id: check_prev
run: |
git fetch --tags
last_tag=$(git describe --abbrev=0 --tags $(git rev-list --tags --skip=1 --max-count=1))
echo "last_tag=${last_tag}" >> "$FORGEJO_OUTPUT"
android_libs:
android:
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
runs-on: ubuntu
runs-on: macos
needs: version
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Checkout submodules
run: |
sed -i -- 's#https://code\.gri\.mw#${{ secrets.REPO_HOST }}#g' .gitmodules
git submodule update --init
- name: Restore cargo cache
id: cache-cargo-restore
uses: actions/cache/restore@v5
@@ -93,11 +98,9 @@ jobs:
~/.cargo/git/db/
target/
key: grim-android-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Setup registry
run: |
echo -e '[registries.nexus]\nindex = "sparse+${{ secrets.MAVEN_HOST }}/repository/cargo/"\n[registry]\ndefault = "nexus"\n[source.crates-io]\nreplace-with = "nexus"\n[source.nexus]\nregistry = "sparse+${{ secrets.MAVEN_HOST }}/repository/cargo/"' > ~/.cargo/config.toml
- name: Build libs
run: |
rustup -q update
chmod +x scripts/android.sh && ./scripts/android.sh lib ${{ needs.version.outputs.v }}
- name: Save cargo cache
uses: actions/cache/save@v5
@@ -109,20 +112,6 @@ jobs:
~/.cargo/git/db/
target/
key: ${{ steps.cache-cargo-restore.outputs.cache-primary-key }}
- name: Upload artifacts
run: |
cd android/app/src/main
tar -czf jniLibs.tar.gz jniLibs
curl -v -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file jniLibs.tar.gz ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/jniLibs.tar.gz
android_release:
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
runs-on: ubuntu-android
needs: [version, android_libs]
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Restore gradle cache
id: cache-gradle-restore
uses: actions/cache/restore@v5
@@ -133,23 +122,17 @@ jobs:
key: grim-android-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Download artifacts
run: |
cd android/app/src/main
curl -o jniLibs.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/jniLibs.tar.gz
tar -xzf jniLibs.tar.gz
rm jniLibs.tar.gz
- name: Setup build
run: |
chmod +x android/gradlew
echo "${{ secrets.ANDROID_KEYSTORE }}" > release.keystore.txt
base64 -d release.keystore.txt > android/keystore
base64 -d < release.keystore.txt -o android/keystore
echo "${{ secrets.ANDROID_KEYSTORE_PROPS }}" > release.keystore.props.txt
base64 -d release.keystore.props.txt > android/keystore.properties
base64 -d < release.keystore.props.txt -o android/keystore.properties
mkdir ~/.gradle && touch ~/.gradle/gradle.properties
printf "mavenHost=${{ secrets.MAVEN_HOST }}\n" >> ~/.gradle/gradle.properties
printf "mavenHost=${{ secrets.MAVEN_LOCAL_HOST }}\n" >> ~/.gradle/gradle.properties
printf "mavenUser=${{ secrets.MAVEN_USER }}\n" >> ~/.gradle/gradle.properties
printf "mavenPassword=${{ secrets.MAVEN_PASSWORD }}" >> ~/.gradle/gradle.properties
printf "mavenPassword=${{ secrets.MAVEN_PASSWORD }}" >> ~/.gradle/gradle.properties
- name: Release ARMv7+v8 APK
working-directory: android
run: |
@@ -194,16 +177,18 @@ jobs:
mkdir release
mv android/grim* release
tar -czf android.tar.gz release
curl -v -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file android.tar.gz ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/android.tar.gz
curl -s -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file android.tar.gz ${{ secrets.MAVEN_LOCAL_HOST }}/repository/grim-ci/${{ forgejo.repository }}/android.tar.gz
linux_arm:
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
runs-on: ubuntu
needs: [version, android_libs]
runs-on: debian-rust-arm
needs: [version]
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Checkout submodules
run: |
sed -i 's#https://code\.gri\.mw#${{ secrets.REPO_HOST }}#g' .gitmodules
git submodule update --init
- name: Restore cargo cache
id: cache-cargo-restore
uses: actions/cache/restore@v5
@@ -217,9 +202,11 @@ jobs:
key: grim-linux-arm-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Setup registry
run: |
echo -e '[registries.nexus]\nindex = "sparse+${{ secrets.MAVEN_HOST }}/repository/cargo/"\n[registry]\ndefault = "nexus"\n[source.crates-io]\nreplace-with = "nexus"\n[source.nexus]\nregistry = "sparse+${{ secrets.MAVEN_HOST }}/repository/cargo/"' > ~/.cargo/config.toml
echo -e '[registries.nexus]\nindex = "sparse+${{ secrets.MAVEN_LOCAL_HOST }}/repository/cargo/"\n[registry]\ndefault = "nexus"\n[source.crates-io]\nreplace-with = "nexus"\n[source.nexus]\nregistry = "sparse+${{ secrets.MAVEN_LOCAL_HOST }}/repository/cargo/"' > ~/.cargo/config.toml
- name: Release Linux ARM
run: cargo zigbuild --release --target aarch64-unknown-linux-gnu
run: |
rustup -q update
cargo zigbuild --release --target aarch64-unknown-linux-gnu
- name: Save cargo cache
uses: actions/cache/save@v5
with:
@@ -230,28 +217,45 @@ jobs:
~/.cargo/git/db/
target/
key: ${{ steps.cache-cargo-restore.outputs.cache-primary-key }}
- name: AppImage ARM
- name: Upload artifacts
run: |
curl -s -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file target/aarch64-unknown-linux-gnu/release/grim ${{ secrets.MAVEN_LOCAL_HOST }}/repository/grim-ci/${{ forgejo.repository }}/grim-linux-arm
linux_arm_appimage:
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
runs-on: debian-arm
needs: [version, linux_arm]
steps:
- uses: actions/checkout@v6
- name: Download Artifact
run: |
wget ${{ secrets.MAVEN_LOCAL_HOST }}/repository/grim-ci/${{ forgejo.repository }}/grim-linux-arm
- name: AppImage
shell: bash
run: |
mkdir release
cp target/aarch64-unknown-linux-gnu/release/grim linux/Grim.AppDir/AppRun
appimagetool linux/Grim.AppDir grim-${{ needs.version.outputs.v }}-linux-arm.AppImage
cp grim-${{ needs.version.outputs.v }}-linux-arm.AppImage release/
chmod +x grim-linux-arm
mv grim-linux-arm linux/Grim.AppDir/AppRun
ARCH=aarch64 appimagetool linux/Grim.AppDir grim-${{ needs.version.outputs.v }}-linux-arm.AppImage
mv grim-${{ needs.version.outputs.v }}-linux-arm.AppImage release/
- name: Checksum AppImage ARM
working-directory: release
run: sha256sum grim-${{ needs.version.outputs.v }}-linux-arm.AppImage > grim-${{ needs.version.outputs.v }}-linux-arm-appimage-sha256sum.txt
- name: Upload artifacts
run: |
tar -czf linux-arm.tar.gz release
curl -v -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file linux-arm.tar.gz ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/linux-arm.tar.gz
tar -czf linux-arm.appimage.tar.gz release
curl -s -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file linux-arm.appimage.tar.gz ${{ secrets.MAVEN_LOCAL_HOST }}/repository/grim-ci/${{ forgejo.repository }}/linux-arm.appimage.tar.gz
linux_x86:
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
runs-on: ubuntu-linux-x86
runs-on: debian-rust-x86_64
needs: [version]
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Checkout submodules
run: |
sed -i 's#https://code\.gri\.mw#${{ secrets.REPO_HOST }}#g' .gitmodules
git submodule update --init
- name: Restore cargo cache
id: cache-cargo-restore
uses: actions/cache/restore@v5
@@ -262,12 +266,14 @@ jobs:
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: grim-linux-x86-cargo-${{ hashFiles('**/Cargo.lock') }}
key: grim-linux-arm-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Setup registry
run: |
echo -e '[registries.nexus]\nindex = "sparse+${{ secrets.MAVEN_HOST }}/repository/cargo/"\n[registry]\ndefault = "nexus"\n[source.crates-io]\nreplace-with = "nexus"\n[source.nexus]\nregistry = "sparse+${{ secrets.MAVEN_HOST }}/repository/cargo/"' > ~/.cargo/config.toml
echo -e '[registries.nexus]\nindex = "sparse+${{ secrets.MAVEN_LOCAL_HOST }}/repository/cargo/"\n[registry]\ndefault = "nexus"\n[source.crates-io]\nreplace-with = "nexus"\n[source.nexus]\nregistry = "sparse+${{ secrets.MAVEN_LOCAL_HOST }}/repository/cargo/"' > ~/.cargo/config.toml
- name: Release Linux x86
run: cargo zigbuild --release --target x86_64-unknown-linux-gnu
run: |
rustup -q update
cargo zigbuild --release --target x86_64-unknown-linux-gnu
- name: Save cargo cache
uses: actions/cache/save@v5
with:
@@ -281,25 +287,27 @@ jobs:
- name: AppImage x86
run: |
mkdir release
cp target/x86_64-unknown-linux-gnu/release/grim linux/Grim.AppDir/AppRun
mv target/x86_64-unknown-linux-gnu/release/grim linux/Grim.AppDir/AppRun
appimagetool linux/Grim.AppDir grim-${{ needs.version.outputs.v }}-linux-x86_64.AppImage
cp grim-${{ needs.version.outputs.v }}-linux-x86_64.AppImage release/
mv grim-${{ needs.version.outputs.v }}-linux-x86_64.AppImage release/
- name: Checksum AppImage x86
working-directory: release
run: sha256sum grim-${{ needs.version.outputs.v }}-linux-x86_64.AppImage > grim-${{ needs.version.outputs.v }}-linux-x86_64-appimage-sha256sum.txt
- name: Upload artifacts
run: |
tar -czf linux-x86_64.tar.gz release
curl -v -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file linux-x86_64.tar.gz ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/linux-x86_64.tar.gz
tar -czf linux-x86_64.appimage.tar.gz release
curl -s -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file linux-x86_64.appimage.tar.gz ${{ secrets.MAVEN_LOCAL_HOST }}/repository/grim-ci/${{ forgejo.repository }}/linux-x86_64.appimage.tar.gz
macos:
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
runs-on: ubuntu
needs: [version, android_libs, linux]
runs-on: macos
needs: [version, android]
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Checkout submodules
run: |
sed -i -- 's#https://code\.gri\.mw#${{ secrets.REPO_HOST }}#g' .gitmodules
git submodule update --init
- run: mkdir release
- name: Restore cargo cache
id: cache-cargo-restore
@@ -312,13 +320,14 @@ jobs:
~/.cargo/git/db/
target/
key: grim-macos-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Setup registry
run: |
echo -e '[registries.nexus]\nindex = "sparse+${{ secrets.MAVEN_HOST }}/repository/cargo/"\n[registry]\ndefault = "nexus"\n[source.crates-io]\nreplace-with = "nexus"\n[source.nexus]\nregistry = "sparse+${{ secrets.MAVEN_HOST }}/repository/cargo/"' > ~/.cargo/config.toml
- name: Release MacOS Universal
run: |
cargo zigbuild --release --target universal2-apple-darwin
cp target/universal2-apple-darwin/release/grim macos/Grim.app/Contents/MacOS
rustup -q update
export MACOSX_DEPLOYMENT_TARGET=11.0
cargo build --release --target x86_64-apple-darwin
cargo build --release --target aarch64-apple-darwin
lipo -create -output grim "target/x86_64-apple-darwin/release/grim" "target/aarch64-apple-darwin/release/grim"
mv grim macos/Grim.app/Contents/MacOS
- name: Save cargo cache
uses: actions/cache/save@v5
with:
@@ -340,7 +349,7 @@ jobs:
- name: Upload artifacts
run: |
tar -czf macos.tar.gz release
curl -v -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file macos.tar.gz ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/macos.tar.gz
curl -s -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file macos.tar.gz ${{ secrets.MAVEN_LOCAL_HOST }}/repository/grim-ci/${{ forgejo.repository }}/macos.tar.gz
windows:
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
@@ -348,11 +357,22 @@ jobs:
needs: [version]
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Checkout submodules
run: |
(Get-content .gitmodules) | Foreach-Object {$_ -replace "https://code.gri.mw", "${{ secrets.REPO_HOST }}"} | Set-Content .gitmodules
git submodule update --init
- name: Update UpgradeCode
shell: powershell
run: |
$guid = [guid]::NewGuid().ToString()
$wix = [xml](Get-Content wix/main.wxs)
$wix.Wix.Product.UpgradeCode = $guid
$wix.Save("wix/main.wxs")
Get-Content wix/main.wxs
- run: mkdir release
- name: Release Windows x86
run: |
rustup -q update
cargo wix -p grim -o grim-${{ needs.version.outputs.v }}-win-x86_64.msi --nocapture
mv grim-${{ needs.version.outputs.v }}-win-x86_64.msi release\
Compress-Archive -Path target\release\grim.exe -DestinationPath grim-${{ needs.version.outputs.v }}-win-x86_64.zip
@@ -366,28 +386,28 @@ jobs:
run: |
tar -czf windows.tar.gz release
Remove-Item alias:curl
curl -v -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file windows.tar.gz ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/windows.tar.gz
curl -s -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} --upload-file windows.tar.gz ${{ secrets.MAVEN_LOCAL_HOST }}/repository/grim-ci/${{ forgejo.repository }}/windows.tar.gz
release:
if: ${{ forgejo.ref_type == 'branch' || needs.version.outputs.exists == 'false' }}
runs-on: ubuntu
needs: [version, android_release, linux, linux_x86, macos, windows]
runs-on: debian-release
needs: [version, android, linux_x86, linux_arm_appimage, macos, windows]
steps:
- name: Download All Artifacts
run: |
curl -o android.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/android.tar.gz
curl -s -o android.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci/${{ forgejo.repository }}/android.tar.gz
tar -xzf android.tar.gz
rm android.tar.gz
curl -o linux-arm.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/linux-arm.tar.gz
tar -xzf linux-arm.tar.gz
rm linux-arm.tar.gz
curl -o linux-x86_64.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/linux-x86_64.tar.gz
tar -xzf linux-x86_64.tar.gz
rm linux-x86_64.tar.gz
curl -o macos.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/macos.tar.gz
curl -s -o linux-x86_64.appimage.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci/${{ forgejo.repository }}/linux-x86_64.appimage.tar.gz
tar -xzf linux-x86_64.appimage.tar.gz
rm linux-x86_64.appimage.tar.gz
curl -s -o linux-arm.appimage.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci/${{ forgejo.repository }}/linux-arm.appimage.tar.gz
tar -xzf linux-arm.appimage.tar.gz
rm linux-arm.appimage.tar.gz
curl -s -o macos.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci/${{ forgejo.repository }}/macos.tar.gz
tar -xzf macos.tar.gz
rm macos.tar.gz
curl -o windows.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci-artifacts/${{ forgejo.repository }}/windows.tar.gz
curl -s -o windows.tar.gz -u ${{ secrets.MAVEN_USER }}:${{ secrets.MAVEN_PASSWORD }} ${{ secrets.MAVEN_HOST }}/repository/grim-ci/${{ forgejo.repository }}/windows.tar.gz
tar -xzf windows.tar.gz
rm windows.tar.gz
- name: Upload release to Forgejo
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Copyright 2026 The Grim Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
rustfmt --version &>/dev/null
if [ $? != 0 ]; then
printf "[pre_commit] \033[0;31merror\033[0m: \"rustfmt\" not available. \n"
printf "[pre_commit] \033[0;31merror\033[0m: rustfmt can be installed via - \n"
printf "[pre_commit] $ rustup component add rustfmt-preview \n"
exit 1
fi
problem_files=()
# first collect all the files that need reformatting
for file in $(git diff --name-only --cached); do
if [ ${file: -3} == ".rs" ]; then
rustfmt --check $file &>/dev/null
if [ $? != 0 ]; then
problem_files+=($file)
fi
fi
done
if [ ${#problem_files[@]} == 0 ]; then
# nothing to do
printf "[pre_commit] rustfmt \033[0;32mok\033[0m \n"
else
# reformat the files that need it and re-stage them.
printf "[pre_commit] the following files were rustfmt'd before commit: \n"
for file in ${problem_files[@]}; do
rustfmt $file
git add $file
printf "\033[0;32m $file\033[0m \n"
done
fi
exit 0
Generated
+369 -345
View File
File diff suppressed because it is too large Load Diff
+13 -13
View File
@@ -1,12 +1,12 @@
[package]
name = "grim"
version = "0.3.3"
version = "0.3.5"
authors = ["Ardocrat <ardocrat@gri.mw>"]
description = "Cross-platform GUI for Grin with focus on usability and availability to be used by anyone, anywhere."
license = "Apache-2.0"
repository = "https://code.gri.mw/GUI/grim"
keywords = [ "crypto", "grin", "mimblewimble" ]
edition = "2021"
edition = "2024"
build = "build.rs"
[[bin]]
@@ -92,23 +92,23 @@ uuid = { version = "0.8.2", features = ["v4"] }
num-bigint = "0.4.6"
## tor
arti-client = { version = "0.38.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client", "experimental-api", "bridge-client"] }
tor-rtcompat = { version = "0.38.0", features = ["static"] }
tor-config = "0.38.0"
fs-mistrust = "0.13.1"
tor-hsservice = "0.38.0"
tor-hsrproxy = "0.38.0"
tor-keymgr = "0.38.0"
tor-llcrypto = "0.38.0"
tor-hscrypto = "0.38.0"
tor-error = "0.38.0"
arti-client = { version = "0.41.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client", "experimental-api", "bridge-client"] }
tor-rtcompat = { version = "0.41.0", features = ["static"] }
tor-config = "0.41.0"
fs-mistrust = "0.14.1"
tor-hsservice = "0.41.0"
tor-hsrproxy = "0.41.0"
tor-keymgr = "0.41.0"
tor-llcrypto = "0.41.0"
tor-hscrypto = "0.41.0"
tor-error = "0.41.0"
sha2 = "0.10.8"
ed25519-dalek = "2.1.1"
curve25519-dalek = "4.1.3"
hyper-tor = { version = "0.14.32", features = ["full"], package = "hyper" }
tls-api = "0.12.0"
tls-api-native-tls = "0.12.1"
safelog = "0.7.0"
safelog = "0.8.1"
## stratum server
tokio-old = { version = "0.2", features = ["full"], package = "tokio" }
+1 -1
View File
@@ -12,7 +12,7 @@ android {
minSdk 24
targetSdk 36
versionCode 5
versionName "0.3.3"
versionName "0.3.5"
}
lint {
+1
View File
@@ -54,6 +54,7 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/*" />
<data android:mimeType="application/*" />
<data android:pathPattern=".*\\.slatepack" />
</intent-filter>
+2 -2
View File
@@ -300,8 +300,8 @@ network_settings:
ban_window_desc: Die Entscheidung über das Verbot trifft der Knoten auf der Grundlage der Korrektheit der von der Gegenstelle erhaltenen Daten.
max_inbound_count: 'Maximale Anzahl der eingehenden Peer-Verbindungen:'
max_outbound_count: 'Maximale Anzahl von ausgehenden Peer-Verbindungen:'
reset_peers_desc: Peer-Daten zurücksetzen. Verwenden Sie diese Funktion nur, wenn es Probleme beim finden von Peers gibt.
reset_peers: Peers zurücksetzten
reset_data_desc: Reset-Knotendaten. Verwenden Sie diese Funktion nur, wenn es Probleme mit der Synchronisation gibt.
reset_data: Daten zurücksetzten
modal:
cancel: Abbrechen
save: Speichern
+2 -2
View File
@@ -300,8 +300,8 @@ network_settings:
ban_window_desc: The decision to ban is made by node, based on the correctness of the data received from the peer.
max_inbound_count: 'Maximum number of inbound peer connections:'
max_outbound_count: 'Maximum number of outbound peer connections:'
reset_peers_desc: Reset peers data. Use it with a caution only if there are problems with finding peers.
reset_peers: Reset peers
reset_data_desc: Reset the node data. Use it with a caution only if there are problems with synchronization.
reset_data: Reset data
modal:
cancel: Cancel
save: Save
+2 -2
View File
@@ -300,8 +300,8 @@ network_settings:
ban_window_desc: La décision de bannir est prise par le noeud, en fonction de la validité des données reçues du pair.
max_inbound_count: 'Nombre maximum de connexions de pairs entrants :'
max_outbound_count: 'Nombre maximum de connexions de pairs sortants :'
reset_peers_desc: Réinitialiser les données des pairs. Utilisez-le avec précaution uniquement en cas de problèmes pour trouver des pairs.
reset_peers: Réinitialiser les pairs
reset_data_desc: Réinitialisez les données du noeud. Utilisez-le avec prudence uniquement en cas de problème de synchronisation.
reset_data: Réinitialisation des données
modal:
cancel: Annuler
save: Sauvegarder
+2 -2
View File
@@ -300,8 +300,8 @@ network_settings:
ban_window_desc: Решение о запрете принимается узлом, основываясь на корректности данных полученных от пира.
max_inbound_count: 'Максимальное количество входящих подключений пиров:'
max_outbound_count: 'Максимальное количество исходящих подключений к пирам:'
reset_peers_desc: Сбросить данные пиров. Используйте с осторожностью, только при наличии проблем с поиском пиров.
reset_peers: Сбросить пиры
reset_data_desc: Сбросить данные узла. Используйте с осторожностью, только при наличии проблем с синхронизацией.
reset_data: Сброс данных
modal:
cancel: Отмена
save: Сохранить
+2 -2
View File
@@ -300,8 +300,8 @@ network_settings:
ban_window_desc: Banlama karari, peerden alinan verilerin dogruluguna bagli olarak Node tarafindan verilir.
max_inbound_count: 'Maksimum gelen Peer baglanti sayisi:'
max_outbound_count: 'Maksimum giden Peer baglanti sayisi:'
reset_peers_desc: Peers verilerini sifirlayin. Yalnizca Peers bulma konusunda sorun yasiyorsaniz dikkatli kullanin.
reset_peers: Peers Resetle
reset_data_desc: Node verisini sifirlama. Sadece senkronizasyonda sorun varsa dikkatli kullanin.
reset_data: Verileri sifirlama
modal:
cancel: Iptal
save: Kaydet
+2 -2
View File
@@ -300,8 +300,8 @@ network_settings:
ban_window_desc: 禁止的决定是由节点 根据从网络对点收到的数据的正确性做出的.
max_inbound_count: '入站网络对点连接的最大数量:'
max_outbound_count: '最大出站网络对点连接数:'
reset_peers_desc: 重置网络对点数据。仅当查找网络对点出现问题时,才请谨慎使用.
reset_peers: 重置网络对点
reset_data_desc: 重置点数据。只有在出现同步问题时才需谨慎使用.
reset_data: 重置数据
modal:
cancel: 取消
save: 保存
+1 -1
View File
@@ -21,7 +21,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.3.3</string>
<string>0.3.5</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
+1 -1
Submodule node updated: 42b928a42f...3a37d24dca
+2
View File
@@ -0,0 +1,2 @@
hard_tabs = true
edition = "2024"
-3
View File
@@ -41,13 +41,10 @@ function build_lib() {
sed -i -e 's/"cdylib","rlib"]/"rlib"]/g' Cargo.toml
sed -i -e 's/"rlib"]/"cdylib","rlib"]/g' Cargo.toml
# Fix for https://stackoverflow.com/questions/57193895/error-use-of-undeclared-identifier-pthread-mutex-robust-cargo-build-liblmdb-s
export CPPFLAGS="-DMDB_USE_ROBUST=0" && export CFLAGS="-DMDB_USE_ROBUST=0"
cargo ndk -t "${arch}" -o android/app/src/main/jniLibs build --profile release-apk
if [ $? -ne 0 ]; then
success=0
fi
unset CPPFLAGS && unset CFLAGS
sed -i -e 's/"cdylib","rlib"]/"rlib"]/g' Cargo.toml
rm -f Cargo.toml-e
+1 -1
View File
@@ -418,7 +418,7 @@ impl<Platform: PlatformCallbacks> eframe::App for App<Platform> {
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Handle Back key code event from Android.
pub extern "C" fn Java_mw_gri_android_MainActivity_onBack(
_env: jni::JNIEnv,
+2 -2
View File
@@ -203,7 +203,7 @@ lazy_static! {
/// Callback from Java code with last entered character from soft keyboard.
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
pub extern "C" fn Java_mw_gri_android_MainActivity_onCameraImage(
env: JNIEnv,
_class: JObject,
@@ -218,7 +218,7 @@ pub extern "C" fn Java_mw_gri_android_MainActivity_onCameraImage(
/// Callback from Java code with picked file path.
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
pub extern "C" fn Java_mw_gri_android_MainActivity_onFilePick(
_env: JNIEnv,
_class: JObject,
+3 -3
View File
@@ -404,7 +404,7 @@ lazy_static! {
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Callback from Java code with last entered character from soft keyboard.
pub extern "C" fn Java_mw_gri_android_MainActivity_onTextInput(
_env: jni::JNIEnv,
@@ -429,7 +429,7 @@ pub extern "C" fn Java_mw_gri_android_MainActivity_onTextInput(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Callback from Java code when Clear key was pressed at soft keyboard.
pub extern "C" fn Java_mw_gri_android_MainActivity_onClearInput(
_env: jni::JNIEnv,
@@ -442,7 +442,7 @@ pub extern "C" fn Java_mw_gri_android_MainActivity_onClearInput(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Callback from Java code when Enter key was pressed at soft keyboard.
pub extern "C" fn Java_mw_gri_android_MainActivity_onEnterInput(
_env: jni::JNIEnv,
+56 -27
View File
@@ -16,7 +16,7 @@ use egui::{RichText, ScrollArea};
use egui::scroll_area::ScrollBarVisibility;
use crate::gui::Colors;
use crate::gui::icons::ARROW_COUNTER_CLOCKWISE;
use crate::gui::icons::{ARROW_COUNTER_CLOCKWISE, TRASH};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, Content, View};
use crate::gui::views::network::setup::{DandelionSetup, NodeSetup, P2PSetup, PoolSetup, StratumSetup};
@@ -36,6 +36,9 @@ pub struct NetworkSettings {
pool: PoolSetup,
/// Dandelion server setup content.
dandelion: DandelionSetup,
/// Flag to check if reset of data was called.
data_reset: bool,
}
/// Identifier for settings reset confirmation [`Modal`].
@@ -49,6 +52,7 @@ impl Default for NetworkSettings {
stratum: StratumSetup::default(),
pool: PoolSetup::default(),
dandelion: DandelionSetup::default(),
data_reset: false,
}
}
}
@@ -110,6 +114,15 @@ impl ContentContainer for NetworkSettings {
// Draw Dandelion server setup section.
self.dandelion.ui(ui, cb);
// Draw content to reset the data.
if !Node::is_restarting() && !self.data_reset {
ui.add_space(4.0);
View::horizontal_line(ui, Colors::item_stroke());
ui.add_space(6.0);
self.reset_data_ui(ui);
}
ui.add_space(6.0);
View::horizontal_line(ui, Colors::stroke());
ui.add_space(6.0);
@@ -179,7 +192,7 @@ impl NetworkSettings {
}).collect::<Vec<_>>();
if saved_ip != selected_ip {
(on_change)(&selected_ip.to_string());
on_change(&selected_ip.to_string());
}
}
@@ -193,37 +206,53 @@ impl NetworkSettings {
ui.add_space(6.0);
});
}
/// Draw content to reset data.
fn reset_data_ui(&mut self, ui: &mut egui::Ui) {
ui.add_space(4.0);
View::colored_text_button(ui,
format!("{} {}", TRASH, t!("network_settings.reset_data")),
Colors::red(),
Colors::white_or_black(false), || {
Node::reset_data(false);
self.data_reset = true;
});
ui.add_space(6.0);
ui.label(RichText::new(t!("network_settings.reset_data_desc"))
.size(16.0)
.color(Colors::inactive_text())
);
ui.add_space(4.0);
}
}
/// Draw button to reset integrated node settings to default values.
fn reset_settings_ui(ui: &mut egui::Ui) {
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network_settings.reset_settings_desc"))
.size(16.0)
.color(Colors::text(false)));
ui.add_space(8.0);
let button_text = format!("{} {}",
ARROW_COUNTER_CLOCKWISE,
t!("network_settings.reset_settings"));
View::action_button(ui, button_text, || {
// Show modal to confirm settings reset.
Modal::new(RESET_SETTINGS_CONFIRMATION_MODAL)
.position(ModalPosition::Center)
.title(t!("confirmation"))
.show();
});
// Show reminder to restart enabled node.
if Node::is_running() {
ui.add_space(12.0);
ui.label(RichText::new(t!("network_settings.restart_node_required"))
.size(16.0)
.color(Colors::gray())
);
}
ui.add_space(12.0);
ui.label(RichText::new(t!("network_settings.reset_settings_desc"))
.size(16.0)
.color(Colors::text(false)));
ui.add_space(8.0);
let button_text = format!("{} {}",
ARROW_COUNTER_CLOCKWISE,
t!("network_settings.reset_settings"));
View::action_button(ui, button_text, || {
// Show modal to confirm settings reset.
Modal::new(RESET_SETTINGS_CONFIRMATION_MODAL)
.position(ModalPosition::Center)
.title(t!("confirmation"))
.show();
});
// Show reminder to restart enabled node.
if Node::is_running() {
ui.add_space(12.0);
ui.label(RichText::new(t!("network_settings.restart_node_required"))
.size(16.0)
.color(Colors::gray())
);
}
ui.add_space(10.0);
}
/// Confirmation to reset settings to default values.
-30
View File
@@ -65,9 +65,6 @@ pub struct P2PSetup {
/// Maximum number of outbound peer connections.
max_outbound_count: String,
/// Flag to check if reset of peers was called.
peers_reset: bool,
}
/// Identifier for port value [`Modal`].
@@ -111,7 +108,6 @@ impl Default for P2PSetup {
ban_window_edit: NodeConfig::get_p2p_ban_window(),
max_inbound_count: NodeConfig::get_max_inbound_peers(),
max_outbound_count: NodeConfig::get_max_outbound_peers(),
peers_reset: false,
}
}
}
@@ -216,15 +212,6 @@ impl ContentContainer for P2PSetup {
// Show maximum outbound peers value setup.
self.max_outbound_ui(ui);
if !Node::is_restarting() && !self.peers_reset {
ui.add_space(6.0);
View::horizontal_line(ui, Colors::item_stroke());
ui.add_space(6.0);
// Show peers data reset content.
self.reset_peers_ui(ui);
}
});
}
}
@@ -753,23 +740,6 @@ impl P2PSetup {
ui.add_space(6.0);
});
}
/// Draw content to reset peers data.
fn reset_peers_ui(&mut self, ui: &mut egui::Ui) {
ui.add_space(4.0);
View::colored_text_button(ui,
format!("{} {}", TRASH, t!("network_settings.reset_peers")),
Colors::red(),
Colors::white_or_black(false), || {
Node::reset_peers(false);
self.peers_reset = true;
});
ui.add_space(6.0);
ui.label(RichText::new(t!("network_settings.reset_peers_desc"))
.size(16.0)
.color(Colors::inactive_text())
);
}
}
/// Draw peer list item.
+7 -1
View File
@@ -113,7 +113,7 @@ pub enum PullToRefreshState {
/// `far_enough` is true if the user dragged far enough to trigger a refresh.
far_enough: bool,
},
/// The user dragged far enough to trigger a refresh and released the pointer.
/// The user dragged far enough to trigger a refresh.
DoRefresh,
/// The refresh is currently happening.
Refreshing,
@@ -298,6 +298,12 @@ impl PullToRefresh {
} else {
state = PullToRefreshState::Idle;
}
} else if let PullToRefreshState::Dragging {
far_enough: enough, ..
} = state.clone() {
if enough {
state = PullToRefreshState::DoRefresh;
}
}
} else {
state = PullToRefreshState::Idle;
+1 -1
View File
@@ -709,7 +709,7 @@ lazy_static! {
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Callback from Java code to update display insets (cutouts).
pub extern "C" fn Java_mw_gri_android_MainActivity_onDisplayInsets(
_env: jni::JNIEnv,
@@ -64,7 +64,7 @@ impl WalletContentContainer for WalletAccountContent {
CREATE_MODAL_ID => self.create_account_content.ui(ui, wallet, modal, cb),
SEND_MODAL_ID => {
if let Some(c) = self.send_content.as_mut() {
c.modal_ui(ui, wallet, modal, cb);
c.ui(ui, wallet, modal, cb);
}
}
_ => {}
+30 -16
View File
@@ -58,36 +58,41 @@ pub struct WalletContent {
const INVOICE_MODAL_ID: &'static str = "invoice_request_modal";
/// Identifier for sending request creation [`Modal`].
const SEND_MODAL_ID: &'static str = "send_request_modal";
/// Identifier for Slatepack message input [`Modal`].
pub const MESSAGE_MODAL_ID: &'static str = "input_message_modal";
impl WalletContentContainer for WalletContent {
fn modal_ids(&self) -> Vec<&'static str> {
vec![
INVOICE_MODAL_ID,
SEND_MODAL_ID,
MESSAGE_MODAL_ID
MessageInputContent::MODAL_ID
]
}
fn modal_ui(&mut self, ui: &mut egui::Ui, w: &Wallet, m: &Modal, cb: &dyn PlatformCallbacks) {
match m.id {
INVOICE_MODAL_ID => {
if let Some(c) = self.invoice_content.as_mut() {
c.modal_ui(ui, w, m, cb);
if self.invoice_content.is_none() {
self.invoice_content = Some(InvoiceRequestContent::default());
}
self.invoice_content.as_mut().unwrap().ui(ui, w, m, cb);
}
SEND_MODAL_ID => {
if let Some(c) = self.send_content.as_mut() {
c.modal_ui(ui, w, m, cb);
if self.send_content.is_none() {
self.send_content = Some(SendRequestContent::new(None));
}
self.send_content.as_mut().unwrap().ui(ui, w, m, cb);
}
MESSAGE_MODAL_ID => {
if let Some(c) = self.message_content.as_mut() {
c.ui(ui, w, m, cb);
MessageInputContent::MODAL_ID => {
if self.message_content.is_none() {
self.message_content = Some(MessageInputContent::default());
}
self.message_content.as_mut().unwrap().ui(ui, w, m, cb);
}
_ => {
self.invoice_content = None;
self.send_content = None;
self.message_content = None;
}
_ => {}
}
}
@@ -394,7 +399,10 @@ impl WalletContent {
} else {
let (icon, color) = (FILE_ARROW_DOWN, Some(Colors::green()));
View::tab_button(ui, icon, color, active, |_| {
self.invoice_content = Some(InvoiceRequestContent::default());
if self.txs_content.is_none() {
self.txs_content = Some(WalletTransactionsContent::new(None));
self.settings_content = None;
}
Modal::new(INVOICE_MODAL_ID)
.position(ModalPosition::CenterTop)
.title(t!("wallets.receive"))
@@ -409,8 +417,11 @@ impl WalletContent {
} else {
let (icon, color) = (FILE_TEXT, Some(Colors::gold_dark()));
View::tab_button(ui, icon, color, active, |_| {
self.message_content = Some(MessageInputContent::default());
Modal::new(MESSAGE_MODAL_ID)
if self.txs_content.is_none() {
self.txs_content = Some(WalletTransactionsContent::new(None));
self.settings_content = None;
}
Modal::new(MessageInputContent::MODAL_ID)
.position(ModalPosition::Center)
.title(t!("wallets.messages"))
.show();
@@ -425,7 +436,10 @@ impl WalletContent {
} else {
let (icon, color) = (FILE_ARROW_UP, Some(Colors::red()));
View::tab_button(ui, icon, color, active, |_| {
self.send_content = Some(SendRequestContent::new(None));
if self.txs_content.is_none() {
self.txs_content = Some(WalletTransactionsContent::new(None));
self.settings_content = None;
}
Modal::new(SEND_MODAL_ID)
.position(ModalPosition::CenterTop)
.title(t!("wallets.send"))
@@ -488,7 +502,7 @@ impl WalletContent {
_ => {}
}
}
MESSAGE_MODAL_ID => {
MessageInputContent::MODAL_ID => {
match t {
WalletTask::VerifyProof(proof, res) => {
if let Some(res) = res {
+10 -9
View File
@@ -56,6 +56,9 @@ impl Default for MessageInputContent {
}
impl MessageInputContent {
/// Identifier for [`Modal`].
pub const MODAL_ID: &'static str = "input_message_modal";
/// Draw [`Modal`] content.
pub fn ui(&mut self,
ui: &mut egui::Ui,
@@ -236,15 +239,13 @@ impl MessageInputContent {
if self.message_edit.is_empty() {
return;
}
match wallet.parse_slatepack(&self.message_edit) {
Ok(_) => {
wallet.task(WalletTask::OpenMessage(self.message_edit.to_string()));
self.message_edit = "".to_string();
Modal::close();
}
Err(_) => {
self.parse_error = true;
}
if self.message_edit.starts_with("BEGINSLATEPACK.") &&
self.message_edit.ends_with("ENDSLATEPACK.") {
wallet.task(WalletTask::OpenMessage(self.message_edit.to_string()));
self.message_edit = "".to_string();
Modal::close();
} else {
self.parse_error = true;
}
}
}
@@ -37,7 +37,7 @@ impl Default for InvoiceRequestContent {
impl InvoiceRequestContent {
/// Draw [`Modal`] content.
pub fn modal_ui(&mut self,
pub fn ui(&mut self,
ui: &mut egui::Ui,
wallet: &Wallet,
modal: &Modal,
+14 -9
View File
@@ -73,11 +73,11 @@ impl SendRequestContent {
}
/// Draw [`Modal`] content.
pub fn modal_ui(&mut self,
ui: &mut egui::Ui,
wallet: &Wallet,
modal: &Modal,
cb: &dyn PlatformCallbacks) {
pub fn ui(&mut self,
ui: &mut egui::Ui,
wallet: &Wallet,
modal: &Modal,
cb: &dyn PlatformCallbacks) {
ui.add_space(6.0);
// Draw QR code scanner content if requested.
@@ -287,9 +287,14 @@ impl SendRequestContent {
});
columns[1].vertical_centered_justified(|ui| {
// Button to create Slatepack message request.
View::button(ui, t!("continue"), Colors::white_or_black(false), || {
self.on_continue(wallet);
});
if self.max_calculating || wallet.fee_calculating() {
ui.add_space(4.0);
View::small_loading_spinner(ui);
} else {
View::button(ui, t!("continue"), Colors::white_or_black(false), || {
self.on_continue(wallet);
});
}
});
});
ui.add_space(6.0);
@@ -297,7 +302,7 @@ impl SendRequestContent {
/// Callback when Continue button was pressed.
fn on_continue(&mut self, wallet: &Wallet) {
if self.amount_edit.is_empty() || self.max_calculating || wallet.fee_calculating() {
if self.amount_edit.is_empty() {
return;
}
// Check address to send over Tor if enabled.
@@ -21,6 +21,7 @@ use crate::gui::views::network::ConnectionsContent;
use crate::gui::views::types::{ContentContainer, ModalPosition};
use crate::gui::views::{Modal, View};
use crate::gui::Colors;
use crate::node::Node;
use crate::wallet::types::ConnectionMethod;
use crate::wallet::{ConnectionsConfig, ExternalConnection};
@@ -35,8 +36,17 @@ pub struct ConnectionSettings {
impl Default for ConnectionSettings {
fn default() -> Self {
let method = {
let ext_conn_list = ConnectionsConfig::ext_conn_list();
if Node::is_running() || Node::is_starting() || ext_conn_list.is_empty() {
ConnectionMethod::Integrated
} else {
let ext_conn = ext_conn_list.get(0).unwrap();
ConnectionMethod::External(ext_conn.id, ext_conn.url.clone())
}
};
Self {
method: ConnectionMethod::Integrated,
method,
ext_conn_modal: ExternalConnectionModal::new(None),
}
}
+8 -8
View File
@@ -45,6 +45,13 @@ pub struct WalletTransactionsContent {
manual_sync: Option<u128>
}
/// Identifier for transaction information [`Modal`].
const TX_INFO_MODAL: &'static str = "tx_info_modal";
/// Identifier for transaction cancellation confirmation [`Modal`].
const CANCEL_TX_CONFIRMATION_MODAL: &'static str = "cancel_tx_conf_modal";
/// Identifier for transaction deletion confirmation [`Modal`].
const DELETE_TX_CONFIRMATION_MODAL: &'static str = "delete_tx_conf_modal";
impl WalletContentContainer for WalletTransactionsContent {
fn modal_ids(&self) -> Vec<&'static str> {
vec![TX_INFO_MODAL, CANCEL_TX_CONFIRMATION_MODAL, DELETE_TX_CONFIRMATION_MODAL]
@@ -78,16 +85,9 @@ impl WalletContentContainer for WalletTransactionsContent {
}
}
/// Identifier for transaction information [`Modal`].
const TX_INFO_MODAL: &'static str = "tx_info_modal";
/// Identifier for transaction cancellation confirmation [`Modal`].
const CANCEL_TX_CONFIRMATION_MODAL: &'static str = "cancel_tx_conf_modal";
/// Identifier for transaction deletion confirmation [`Modal`].
const DELETE_TX_CONFIRMATION_MODAL: &'static str = "delete_tx_conf_modal";
impl WalletTransactionsContent {
/// Height of transaction list item.
pub const TX_ITEM_HEIGHT: f32 = 73.0;
pub const TX_ITEM_HEIGHT: f32 = 75.0;
/// Create new content instance with opening tx info.
pub fn new(tx: Option<WalletTx>) -> Self {
+23 -2
View File
@@ -28,6 +28,8 @@ use crate::gui::Colors;
use crate::wallet::types::{WalletTask, WalletTx};
use crate::wallet::Wallet;
use crate::AppConfig;
use crate::gui::views::types::ModalPosition;
use crate::gui::views::wallets::wallet::message::MessageInputContent;
/// Transaction information [`Modal`] content.
pub struct WalletTransactionContent {
@@ -219,6 +221,8 @@ impl WalletTransactionContent {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
let mut finalization_needed = false;
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
// Draw button to show Slatepack message as QR code.
@@ -232,7 +236,12 @@ impl WalletTransactionContent {
let copy_text = format!("{} {}", COPY, t!("copy"));
View::button(ui, copy_text, Colors::white_or_black(false), || {
cb.copy_string_to_buffer(m.clone());
Modal::close();
// Show message input or close modal.
if tx.can_finalize() {
finalization_needed = true;
} else {
Modal::close();
}
});
});
});
@@ -249,10 +258,22 @@ impl WalletTransactionContent {
let name = format!("{}.{}.slatepack", slate_id, tx.state);
let data = m.as_bytes().to_vec();
cb.share_data(name, data).unwrap_or_default();
Modal::close();
// Show message input or close modal.
if tx.can_finalize() {
finalization_needed = true;
} else {
Modal::close();
}
}
});
});
if finalization_needed {
Modal::new(MessageInputContent::MODAL_ID)
.position(ModalPosition::Center)
.title(t!("wallets.messages"))
.show();
}
}
}
+2 -2
View File
@@ -46,7 +46,7 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Android platform entry point.
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[no_mangle]
#[unsafe(no_mangle)]
fn android_main(app: AndroidApp) {
// Setup logger.
logger::init_logger();
@@ -273,7 +273,7 @@ lazy_static! {
#[allow(dead_code)]
#[allow(non_snake_case)]
#[cfg(target_os = "android")]
#[no_mangle]
#[unsafe(no_mangle)]
pub extern "C" fn Java_mw_gri_android_MainActivity_onData(
_env: jni::JNIEnv,
_class: jni::objects::JObject,
+60 -65
View File
@@ -28,7 +28,7 @@ use grin_p2p::msg::PeerAddrs;
use grin_p2p::Seeding;
use grin_servers::{Server, ServerStats, StratumServerConfig, StratumStats};
use grin_servers::common::types::Error;
use log::error;
use crate::node::{NodeConfig, NodeError, PeersConfig};
use crate::node::stratum::{StratumStopState, StratumServer};
@@ -57,8 +57,8 @@ pub struct Node {
stop_needed: AtomicBool,
/// Flag to check if app exit is needed after [`Server`] stop.
exit_after_stop: AtomicBool,
/// Flag to reset peers data and restart the [`Server`].
reset_peers: AtomicBool,
/// Flag to reset data and restart the [`Server`].
reset_data: AtomicBool,
/// Flag to change data directory and restart the [`Server`].
change_data_dir: AtomicBool,
@@ -78,7 +78,7 @@ impl Default for Node {
exit_after_stop: AtomicBool::new(false),
start_stratum_needed: AtomicBool::new(false),
error: Arc::new(RwLock::new(None)),
reset_peers: AtomicBool::new(false),
reset_data: AtomicBool::new(false),
change_data_dir: AtomicBool::new(false),
}
}
@@ -89,26 +89,20 @@ impl Node {
pub const STATS_UPDATE_DELAY: Duration = Duration::from_millis(1000);
/// Default Mainnet DNS Seeds
pub const MAINNET_DNS_SEEDS: &'static[&'static str] = &[
"main.gri.mw",
"grincoin.org",
"mainnet.grinffindor.org",
"mainnet.seed.grin.lesceller.com",
"grinseed.revcore.net",
"mainnet-seed.grinnode.live",
"mainnet.grin.punksec.de",
"grinnode.30-r.com"
pub const MAINNET_DNS_SEEDS: &[&str] = &[
"mainnet-seed.grinnode.live", // info@grinnode.live
"grincoin.org", // xmpp:aglkm@conversations.im
"main.gri.mw", // admin@gri.mw
"mainnet.grinffindor.org", // support@grinffindor.org
"main-seed.grin.money", // support@grinily.com
];
/// Default Testnet DNS Seeds
pub const TESTNET_DNS_SEEDS: &'static[&'static str] = &[
"test.gri.mw",
"testnet.grincoin.org",
"testnet.grinffindor.org",
"floonet.seed.grin.lesceller.com",
"grintestseed.revcore.net",
"testnet.grin.punksec.de",
"testnet.grinnode.30-r.com"
pub const TESTNET_DNS_SEEDS: &[&str] = &[
"testnet.grincoin.org", // xmpp:aglkm@conversations.im
"test.gri.mw", // admin@gri.mw
"testnet.grinffindor.org", // support@grinffindor.org
"test-seed.grin.money", // support@grinily.com
];
/// Stop the [`Server`] and setup exit flag after if needed.
@@ -175,12 +169,12 @@ impl Node {
/// Check if [`Node`] is restarting.
pub fn is_restarting() -> bool {
NODE_STATE.restart_needed.load(Ordering::Relaxed) || Self::reset_peers_needed()
NODE_STATE.restart_needed.load(Ordering::Relaxed) || Self::reset_data_needed()
}
/// Check if reset of [`Server`] peers is needed.
fn reset_peers_needed() -> bool {
NODE_STATE.reset_peers.load(Ordering::Relaxed)
fn reset_data_needed() -> bool {
NODE_STATE.reset_data.load(Ordering::Relaxed)
}
/// Get node [`Server`] statistics.
@@ -269,9 +263,9 @@ impl Node {
server.stop();
// Wait server after stop.
thread::sleep(Duration::from_millis(5000));
// Reset peers data if requested.
if Self::reset_peers_needed() {
Node::reset_peers(true);
// Reset data if requested.
if Self::reset_data_needed() {
Node::reset_data(true);
}
// Reset stratum stats.
{
@@ -285,7 +279,7 @@ impl Node {
NODE_STATE.restart_needed.store(false, Ordering::Relaxed);
}
Err(e) => {
// Set an error.
error!("Error starting node: {:?}", e);
{
let mut w_err = NODE_STATE.error.write();
*w_err = Some(e);
@@ -339,7 +333,7 @@ impl Node {
}
}
Err(e) => {
// Set an error.
error!("Error starting node: {:?}", e);
{
let mut w_err = NODE_STATE.error.write();
*w_err = Some(e);
@@ -434,24 +428,20 @@ impl Node {
}
}
/// Reset [`Server`] peers data.
pub fn reset_peers(force: bool) {
/// Reset [`Server`] data.
pub fn reset_data(force: bool) {
if force || !Node::is_running() {
// Get saved server config.
let config = NodeConfig::node_server_config();
let server_config = config.server.clone();
// Remove peers folder.
let mut peers_dir = PathBuf::from(&server_config.db_root);
peers_dir.push("peer");
if peers_dir.exists() {
match fs::remove_dir_all(peers_dir) {
Ok(_) => {}
Err(_) => {}
}
// Remove data folder.
let data_dir = PathBuf::from(&server_config.db_root);
match fs::remove_dir_all(data_dir) {
Ok(_) => {}
Err(_) => {}
}
NODE_STATE.reset_peers.store(false, Ordering::Relaxed);
NODE_STATE.reset_data.store(false, Ordering::Relaxed);
} else {
NODE_STATE.reset_peers.store(true, Ordering::Relaxed);
NODE_STATE.reset_data.store(true, Ordering::Relaxed);
}
}
@@ -585,20 +575,25 @@ fn start_node_server() -> Result<Server, Error> {
PeersConfig::load_to_server_config(&mut config);
let mut server_config = config.server.clone();
// Setup Mainnet DNSSeed
if server_config.chain_type == ChainTypes::Mainnet && NodeConfig::is_default_seeding_type() {
// DNS seed setup.
if NodeConfig::is_default_seeding_type() {
server_config.p2p_config.seeding_type = Seeding::List;
server_config.p2p_config.seeds = Some(PeerAddrs::default());
for seed in Node::MAINNET_DNS_SEEDS {
let addr = format!("{}:3414", seed);
let is_mainnet = server_config.chain_type == ChainTypes::Mainnet;
let seed_list = if is_mainnet {
Node::MAINNET_DNS_SEEDS
} else {
Node::TESTNET_DNS_SEEDS
};
let seed_port = if is_mainnet {
3414
} else {
13414
};
for seed_addr in seed_list {
let addr = format!("{}:{}", seed_addr, seed_port);
if let Some(p) = PeersConfig::peer_to_addr(addr) {
let mut seeds = server_config
.p2p_config
.seeds
.clone()
.unwrap_or(PeerAddrs::default());
seeds.peers.insert(seeds.peers.len(), p);
server_config.p2p_config.seeds = Some(seeds);
server_config.p2p_config.seeds.as_mut().unwrap().peers.push(p)
}
}
}
@@ -710,7 +705,7 @@ pub fn start_stratum_mining_server(server: &Server, config: StratumServerConfig)
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Get sync status text for Android notification from [`NODE_STATE`] in Java string format.
pub extern "C" fn Java_mw_gri_android_BackgroundService_getSyncStatusText(
_env: jni::JNIEnv,
@@ -725,7 +720,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_getSyncStatusText(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Get sync title for Android notification in Java string format.
pub extern "C" fn Java_mw_gri_android_BackgroundService_getSyncTitle(
_env: jni::JNIEnv,
@@ -739,7 +734,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_getSyncTitle(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Get start text for Android notification in Java string format.
pub extern "C" fn Java_mw_gri_android_BackgroundService_getStartText(
_env: jni::JNIEnv,
@@ -753,7 +748,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_getStartText(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Get stop text for Android notification in Java string format.
pub extern "C" fn Java_mw_gri_android_BackgroundService_getStopText(
_env: jni::JNIEnv,
@@ -767,7 +762,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_getStopText(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Get exit text for Android notification in Java string format.
pub extern "C" fn Java_mw_gri_android_BackgroundService_getExitText(
_env: jni::JNIEnv,
@@ -781,7 +776,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_getExitText(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Check if node launch is possible.
pub extern "C" fn Java_mw_gri_android_BackgroundService_canStartNode(
_env: jni::JNIEnv,
@@ -795,7 +790,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_canStartNode(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Check if node stop is possible.
pub extern "C" fn Java_mw_gri_android_BackgroundService_canStopNode(
_env: jni::JNIEnv,
@@ -809,7 +804,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_canStopNode(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Start node from Android Java code.
pub extern "C" fn Java_mw_gri_android_NotificationActionsReceiver_startNode(
_env: jni::JNIEnv,
@@ -822,7 +817,7 @@ pub extern "C" fn Java_mw_gri_android_NotificationActionsReceiver_startNode(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Stop node from Android Java code.
pub extern "C" fn Java_mw_gri_android_NotificationActionsReceiver_stopNode(
_env: jni::JNIEnv,
@@ -835,7 +830,7 @@ pub extern "C" fn Java_mw_gri_android_NotificationActionsReceiver_stopNode(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Stop node from Android Java code.
pub extern "C" fn Java_mw_gri_android_NotificationActionsReceiver_stopNodeToExit(
_env: jni::JNIEnv,
@@ -852,7 +847,7 @@ pub extern "C" fn Java_mw_gri_android_NotificationActionsReceiver_stopNodeToExit
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Check if app exit is needed after node stop to finish Android app at background.
pub extern "C" fn Java_mw_gri_android_BackgroundService_exitAppAfterNodeStop(
_env: jni::JNIEnv,
@@ -866,7 +861,7 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_exitAppAfterNodeStop(
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
/// Handle unexpected application termination on Android (removal from recent apps).
pub extern "C" fn Java_mw_gri_android_MainActivity_onTermination(
_env: jni::JNIEnv,
+1 -1
View File
@@ -656,7 +656,7 @@ impl Tor {
}
};
// Wait to check service again.
thread::sleep(duration);
tokio::time::sleep(duration).await;
}
});
});
+6 -6
View File
@@ -59,12 +59,12 @@ impl TorBridge {
/// Default webtunnel protocol connection line.
pub const DEFAULT_WEBTUNNEL_CONN_LINE: &'static str = "webtunnel [2001:db8:beb:5884:ffcc:bfe3:2858:b06b]:443 1E242C749707B4A68A269F0D31311CE36CDFEC28 url=https://wt.gri.mw/74Fm0lKUWWMMjZpKf6iSC0UH";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_1: &'static str = "webtunnel [2001:db8:1640:379c:ad30:db5f:bff5:37d0]:443 AF8F7548C886D6F53A652411DBB71D089517085A url=https://app05.oneclickhost.eu/alpfZGTB9FckCgOkOOA0OHlh";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_2: &'static str = "webtunnel [2001:db8:eedb:cae7:a345:4f72:f9cc:5de0]:443 B3C81E7A0CA474270DAA4A2C8633E1CA8935C37D url=https://wordpress.far-east-investment.ru/sORes7268CEUSRD7hAWvJU5A";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_3: &'static str = "webtunnel [2001:db8:945c:e0b9:7e4c:c974:ff00:d4c5]:443 91937F3EFB3BE5169788AC7C8BF07460B7E306DB url=https://kabel.entreri.de/YXbp1dNrJeOF8giAFFYWxvmf";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_4: &'static str = "webtunnel [2001:db8:4767:7aa2:df21:1b2b:d7f9:caee]:443 CD193CF0D0C29551928C01FCB28D1200D9F27CFA url=https://occurrence.pics/68SzSlQCRgnfSo32eLyjC1V3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_5: &'static str = "webtunnel [2001:db8:ce90:3593:272e:4975:a031:55b]:443 12382A2F3912AD1983A97C8709CBAE47ADB60BE3 url=https://miranda.today/LWwxIXDHCyyScn7oDauPMTmX";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_6: &'static str = "webtunnel [2001:db8:a12b:ff8:8a1a:a05b:5f21:2ccc]:443 F2A9C5AEE0A420EB9D55F9497B3C0FA243A2A770 url=https://bridge.lovecloud.me/wss-wc3p0euqrlne98t9";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_1: &'static str = "webtunnel [2001:db8:289b:84cd:4be3:77f1:1cdd:9cb1]:443 D71C8E9C2180D2F35DEBF4A39BFCA6972F076D1C sni-imitation=yandex.ru,google.com,dzen.ru,vk.com,mail.ru,ozon.ru,ya.ru,www.wildberries.ru,rutube.ru,www.avito.ru,ok.ru,vkvideo.ru url=https://streaming.the-forgotten-tales.com/gz9X1VBgl0r1Xfx3dHdNl5Tl";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_2: &'static str = "webtunnel [2001:db8:dee9:5852:b4dc:7e14:21bd:c99b]:443 8ADF1761FA735FDD763781BB94A16EAB64A1CF6C url=https://app01.oneclickhost.eu/WJSgXJRlNnMStkuLZygVJ7lo";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_3: &'static str = "webtunnel [2001:db8:eedb:cae7:a345:4f72:f9cc:5de0]:443 B3C81E7A0CA474270DAA4A2C8633E1CA8935C37D url=https://wordpress.far-east-investment.ru/sORes7268CEUSRD7hAWvJU5A";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_4: &'static str = "webtunnel [2001:db8:945c:e0b9:7e4c:c974:ff00:d4c5]:443 91937F3EFB3BE5169788AC7C8BF07460B7E306DB url=https://kabel.entreri.de/YXbp1dNrJeOF8giAFFYWxvmf";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_5: &'static str = "webtunnel [2001:db8:7d4:9e13:8c7a:7e3:1f62:d790]:443 B7E362F9079D0C908F204581EB019034023BB224 url=https://balades-et-gouts.fr/xt70R9oyJt3B1xj89UCWPdLt";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_6: &'static str = "webtunnel [2001:db8:8c88:1b17:d7ae:cb68:f28e:e31c]:443 C115DAC2FE991CA25DDD43D7D4D398FEA9AA4C01 url=https://foglab.net/t9crLwo4LzFDWHdwcGf9gFrk";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_7: &'static str = "webtunnel [2001:db8:8ed6:e6c9:5fc9:9f20:a373:2374]:443 1636A2EFFBAA4B162F5FF461A1663EB55C41AE11 url=https://hanoi.delivery/roQFPLtlspWT6yIKeXD6lEci";
pub const DEFAULT_WEBTUNNEL_CONN_LINES: [&'static str; 8] = [
+44 -38
View File
@@ -52,6 +52,7 @@ use std::{fs, path, thread};
use chrono::Utc;
use log::error;
use num_bigint::BigInt;
use tor_config::deps::Itertools;
use uuid::Uuid;
/// Contains wallet instance, configuration and state, handles wallet commands.
@@ -63,7 +64,7 @@ pub struct Wallet {
instance: Arc<RwLock<Option<WalletInstance>>>,
/// Connection of current wallet instance.
connection: Arc<RwLock<ConnectionMethod>>,
/// Wallet secret key for transport service.
/// Keychain mask for API calls.
keychain_mask: Arc<RwLock<Option<SecretKey>>>,
/// Wallet Slatepack address to receive txs at transport.
@@ -532,13 +533,16 @@ impl Wallet {
if !self.is_open() || !has_instance {
return;
}
self.closing.store(true, Ordering::Relaxed);
// Stop repairing.
if self.is_repairing() {
self.repair_needed.store(false, Ordering::Relaxed);
}
// Close wallet at separate thread.
let wallet_close = self.clone();
let service_id = wallet_close.identifier();
let conn = wallet_close.connection.clone();
thread::spawn(move || {
wallet_close.closing.store(true, Ordering::Relaxed);
// Wait common operations to finish.
while wallet_close.message_opening() || wallet_close.send_creating() ||
wallet_close.invoice_creating() {
@@ -648,8 +652,12 @@ impl Wallet {
let w = lc.wallet_inst()?;
let parent_key_id = w.parent_key_id();
// Retrieve txs from database.
let txs_iter = w.tx_log_iter()
let txs: Vec<TxLogEntry> = w.tx_log_iter()
.filter(|tx_entry| tx_entry.parent_key_id == parent_key_id)
// Filter transactions to not show txs without slate (usually unspent outputs).
.filter(|tx| {
tx.tx_slate_id.is_some() || (tx.tx_slate_id.is_none() && tx.payment_proof.is_some())
})
.filter(|tx_entry| {
if tx_entry.tx_type == TxLogEntryType::TxSent
|| tx_entry.tx_type == TxLogEntryType::TxSentCancelled {
@@ -661,20 +669,21 @@ impl Wallet {
- BigInt::from(tx_entry.amount_debited)
>= BigInt::from(1)
}
});
let mut return_txs: Vec<TxLogEntry> = txs_iter.collect();
// Sort txs by creation date and confirmation status reversing an order.
return_txs.sort_by_key(|tx| if !tx.confirmed && (tx.tx_type == TxLogEntryType::TxSent ||
tx.tx_type == TxLogEntryType::TxReceived) {
i64::MAX
} else {
tx.creation_ts.timestamp()
});
// return_txs.sort_by_key(|tx| tx.confirmed);
return_txs.reverse();
// Apply limit.
return_txs = return_txs.into_iter().take(limit as usize).collect();
Ok(return_txs)
})
// Sort txs by creation date and confirmation status.
.sorted_by_key(|tx| -tx.creation_ts.timestamp())
// Sort to show unconfirmed at top.
.sorted_by_key(|tx| {
tx.confirmed || tx.tx_type == TxLogEntryType::TxReceivedCancelled ||
tx.tx_type == TxLogEntryType::TxSentCancelled ||
tx.tx_type == TxLogEntryType::TxReverted
})
// Apply limit.
.take(limit as usize)
.collect();
// Reverse an order.
// txs.reverse();
Ok(txs)
}
/// Send a task to the wallet.
@@ -799,7 +808,7 @@ impl Wallet {
let wallet = self.clone();
thread::spawn(move || {
// Wait when current sync will be finished.
if wallet.syncing() {
while wallet.syncing() {
thread::sleep(Duration::from_secs(1));
}
// Sync wallet data with new limit.
@@ -978,7 +987,10 @@ impl Wallet {
null
]
}).to_string();
// Wait Tor service to launch.
while Tor::is_service_starting(&self.identifier()) {
tokio::time::sleep(Duration::from_secs(1)).await;
}
// Send request to receiver.
let req_res = Tor::post(body, url).await;
if req_res.is_none() {
@@ -1126,13 +1138,17 @@ impl Wallet {
/// Update transaction action status.
fn on_tx_action(&self, id: u32, action: Option<WalletTxAction>) {
let mut w_data = self.data.write();
w_data.as_mut().unwrap().on_tx_action(id, action);
if let Some(data) = w_data.as_mut() {
data.on_tx_action(id, action);
}
}
/// Update transaction action error status.
fn on_tx_error(&self, id: u32, err: Option<Error>) {
let mut w_data = self.data.write();
w_data.as_mut().unwrap().on_tx_error(id, err);
if let Some(data) = w_data.as_mut() {
data.on_tx_error(id, err);
}
}
/// Save task result to consume later.
@@ -1735,7 +1751,8 @@ async fn handle_task(w: &Wallet, t: WalletTask) {
let tx = w.retrieve_tx_by_id(None, Some(s.id));
if let Some(tx) = tx {
if let Some(addr) = r {
if Tor::is_service_running(&w.identifier()) {
let id = w.identifier();
if Tor::is_service_running(&id) || Tor::is_service_starting(&id) {
w.send_creating.store(false, Ordering::Relaxed);
send_tor(tx, &s, addr).await;
return;
@@ -1966,21 +1983,10 @@ fn update_txs(wallet: &Wallet, mut txs_limit: u32) -> Result<(), Error> {
return Err(Error::GenericError("Wallet is not open".to_string()));
}
// Filter transactions to not show txs without slate (usually unspent outputs).
let mut filter_txs = txs.iter().map(|v| v.clone()).filter(|tx| {
tx.tx_slate_id.is_some() || (tx.tx_slate_id.is_none() && tx.payment_proof.is_some())
}).collect::<Vec<TxLogEntry>>();
// Sort to show unconfirmed at top.
filter_txs.sort_by_key(|tx| {
tx.confirmed || tx.tx_type == TxLogEntryType::TxReceivedCancelled ||
tx.tx_type == TxLogEntryType::TxSentCancelled ||
tx.tx_type == TxLogEntryType::TxReverted
});
// Update limit with actual length.
let txs_size = txs.len() as u32;
let filter_size = filter_txs.len() as u32;
let filter_size = txs.len() as u32;
if txs_size > filter_size && txs_limit >= filter_size {
txs_limit = txs_limit - (txs_size - filter_size);
}
@@ -1990,7 +1996,7 @@ fn update_txs(wallet: &Wallet, mut txs_limit: u32) -> Result<(), Error> {
let data = wallet.get_data().unwrap();
let data_txs = data.txs.unwrap_or(vec![]);
let mut new_txs: Vec<WalletTx> = vec![];
for tx in &filter_txs {
for tx in &txs {
let mut height: Option<u64> = None;
let mut broadcasting_height: Option<u64> = None;
let mut action: Option<WalletTxAction> = None;
@@ -2183,10 +2189,10 @@ fn repair_wallet(wallet: &Wallet) {
}
});
// Start wallet scanning.
let r_inst = wallet.instance.as_ref().read();
let instance = r_inst.clone().unwrap();
let api = Owner::new(instance, Some(info_tx));
// Start wallet scanning.
match api.scan(wallet.keychain_mask().as_ref(), Some(1), false) {
Ok(()) => {
// Set sync error if scanning was not complete and wallet is open.
+1 -1
Submodule wallet updated: f54a8e7756...c1d7070291
+2 -2
View File
@@ -7,8 +7,8 @@
<?endif ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Version="0.3.3" UpgradeCode="C19F9B41-CD13-4F0E-B27D-E0EF8CF1CE91" Language="1033" Name="Grim" Manufacturer="Ardocrat">
<Package Id="F0DD07CB-48B4-419C-9A20-CE41CD0D9252" InstallerVersion="300" Compressed="yes"/>
<Product Id="*" Version="0.3.5" UpgradeCode="C19F9B41-CD13-4F0E-B27D-E0EF8CF1CE91" Language="1033" Name="Grim" Manufacturer="Ardocrat">
<Package Id="E15A3211-C334-4B2D-8774-4834657A00B6" InstallerVersion="300" Compressed="yes"/>
<Media Id="1" Cabinet="grim.cab" EmbedCab="yes" />
<MajorUpgrade AllowDowngrades = "yes"/>