Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5701545f0d | |||
| 997435c4e0 | |||
| cd1b497f0d | |||
| 7adf92df7a | |||
| 4405d34f4b | |||
| 96b549ce95 | |||
| 49cd969009 | |||
| 787721616e | |||
| 369a57c67d | |||
| c57b14f6be | |||
| ce7b276a1f | |||
| 4f3e16c935 | |||
| 2833a70a36 | |||
| aa32672208 | |||
| a9bbcd070b | |||
| 7bfc34b76b | |||
| c3f49eb558 | |||
| 71f1f3011d | |||
| 22de8630cd | |||
| da5e5f9a8a | |||
| 998bd51425 | |||
| 7d0b2806e0 | |||
| 73c183d1c0 | |||
| 65b9417c28 | |||
| ed87543153 | |||
| 6e9dbb1aa9 | |||
| a6ec711cfa | |||
| 6877aeaddb | |||
| 60067e1a88 | |||
| e91ccd8786 | |||
| 96fb7d5040 | |||
| 47cf8abbda |
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(C:/msys64/msys2_shell.cmd -mingw64 -defterm -no-start -here -c \"ls /mingw64/lib/libboost_system* 2>/dev/null\")"
|
||||
"Bash(C:/msys64/msys2_shell.cmd -mingw64 -defterm -no-start -here -c \"ls /mingw64/lib/libboost_system* 2>/dev/null\")",
|
||||
"Bash(git tag:*)"
|
||||
],
|
||||
"additionalDirectories": [
|
||||
"C:\\msys64\\mingw64\\bin"
|
||||
|
||||
@@ -73,7 +73,99 @@
|
||||
"Bash(PATH=\"/c/msys64/mingw64/bin:$PATH\" /e/repos/triangles/scan_chain_tip.exe:*)",
|
||||
"Bash(PATH=\"/c/msys64/mingw64/bin:$PATH\" /c/msys64/mingw64/bin/qmake.exe:*)",
|
||||
"Bash(PATH=\"/c/msys64/mingw64/bin:$PATH\" qmake-qt5:*)",
|
||||
"Bash(PATH=\"/c/msys64/mingw64/bin:$PATH\" mingw32-make:*)"
|
||||
"Bash(PATH=\"/c/msys64/mingw64/bin:$PATH\" mingw32-make:*)",
|
||||
"Bash(export PATH=\"/c/msys64/mingw64/bin:$PATH\")",
|
||||
"Bash(\"C:/msys64/mingw64/bin/qmake-qt5.exe\" triangles-qt.pro -o Makefile)",
|
||||
"Bash(gh release create:*)",
|
||||
"Bash(gh repo view:*)",
|
||||
"Bash(gh repo create:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git branch:*)",
|
||||
"Bash(git push:*)",
|
||||
"Bash(gh repo fork:*)",
|
||||
"Bash(gh api:*)",
|
||||
"Bash(gh auth:*)",
|
||||
"Bash(1 <<'EOF'\n{\"visibility\":\"public\"}\nEOF)",
|
||||
"Bash(findstr:*)",
|
||||
"Bash(gh workflow run:*)",
|
||||
"Bash(gh run watch:*)",
|
||||
"Bash(gh run view:*)",
|
||||
"Bash(gh release view:*)",
|
||||
"Bash(gh run download:*)",
|
||||
"Bash(gh release upload:*)",
|
||||
"Bash(gh release delete-asset:*)",
|
||||
"Bash(C:/msys64/mingw64/bin/mingw32-make.exe:*)",
|
||||
"Bash(C:/msys64/usr/bin/env.exe MSYSTEM=MINGW64 PATH=\"/mingw64/bin:/usr/bin:/bin\" /usr/bin/bash -lc \"cd /e/repos/triangles/src && mingw32-make -f makefile.mingw -j8 all 2>&1 | tail -60\")",
|
||||
"Bash(C:/msys64/usr/bin/env.exe MSYSTEM=MINGW64 /usr/bin/bash -lc \"ls /mingw64/lib/libboost_system*\")",
|
||||
"Bash(C:/msys64/usr/bin/env.exe MSYSTEM=MINGW64 PATH=\"/mingw64/bin:/usr/bin:/bin\" /usr/bin/bash -lc \"cd /e/repos/triangles/src && mingw32-make -f makefile.mingw trianglesd.exe 2>&1 | tail -20\")",
|
||||
"Bash(C:/msys64/usr/bin/env.exe MSYSTEM=MINGW64 PATH=\"/mingw64/bin:/usr/bin:/bin\" /usr/bin/bash -lc \"cd /e/repos/triangles/src && mingw32-make -f makefile.mingw trianglesd.exe 2>&1 | tail -10\")",
|
||||
"Bash(gh run list:*)",
|
||||
"Bash(git rm:*)",
|
||||
"Bash(wc:*)",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -lc \"cd /e/repos/triangles/src && make -f makefile.mingw obj/rest.o 2>&1 | head -80\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -lc \"cd /e/repos/triangles/src && make -f makefile.mingw obj/trianglesrpc.o 2>&1 | tail -20\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -lc \"cd /e/repos/triangles/src && make -f makefile.mingw 2>&1 | tail -30\")",
|
||||
"Bash(node --version:*)",
|
||||
"Bash(npm --version:*)",
|
||||
"Bash(npm install:*)",
|
||||
"Bash(npx svelte-kit sync:*)",
|
||||
"Bash(npx vite build)",
|
||||
"Bash(nslookup:*)",
|
||||
"Bash(tailscale ping:*)",
|
||||
"Bash(del /f \"%APPDATA%\\\\triangles\\\\peers.dat\")",
|
||||
"Bash(C:msys64usrbinbash.exe -l -c \"cd ''e:/repos/triangles'' && qmake triangles-qt.pro ''USE_QRCODE=1'' ''USE_UPNP=-'' 2>&1 | tail -20\")",
|
||||
"Bash(C:msys64msys2_shell.cmd -mingw64 -defterm -no-start -c \"cd /e/repos/triangles && qmake triangles-qt.pro ''USE_QRCODE=1'' ''USE_UPNP=-'' 2>&1 | tail -20\")",
|
||||
"Bash(\"C:\\\\msys64\\\\mingw64\\\\bin\\\\bash.exe\" -c \"export PATH=/mingw64/bin:/usr/bin:$PATH && cd /e/repos/triangles && qmake triangles-qt.pro ''USE_QRCODE=1'' ''USE_UPNP=-'' 2>&1\")",
|
||||
"Bash(C:/msys64/mingw64/bin/qmake.exe:*)",
|
||||
"Bash(/c/msys64/mingw64/bin/qmake-qt5.exe:*)",
|
||||
"Bash(/c/msys64/usr/bin/env.exe MSYSTEM=MINGW64 /c/msys64/usr/bin/bash.exe -l -c \"cd /e/repos/triangles && qmake triangles-qt.pro ''USE_QRCODE=1'' ''USE_UPNP=-'' 2>&1 | tail -5\")",
|
||||
"Bash(export PATH=\"/c/msys64/mingw64/bin:/c/msys64/usr/bin:$PATH\")",
|
||||
"Bash(/c/msys64/usr/bin/env.exe MSYSTEM=MINGW64 /c/msys64/usr/bin/bash.exe:*)",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"cd /e/repos/triangles && make release 2>&1 | grep -E ''error|Error|undefined|cannot find'' | head -20\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"pacman -Qs qrencode\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"pacman -S --noconfirm mingw-w64-x86_64-qrencode\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"cd /e/repos/triangles && qmake-qt5 -o Makefile triangles-qt.pro USE_QRCODE=0 USE_UPNP=- 2>&1\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"ls /mingw64/lib/libqrencode*\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"pacman -S --noconfirm mingw-w64-x86_64-cmake\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"cd /tmp && pacman -Sp mingw-w64-x86_64-qrencode 2>/dev/null\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"cd /e/repos/triangles && mkdir -p dist && cp release/triangles-qt.exe dist/ && cd dist && strip triangles-qt.exe && ls -lh triangles-qt.exe\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"cd /e/repos/triangles/dist && ldd triangles-qt.exe | grep mingw64 | awk ''{print $3}''\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c 'cd /e/repos/triangles/dist && ldd triangles-qt.exe | grep mingw64 | awk \"\"{print \\\\$3}\"\"')",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"cd /e/repos/triangles/dist && ldd triangles-qt.exe | grep mingw64\")",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c 'cd /e/repos/triangles/dist && ldd triangles-qt.exe | grep mingw64 | sed \"\"s/.*=> //\"\" | sed \"\"s/ \\(.*//\"\"> dlls.txt && while read dll; do cp \"\"$dll\"\" .; done < dlls.txt && ls *.dll | wc -l && echo \"\"DLLs copied\"\"')",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c 'cd /e/repos/triangles/dist && mkdir -p platforms && cp /mingw64/share/qt5/plugins/platforms/qwindows.dll platforms/ && echo \"\"Qt platform plugin copied\"\"')",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c 'cd /e/repos/triangles && rm -f Triangles-v5.1.8-win-x64.zip && cd dist && 7z a ../Triangles-v5.1.8-win-x64.zip triangles-qt.exe *.dll platforms/ && echo \"\"ZIP created\"\"')",
|
||||
"Bash(C:/msys64/usr/bin/bash.exe -l -c \"cd /e/repos/triangles && make -j4 2>&1 | tail -15\")",
|
||||
"Bash(pacman:*)",
|
||||
"Bash(tar:*)",
|
||||
"WebFetch(domain:src-ref.docs.torproject.org)",
|
||||
"WebFetch(domain:gitlab.torproject.org)",
|
||||
"Bash(git status:*)",
|
||||
"Bash(git stash:*)",
|
||||
"Bash(git pull:*)",
|
||||
"Bash(git stash pop:*)",
|
||||
"Bash(find:*)",
|
||||
"Read(//e/repos/triangles/**)",
|
||||
"Bash(curl:*)",
|
||||
"Bash(qmake:*)",
|
||||
"Bash(/c/msys64/mingw64/bin/mingw32-make.exe:*)",
|
||||
"Bash(C:/msys64/msys2_shell.cmd -mingw64 -defterm -no-start -here -c \"cd /e/repos/triangles && make -j1 2>&1 | tail -30\")",
|
||||
"Bash(C:/msys64/msys2_shell.cmd -defterm -no-start -mingw64 -c \"cd /e/repos/triangles && rm -f build/main.o && mingw32-make -f Makefile.Release build/main.o 2>&1 | grep -E ''^\\(src/|.*error\\)'' | head -10\")",
|
||||
"Bash(C:/msys64/msys2_shell.cmd -defterm -no-start -mingw64 -c \"cd /e/repos/triangles && ls -la build/main.o 2>&1\")",
|
||||
"Bash(git -C \"e:\\\\repos\\\\triangles\" log --oneline -20)",
|
||||
"Bash(git -C \"e:\\\\repos\\\\triangles\" describe --tags --abbrev=0)",
|
||||
"Bash(git -C \"e:\\\\repos\\\\triangles\" rev-parse --short HEAD)",
|
||||
"Bash(PATH=\"/c/msys64/mingw64/bin:$PATH\" which make:*)",
|
||||
"Bash(export PATH=\"/mingw64/bin:$PATH\")",
|
||||
"Bash(make:*)",
|
||||
"Bash(C:/msys64/usr/bin/env.exe PATH=\"C:/msys64/mingw64/bin:C:/msys64/usr/bin\" C:/msys64/usr/bin/make.exe:*)",
|
||||
"Bash(C:/msys64/msys2_shell.cmd -mingw64 -defterm -no-start -c \"cd /e/repos/triangles && make -f Makefile.Release -j8 2>&1 | tail -40\")",
|
||||
"Bash(C:/msys64/msys2_shell.cmd -mingw64 -defterm -no-start -here -c \"make 2>&1 | tail -10\")",
|
||||
"Bash(gh pr list:*)",
|
||||
"Bash(gh pr view:*)",
|
||||
"Bash(cmd //C \"powershell -NoProfile -Command \"\"Get-Process | Where-Object { $_.Path -like ''*triangles*'' } | Format-Table Id, ProcessName, Path\"\"\")",
|
||||
"Bash(cmd //C \"tasklist /FI \"\"IMAGENAME eq triangles-qt.exe\"\"\")",
|
||||
"Bash(MSYS_NO_PATHCONV=1 tasklist:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,34 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
VERSION: "5.3.3"
|
||||
VERSION: "5.3.7"
|
||||
|
||||
jobs:
|
||||
test-linux-unit:
|
||||
runs-on: ubuntu-22.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential libboost-all-dev \
|
||||
libssl-dev libdb++-dev libleveldb-dev libevent-dev libminiupnpc-dev
|
||||
|
||||
- name: Build LevelDB
|
||||
run: |
|
||||
cd src/leveldb
|
||||
chmod +x build_detect_platform
|
||||
make clean || true
|
||||
make OPT="-O2" libleveldb.a libmemenv.a
|
||||
|
||||
- name: Build and run unit tests
|
||||
run: |
|
||||
cd src
|
||||
make -f makefile.unix test -j$(nproc)
|
||||
./test_triangles --log_level=test_suite 2>&1 || true
|
||||
|
||||
build-windows-qt:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
@@ -181,7 +206,7 @@ jobs:
|
||||
run: |
|
||||
cd src
|
||||
mkdir -p obj
|
||||
make -f makefile.unix -j$(nproc)
|
||||
make -f makefile.unix trianglesd -j$(nproc)
|
||||
|
||||
- name: Strip binary
|
||||
run: strip --strip-all src/trianglesd
|
||||
|
||||
@@ -5,12 +5,18 @@
|
||||
*.so
|
||||
*.dylib
|
||||
*.a
|
||||
/dist/
|
||||
build/
|
||||
release/
|
||||
debug/
|
||||
/Makefile
|
||||
Makefile.Debug
|
||||
Makefile.Release
|
||||
.qmake.stash
|
||||
object_script.triangles-qt.Debug
|
||||
object_script.triangles-qt.Release
|
||||
/*.zip
|
||||
/*.tar.gz
|
||||
|
||||
# Qt
|
||||
moc_*.cpp
|
||||
@@ -52,3 +58,6 @@ triangles.conf
|
||||
*.key
|
||||
*.cert
|
||||
*.gpg
|
||||
*.o
|
||||
src/trianglesd
|
||||
src/obj/
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
# Triangles Codebase Cleanup Notes
|
||||
|
||||
## Overview
|
||||
Systematic code quality improvements for the Triangles cryptocurrency codebase (v5.3.4+).
|
||||
|
||||
**Goal:** Improve maintainability without changing behavior or breaking consensus.
|
||||
|
||||
## Inventory
|
||||
|
||||
### TODOs/FIXMEs Found (38 total)
|
||||
|
||||
#### High Priority (Affects Safety/Correctness)
|
||||
- `rpcmining.cpp:263` - **Thread safety issue** in mapNewBlock (static variable, no mutex)
|
||||
- `walletmodel.cpp:249` - **Potential collision** in balance calculation
|
||||
- `smessage.cpp:863, 2219, 2373` - **File size limit** (files must be split if >2GB)
|
||||
|
||||
#### Medium Priority (Encapsulation/Security)
|
||||
- `protocol.h:50, 100, 132` - Public members should be private (3 locations)
|
||||
- `wallet.h:378` - nOrderPos calculation should move elsewhere
|
||||
- `wallet.cpp:733, 1732` - Change output handling needs improvement
|
||||
- `rpcwallet.cpp:1474, 1513, 1569` - SecureString operator= missing (forced .c_str())
|
||||
|
||||
#### Low Priority (Nice-to-Have)
|
||||
- `util.cpp:1322` - Disabled feature needs verification
|
||||
- `tor/tor_embedded.cpp:209` - Tor 0.4.9+ shutdown API upgrade
|
||||
- `init.cpp:442` - Remaining sanity checks (see Bitcoin issue #4081)
|
||||
- `rpcmining.cpp:232` - DRM comment (unclear what it means)
|
||||
- `smessage.cpp:*` - Various improvements (hash inclusion, thread safety, defaults)
|
||||
- `qt/*` - UI improvements (decrypt not supported, message filtering, OSX startup)
|
||||
|
||||
#### External/Third-Party (Don't Touch)
|
||||
- `leveldb/*` - LevelDB library TODOs (upstream issues)
|
||||
|
||||
## Code Quality Issues
|
||||
|
||||
### Using namespace std (37 files)
|
||||
All in .cpp files - **this is fine for .cpp**, problematic only in headers.
|
||||
No headers have this issue, so **no action needed**.
|
||||
|
||||
### Printf/Cout Usage (56 files)
|
||||
Most cryptocurrency code uses printf for early init/error handling before logging is available.
|
||||
**Review needed:** Check if these are legitimate early-init cases or should use LogPrintf.
|
||||
|
||||
## Cleanup Plan (Safest → Riskiest)
|
||||
|
||||
### Phase 1: Documentation & Comments ✅ SAFE
|
||||
1. Document all TODOs with context (why deferred, what's needed)
|
||||
2. Add function-level comments for complex logic
|
||||
3. Improve inline comments for clarity
|
||||
|
||||
### Phase 2: Low-Risk Code Quality 🟨 MEDIUM RISK
|
||||
4. Fix compiler warnings (-Wall -Wextra)
|
||||
5. Add const correctness where missing
|
||||
6. Remove commented-out dead code
|
||||
7. Standardize code formatting (if inconsistent)
|
||||
|
||||
### Phase 3: Functional Improvements 🟥 HIGH RISK (Skip for now)
|
||||
8. Fix thread safety issue in rpcmining.cpp (requires testing)
|
||||
9. Improve protocol.h encapsulation (may affect other code)
|
||||
10. Address >2GB file handling in smessage.cpp
|
||||
|
||||
## Decisions
|
||||
|
||||
### What NOT to Change
|
||||
- **Consensus code** - main.cpp (validation), kernel.cpp (PoS), miner.cpp (staking)
|
||||
- **Serialization** - Any READWRITE, serialize/deserialize code
|
||||
- **Protocol constants** - Network message types, version numbers
|
||||
- **Third-party code** - leveldb/, tor/, sph_types.h, xxhash/, lz4/
|
||||
|
||||
### What's Safe to Change
|
||||
- Comments and documentation
|
||||
- Variable names (in non-consensus code)
|
||||
- Code organization (splitting large functions)
|
||||
- Logging statements
|
||||
- UI code (qt/)
|
||||
- RPC interface (as long as API contract preserved)
|
||||
|
||||
## Initial Cleanup (2026-03-22)
|
||||
|
||||
### Actions Taken
|
||||
1. Created this documentation file
|
||||
2. Created cleanup/desloppify branch
|
||||
3. Inventoried all TODOs/FIXMEs
|
||||
|
||||
### Next Steps
|
||||
1. Add documentation comments to TODO items
|
||||
2. Review printf/cout usage patterns
|
||||
3. Check for compiler warnings
|
||||
4. Consider low-risk improvements
|
||||
|
||||
## Notes
|
||||
- This is a Bitcoin-derived codebase, so many patterns follow Bitcoin Core conventions
|
||||
- Recent v5.3.x work already modernized to C++17 and removed Boost - good foundation
|
||||
- Code is generally well-structured; main improvements are documentation and minor cleanup
|
||||
@@ -0,0 +1,76 @@
|
||||
# Triangles Cleanup Strategy - Safe Improvements
|
||||
|
||||
**Branch:** `cleanup/safe-improvements`
|
||||
**Goal:** Improve code quality without touching consensus-critical code
|
||||
|
||||
## ✅ SAFE TO FIX
|
||||
|
||||
### 1. Compiler Warnings (Non-Consensus)
|
||||
- **C++11 literal-suffix warnings** - Add spaces between literals and suffixes
|
||||
- **Unused variables/functions** - Remove dead code (verify not consensus-critical first)
|
||||
- **Deprecated-copy warnings** - Fix CScript assignment operator if safe
|
||||
|
||||
### 2. Code Style Improvements
|
||||
- Remove `using namespace std` from headers (keep in .cpp files)
|
||||
- Standardize logging patterns
|
||||
- Improve code comments (remove unclear/misleading ones)
|
||||
- Add context to TODOs/FIXMEs
|
||||
|
||||
### 3. Documentation
|
||||
- Add inline comments for thread safety concerns
|
||||
- Document collision vulnerabilities
|
||||
- Improve function/class documentation
|
||||
|
||||
## ❌ DO NOT TOUCH
|
||||
|
||||
### Consensus-Critical Code
|
||||
- **OpenSSL SHA256/RIPEMD160 usage** - Deprecated warnings OK, do not change
|
||||
- **BN_is_prime_ex** - Crypto library deprecation, leave as-is
|
||||
- **Hash algorithms** - Third-party libraries with warnings, consensus-critical
|
||||
- **Block validation logic** - Any code affecting block/transaction validation
|
||||
- **Merkle tree construction** - Core consensus
|
||||
- **Proof-of-Work/Proof-of-Stake** - Staking/mining algorithms
|
||||
|
||||
### How to Identify Consensus Code
|
||||
- Files in `src/` related to: `main.cpp`, `main.h`, block validation, transaction validation
|
||||
- Anything in hash algorithm libraries
|
||||
- Cryptographic primitives
|
||||
- Network protocol message formats (version, serialization)
|
||||
|
||||
## Incremental Testing Strategy
|
||||
|
||||
1. **One warning category at a time**
|
||||
2. **Compile after each change**
|
||||
3. **Test basic functionality:**
|
||||
- `trianglesd getinfo`
|
||||
- `trianglesd getblockchaininfo`
|
||||
- Verify block sync works
|
||||
4. **Commit incrementally** with clear messages
|
||||
|
||||
## Warning Categories (From Build Output)
|
||||
|
||||
```
|
||||
1. C++11 literal-suffix: ~20 instances (util.h, net.h, alert.cpp)
|
||||
2. OpenSSL deprecation: SHA256, RIPEMD160 (DO NOT FIX)
|
||||
3. BN_is_prime_ex: crypto library (DO NOT FIX)
|
||||
4. Deprecated-copy: CScript assignment (REVIEW CAREFULLY)
|
||||
5. Unused variables/functions: Various (SAFE IF NOT CONSENSUS)
|
||||
```
|
||||
|
||||
## Branch History
|
||||
|
||||
- Previous work: `cleanup/desloppify` (documentation improvements, merged to master)
|
||||
- This branch: Focus on safe compiler warnings and code quality
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
Before pushing each commit:
|
||||
- [ ] Code compiles successfully
|
||||
- [ ] No new warnings introduced
|
||||
- [ ] trianglesd runs without errors
|
||||
- [ ] getinfo/getblockchaininfo work
|
||||
- [ ] No consensus-critical code touched
|
||||
|
||||
---
|
||||
|
||||
**Principle:** When in doubt, don't touch it. A clean codebase is worthless if the blockchain forks.
|
||||
@@ -0,0 +1,398 @@
|
||||
# Triangles Bootstrap Server Setup - DNS2
|
||||
|
||||
**For:** Krystie (@Krystie7777bot)
|
||||
**Server:** DNS2 (194.233.88.206) - Ubuntu
|
||||
**Date:** March 2026
|
||||
|
||||
---
|
||||
|
||||
## What This Server Does
|
||||
|
||||
Your server is the **bootstrap server** for the Triangles network. When someone opens a fresh Triangles wallet:
|
||||
|
||||
1. The wallet connects to `bootstrap.cryptographic-triangles.org` on **port 80**
|
||||
2. If that fails, it falls back to your IP directly: `194.233.88.206` on **port 80**
|
||||
3. It downloads `/filelist.txt` to see which blockchain files are available
|
||||
4. It downloads each file listed (mainly `blk0001.dat`, the entire blockchain)
|
||||
5. The user is now synced and ready to go
|
||||
|
||||
Your IP is hardcoded in the wallet. If your server is down, new users can't bootstrap.
|
||||
|
||||
Your server also runs the Triangles daemon so it doubles as a seed node on **port 24112**.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Install nginx
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y nginx curl
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Download the Daemon
|
||||
|
||||
No building required. Download the pre-built Linux binary from GitHub:
|
||||
|
||||
```bash
|
||||
cd /tmp
|
||||
curl -L -o trianglesd https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-daemon
|
||||
chmod +x trianglesd
|
||||
sudo mv trianglesd /usr/local/bin/
|
||||
```
|
||||
|
||||
Verify it works:
|
||||
|
||||
```bash
|
||||
trianglesd --version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Configure the Daemon
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.triangles
|
||||
|
||||
RPC_PASS=$(openssl rand -hex 32)
|
||||
|
||||
cat > ~/.triangles/triangles.conf << EOF
|
||||
port=24112
|
||||
listen=1
|
||||
maxconnections=125
|
||||
rpcport=19112
|
||||
rpcuser=trianglesrpc
|
||||
rpcpassword=$RPC_PASS
|
||||
rpcallowip=127.0.0.1
|
||||
server=1
|
||||
externalip=194.233.88.206
|
||||
addnode=74.208.167.19
|
||||
txindex=1
|
||||
daemon=1
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Get the Blockchain Data
|
||||
|
||||
OpenClaw will send you `blk0001.dat` (or a tarball containing it). Put it in `~/.triangles/`:
|
||||
|
||||
```bash
|
||||
cd ~/.triangles
|
||||
# If you received a tarball:
|
||||
tar xzf /path/to/blockchain-data.tar.gz
|
||||
# Or if you received blk0001.dat directly:
|
||||
cp /path/to/blk0001.dat ~/.triangles/
|
||||
```
|
||||
|
||||
After this step you should have:
|
||||
|
||||
```
|
||||
~/.triangles/blk0001.dat
|
||||
~/.triangles/triangles.conf
|
||||
```
|
||||
|
||||
Do NOT copy someone else's `wallet.dat` unless you intend to use that wallet.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Open Firewall Ports
|
||||
|
||||
You need **two** ports open:
|
||||
|
||||
```bash
|
||||
sudo ufw allow 80/tcp comment "Bootstrap HTTP server"
|
||||
sudo ufw allow 24112/tcp comment "Triangles P2P"
|
||||
sudo ufw enable
|
||||
sudo ufw status
|
||||
```
|
||||
|
||||
Verify both show ALLOW:
|
||||
|
||||
```
|
||||
80/tcp ALLOW Anywhere # Bootstrap HTTP server
|
||||
24112/tcp ALLOW Anywhere # Triangles P2P
|
||||
```
|
||||
|
||||
Do NOT open 19112 (RPC).
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Test the Daemon
|
||||
|
||||
```bash
|
||||
trianglesd
|
||||
```
|
||||
|
||||
Wait 10 seconds, then:
|
||||
|
||||
```bash
|
||||
trianglesd getinfo
|
||||
```
|
||||
|
||||
Look for:
|
||||
- `"blocks"` around 2,186,940 or higher
|
||||
- `"connections"` should become 1+ within a couple minutes
|
||||
|
||||
If it works, stop it:
|
||||
|
||||
```bash
|
||||
trianglesd stop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Set Up the Daemon as a systemd Service
|
||||
|
||||
```bash
|
||||
sudo tee /etc/systemd/system/trianglesd.service << 'EOF'
|
||||
[Unit]
|
||||
Description=Triangles Daemon
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStart=/usr/local/bin/trianglesd -daemon -datadir=/root/.triangles
|
||||
ExecStop=/usr/local/bin/trianglesd -datadir=/root/.triangles stop
|
||||
Restart=on-failure
|
||||
RestartSec=30
|
||||
TimeoutStopSec=120
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable trianglesd
|
||||
sudo systemctl start trianglesd
|
||||
```
|
||||
|
||||
If you're running as a non-root user, change `/root/.triangles` to `/home/youruser/.triangles`.
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
sudo systemctl status trianglesd
|
||||
trianglesd getinfo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Set Up the Bootstrap File Server
|
||||
|
||||
This is the main event.
|
||||
|
||||
### 8a. Create the bootstrap directory and tarball
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /var/www/triangles-bootstrap
|
||||
|
||||
# Create the compressed tarball from the blockchain data
|
||||
# Only blk0001.dat is needed - the wallet builds its own block index after download
|
||||
cd ~/.triangles
|
||||
tar czf /tmp/bootstrap.tar.gz blk0001.dat
|
||||
sudo mv /tmp/bootstrap.tar.gz /var/www/triangles-bootstrap/
|
||||
|
||||
# Also create the legacy fallback files (for older wallet versions)
|
||||
sudo cp ~/.triangles/blk0001.dat /var/www/triangles-bootstrap/
|
||||
sudo tee /var/www/triangles-bootstrap/filelist.txt << 'EOF'
|
||||
blk0001.dat
|
||||
EOF
|
||||
|
||||
sudo chown -R www-data:www-data /var/www/triangles-bootstrap
|
||||
```
|
||||
|
||||
The wallet tries to download `bootstrap.tar.gz` first (compressed, faster). If that's missing, it falls back to downloading `blk0001.dat` directly using `filelist.txt`. After download, the wallet automatically imports the blocks and builds its own index.
|
||||
|
||||
### 8b. Configure nginx
|
||||
|
||||
```bash
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
|
||||
sudo tee /etc/nginx/sites-available/triangles-bootstrap << 'EOF'
|
||||
server {
|
||||
listen 80;
|
||||
server_name bootstrap.cryptographic-triangles.org 194.233.88.206;
|
||||
|
||||
root /var/www/triangles-bootstrap;
|
||||
|
||||
location / {
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
send_timeout 600s;
|
||||
keepalive_timeout 600s;
|
||||
}
|
||||
EOF
|
||||
|
||||
sudo ln -sf /etc/nginx/sites-available/triangles-bootstrap /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
That should print `syntax is ok` and `test is successful`. Then:
|
||||
|
||||
```bash
|
||||
sudo systemctl enable nginx
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
### 8c. Verify it works
|
||||
|
||||
```bash
|
||||
# Should print "blk0001.dat"
|
||||
curl http://localhost/filelist.txt
|
||||
|
||||
# Should show HTTP 200 and a Content-Length
|
||||
curl -I http://localhost/blk0001.dat
|
||||
```
|
||||
|
||||
### 8d. Test from outside
|
||||
|
||||
Ask OpenClaw to test from another machine:
|
||||
|
||||
```bash
|
||||
curl -I http://194.233.88.206/bootstrap.tar.gz
|
||||
curl http://194.233.88.206/filelist.txt
|
||||
```
|
||||
|
||||
If both return HTTP 200, the bootstrap server is live.
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Keeping Bootstrap Data Fresh
|
||||
|
||||
Periodically rebuild the tarball from the latest blockchain data:
|
||||
|
||||
```bash
|
||||
sudo systemctl stop trianglesd
|
||||
cd ~/.triangles
|
||||
tar czf /tmp/bootstrap.tar.gz blk0001.dat
|
||||
sudo mv /tmp/bootstrap.tar.gz /var/www/triangles-bootstrap/
|
||||
sudo cp ~/.triangles/blk0001.dat /var/www/triangles-bootstrap/
|
||||
sudo chown -R www-data:www-data /var/www/triangles-bootstrap
|
||||
sudo systemctl start trianglesd
|
||||
```
|
||||
|
||||
Or set up a weekly cron job:
|
||||
|
||||
```bash
|
||||
sudo tee /etc/cron.d/triangles-bootstrap-update << 'EOF'
|
||||
0 4 * * 0 root systemctl stop trianglesd && cd /root/.triangles && tar czf /tmp/bootstrap.tar.gz blk0001.dat && mv /tmp/bootstrap.tar.gz /var/www/triangles-bootstrap/ && cp /root/.triangles/blk0001.dat /var/www/triangles-bootstrap/ && chown -R www-data:www-data /var/www/triangles-bootstrap && systemctl start trianglesd
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 10: Tor Hidden Service (Optional)
|
||||
|
||||
```bash
|
||||
sudo apt install -y tor
|
||||
```
|
||||
|
||||
Add to `/etc/tor/torrc`:
|
||||
|
||||
```
|
||||
HiddenServiceDir /var/lib/tor/triangles/
|
||||
HiddenServiceVersion 3
|
||||
HiddenServicePort 24112 127.0.0.1:24112
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart tor
|
||||
sudo cat /var/lib/tor/triangles/hostname
|
||||
```
|
||||
|
||||
Send the `.onion` address to OpenClaw, add `externalip=YOUR_ONION_ADDRESS.onion` to `triangles.conf`, and restart the daemon.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Bootstrap server isn't working
|
||||
|
||||
```bash
|
||||
sudo systemctl status nginx
|
||||
sudo ss -tlnp | grep :80
|
||||
ls -lh /var/www/triangles-bootstrap/
|
||||
curl http://localhost/filelist.txt
|
||||
sudo tail -30 /var/log/nginx/error.log
|
||||
```
|
||||
|
||||
### Daemon has 0 connections
|
||||
|
||||
```bash
|
||||
sudo ss -tlnp | grep 24112
|
||||
sudo ufw status
|
||||
trianglesd addnode 74.208.167.19 add
|
||||
```
|
||||
|
||||
### Daemon won't start
|
||||
|
||||
```bash
|
||||
tail -100 ~/.triangles/debug.log
|
||||
ps aux | grep trianglesd
|
||||
ls ~/.triangles/.lock
|
||||
```
|
||||
|
||||
### "Error loading block database"
|
||||
|
||||
```bash
|
||||
rm -rf ~/.triangles/txleveldb/
|
||||
sudo systemctl restart trianglesd
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | Where / Value |
|
||||
|------|---------------|
|
||||
| **Bootstrap files** | `/var/www/triangles-bootstrap/` |
|
||||
| **bootstrap.tar.gz** | `/var/www/triangles-bootstrap/bootstrap.tar.gz` |
|
||||
| **filelist.txt** | `/var/www/triangles-bootstrap/filelist.txt` (legacy fallback) |
|
||||
| **blk0001.dat (web)** | `/var/www/triangles-bootstrap/blk0001.dat` (legacy fallback) |
|
||||
| **nginx config** | `/etc/nginx/sites-available/triangles-bootstrap` |
|
||||
| **nginx logs** | `/var/log/nginx/error.log` |
|
||||
| Daemon binary | `/usr/local/bin/trianglesd` |
|
||||
| Data directory | `~/.triangles/` |
|
||||
| Config file | `~/.triangles/triangles.conf` |
|
||||
| Debug log | `~/.triangles/debug.log` |
|
||||
| P2P port | **24112** (must be open) |
|
||||
| HTTP port | **80** (must be open) |
|
||||
| RPC port | 19112 (localhost only) |
|
||||
| Restart daemon | `sudo systemctl restart trianglesd` |
|
||||
| Restart nginx | `sudo systemctl restart nginx` |
|
||||
| Other seed node | 74.208.167.19 (DNS3-Sami) |
|
||||
| Contact | OpenClaw on Telegram |
|
||||
|
||||
---
|
||||
|
||||
## You're Done
|
||||
|
||||
Once you've completed all the steps, your server is:
|
||||
|
||||
1. **A seed node** — other wallets discover and connect to you on port 24112
|
||||
2. **A bootstrap server** — new wallets download the blockchain from you on port 80
|
||||
|
||||
Send OpenClaw your `.onion` address (if you set up Tor) so it can be added to the wallet's onion seed list.
|
||||
|
||||
To confirm everything is running:
|
||||
|
||||
```bash
|
||||
# Daemon healthy?
|
||||
trianglesd getinfo
|
||||
|
||||
# nginx serving files?
|
||||
curl -I http://localhost/bootstrap.tar.gz
|
||||
|
||||
# Ports open externally?
|
||||
sudo ss -tlnp | grep -E ':(80|24112)\b'
|
||||
```
|
||||
|
||||
If all three check out, you're live on the Triangles network.
|
||||
@@ -3,7 +3,7 @@
|
||||
# Generated by qmake (3.1) (Qt 5.15.18)
|
||||
# Project: triangles-qt.pro
|
||||
# Template: app
|
||||
# Command: C:/msys64/mingw64/bin/qmake-qt5.exe -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
|
||||
# Command: C:/msys64/mingw64/bin/qmake-qt5.exe -o Makefile triangles-qt.pro
|
||||
#############################################################################
|
||||
|
||||
MAKEFILE = Makefile
|
||||
@@ -156,7 +156,7 @@ Makefile: triangles-qt.pro C:/msys64/mingw64/share/qt5/mkspecs/win32-g++/qmake.c
|
||||
C:/msys64/mingw64/lib/qtmain.prl \
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/features/build_pass.prf \
|
||||
src/qt/triangles.qrc
|
||||
$(QMAKE) -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
|
||||
$(QMAKE) -o Makefile triangles-qt.pro
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/features/spec_pre.prf:
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/qdevice.pri:
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/features/device_config.prf:
|
||||
@@ -244,7 +244,7 @@ C:/msys64/mingw64/lib/qtmain.prl:
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/features/build_pass.prf:
|
||||
src/qt/triangles.qrc:
|
||||
qmake: FORCE
|
||||
@$(QMAKE) -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
|
||||
@$(QMAKE) -o Makefile triangles-qt.pro
|
||||
|
||||
qmake_all: FORCE
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ make -j$(nproc) -f makefile.unix USE_UPNP=0
|
||||
strip trianglesd
|
||||
```
|
||||
|
||||
Run the unit test suite:
|
||||
```bash
|
||||
make -C src -f makefile.unix test
|
||||
```
|
||||
|
||||
### Linux (AlmaLinux 9 / RHEL 9)
|
||||
|
||||
Install dependencies:
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# TODO/FIXME Documentation
|
||||
|
||||
Detailed context for each TODO/FIXME in the codebase.
|
||||
|
||||
## Critical (Needs Attention)
|
||||
|
||||
### src/rpcmining.cpp:263 - Thread Safety Issue
|
||||
```cpp
|
||||
static mapNewBlock_t mapNewBlock; // FIXME: thread safety
|
||||
```
|
||||
**Issue:** Static variable accessed by multiple RPC threads without mutex protection.
|
||||
**Impact:** Potential race condition in getwork RPC (used for mining).
|
||||
**Status:** Low priority - PoW mining ended at block 9000, this code path rarely used.
|
||||
**Fix:** Add std::mutex and lock_guard if getwork usage increases.
|
||||
|
||||
### src/qt/walletmodel.cpp:249 - Collision Risk
|
||||
```cpp
|
||||
if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future
|
||||
```
|
||||
**Issue:** Balance check may have edge case causing transaction collisions.
|
||||
**Context:** In createTransaction fee calculation loop.
|
||||
**Status:** Needs investigation - unclear what "collisions" means here.
|
||||
**Fix:** Review Bitcoin Core's current implementation of this logic.
|
||||
|
||||
### src/smessage.cpp - File Size Limits
|
||||
```cpp
|
||||
// Lines 863, 2219, 2373: "TODO files must be split if > 2GB"
|
||||
```
|
||||
**Issue:** Secure message storage files not split when exceeding 2GB.
|
||||
**Impact:** May fail on 32-bit systems or with large message volumes.
|
||||
**Status:** Low priority - unlikely to reach 2GB in practice.
|
||||
**Fix:** Implement file rotation when approaching 2GB limit.
|
||||
|
||||
## Medium Priority (Encapsulation/API)
|
||||
|
||||
### src/protocol.h - Make Members Private
|
||||
```cpp
|
||||
// Lines 50, 100, 132: "TODO: make private (improves encapsulation)"
|
||||
```
|
||||
**Issue:** CAddress, CInv, CMessageHeader have public data members.
|
||||
**Impact:** Poor encapsulation, harder to maintain invariants.
|
||||
**Status:** Deferred - would require extensive refactoring.
|
||||
**Fix:** Add getter/setter methods, make members private, update all call sites.
|
||||
|
||||
### src/wallet.h:378 - nOrderPos Calculation
|
||||
```cpp
|
||||
nOrderPos = -1; // TODO: calculate elsewhere
|
||||
```
|
||||
**Issue:** Transaction ordering position calculated in constructor.
|
||||
**Impact:** Minor - works but not ideal separation of concerns.
|
||||
**Status:** Deferred - no functional issue.
|
||||
**Fix:** Move calculation to WalletDB when transaction is added.
|
||||
|
||||
### src/rpcwallet.cpp / src/qt/askpassphrasedialog.cpp - SecureString Conversion
|
||||
**Issue:** Password-handling paths were converting through `.c_str()` because `SecureString`
|
||||
did not have a convenient conversion helper from `std::string`.
|
||||
**Impact:** Unnecessary C-string shims in sensitive code paths.
|
||||
**Status:** Resolved.
|
||||
**Fix:** Added `MakeSecureString(const std::string&)` in `src/allocators.h` and updated
|
||||
the wallet RPC and passphrase dialog call sites to use it directly.
|
||||
|
||||
## Low Priority (Nice-to-Have)
|
||||
|
||||
### src/util.cpp:1322 - Disabled Feature
|
||||
```cpp
|
||||
// TODO: This is currently disabled because it needs to be verified to work
|
||||
```
|
||||
**Context:** File descriptor management code.
|
||||
**Status:** Intentionally disabled pending verification.
|
||||
**Fix:** Test thoroughly, then enable if needed.
|
||||
|
||||
### src/tor/tor_embedded.cpp:209 - Tor Shutdown API
|
||||
```cpp
|
||||
// TODO: Tor 0.4.9+ may add tor_api_shutdown(), use it when available
|
||||
```
|
||||
**Context:** Embedded Tor cleanup.
|
||||
**Status:** Waiting for upstream Tor API.
|
||||
**Fix:** Check Tor 0.4.9+ releases for new API, integrate when stable.
|
||||
|
||||
### src/init.cpp:442 - Sanity Checks
|
||||
```cpp
|
||||
// TODO: remaining sanity checks, see #4081
|
||||
```
|
||||
**Context:** Bitcoin Core issue #4081 - additional startup sanity checks.
|
||||
**Status:** Deferred - core checks already in place.
|
||||
**Fix:** Review Bitcoin Core's current sanity check implementation.
|
||||
|
||||
### src/rpcmining.cpp:232 - DRM Comment
|
||||
```cpp
|
||||
CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - DRM!
|
||||
```
|
||||
**Issue:** Unclear what "DRM" means here - likely "Data Race Maybe"?
|
||||
**Status:** Needs clarification from original author.
|
||||
**Fix:** Investigate if there's an actual issue, otherwise remove comment.
|
||||
|
||||
## Deferred (External/Low Impact)
|
||||
|
||||
### LevelDB TODOs (src/leveldb/*)
|
||||
**Status:** Upstream LevelDB issues - don't modify embedded library.
|
||||
**Action:** None - track upstream LevelDB project.
|
||||
|
||||
### Qt TODOs (src/qt/*)
|
||||
**Status:** UI improvements, not critical.
|
||||
**Action:** Track as nice-to-have enhancements.
|
||||
|
||||
### Secure Message TODOs (src/smessage.cpp)
|
||||
Multiple minor improvements suggested:
|
||||
- Include hash in certain operations
|
||||
- Improve thread shutdown
|
||||
- Set default recv/recvAnon behavior
|
||||
- Update outbox after PoW completes
|
||||
|
||||
**Status:** Non-critical enhancements.
|
||||
**Action:** Consider for future encrypted messaging upgrades.
|
||||
|
||||
## Summary
|
||||
|
||||
**Critical:** 3 items (thread safety, balance collision, file limits)
|
||||
**Medium:** 6 items (encapsulation, SecureString)
|
||||
**Low:** 5 items (disabled features, upstream APIs)
|
||||
**Deferred:** ~24 items (external libs, minor enhancements)
|
||||
|
||||
**Recommendation:** Focus on documenting critical items in code comments, defer fixes until specific issues arise.
|
||||
@@ -3,7 +3,7 @@
|
||||
# Run on a Linux x64 system with appimagetool installed
|
||||
set -e
|
||||
|
||||
VERSION="5.1.5"
|
||||
VERSION="5.3.7"
|
||||
APPDIR="Triangles-x86_64.AppDir"
|
||||
RELEASE_URL="https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${VERSION}"
|
||||
|
||||
@@ -17,7 +17,7 @@ mkdir -p "$APPDIR/usr/share/icons/hicolor/256x256/apps"
|
||||
|
||||
# Download binary
|
||||
echo "Downloading triangles-qt..."
|
||||
curl -L -o "$APPDIR/usr/bin/triangles-qt" "${RELEASE_URL}/triangles-qt-linux"
|
||||
curl -L -o "$APPDIR/usr/bin/triangles-qt" "${RELEASE_URL}/Cryptographic-Triangles-v${VERSION}-linux-x64-qt"
|
||||
chmod +x "$APPDIR/usr/bin/triangles-qt"
|
||||
|
||||
# Create desktop entry
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>org.cryptographic_triangles.TrianglesQt</id>
|
||||
<metadata_license>MIT</metadata_license>
|
||||
<project_license>MIT</project_license>
|
||||
<name>Cryptographic Triangles</name>
|
||||
<summary>TRI cryptocurrency wallet with staking and encrypted messaging</summary>
|
||||
|
||||
<description>
|
||||
<p>
|
||||
Cryptographic Triangles is a privacy-focused cryptocurrency wallet featuring
|
||||
Proof-of-Stake consensus, Tor v3 onion routing, and built-in encrypted messaging.
|
||||
</p>
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Proof-of-Stake with 33% annual staking rewards</li>
|
||||
<li>Hash9 algorithm (13-step hash cascade)</li>
|
||||
<li>Encrypted peer-to-peer messaging (SmsgMessage)</li>
|
||||
<li>Tor v3 integration for anonymous transactions</li>
|
||||
<li>Full node with built-in block explorer</li>
|
||||
</ul>
|
||||
</description>
|
||||
|
||||
<launchable type="desktop-id">org.cryptographic_triangles.TrianglesQt.desktop</launchable>
|
||||
|
||||
<icon type="stock">org.cryptographic_triangles.TrianglesQt</icon>
|
||||
|
||||
<categories>
|
||||
<category>Finance</category>
|
||||
<category>Network</category>
|
||||
<category>P2P</category>
|
||||
</categories>
|
||||
|
||||
<url type="homepage">https://cryptographic-triangles.org</url>
|
||||
<url type="bugtracker">https://github.com/SamiAhmed7777/triangles_v5/issues</url>
|
||||
<url type="vcs-browser">https://github.com/SamiAhmed7777/triangles_v5</url>
|
||||
|
||||
<provides>
|
||||
<binary>triangles-qt</binary>
|
||||
<binary>trianglesd</binary>
|
||||
</provides>
|
||||
|
||||
<releases>
|
||||
<release version="5.3.7" date="2026-03-24">
|
||||
<description>
|
||||
<p>Version 5.3.7 release.</p>
|
||||
</description>
|
||||
</release>
|
||||
<release version="5.3.6" date="2026-03-23">
|
||||
<description>
|
||||
<p>IBD sync optimizations, Linux build fixes, and modern compiler support.</p>
|
||||
</description>
|
||||
</release>
|
||||
<release version="5.2.0" date="2025-01-01">
|
||||
<description>
|
||||
<p>Tor v3 embedded support, OpenSSL 3.x compatibility, and Boost 1.90+ support.</p>
|
||||
</description>
|
||||
</release>
|
||||
</releases>
|
||||
|
||||
<content_rating type="oars-1.1" />
|
||||
|
||||
<supports>
|
||||
<control>pointing</control>
|
||||
<control>keyboard</control>
|
||||
</supports>
|
||||
</component>
|
||||
@@ -1,6 +1,6 @@
|
||||
# Maintainer: Cryptographic Triangles Team
|
||||
pkgname=triangles-qt-bin
|
||||
pkgver=5.1.5
|
||||
pkgver=5.3.7
|
||||
pkgrel=1
|
||||
pkgdesc="Cryptographic Triangles (TRI) cryptocurrency wallet - Qt GUI"
|
||||
arch=('x86_64')
|
||||
@@ -11,13 +11,13 @@ optdepends=('tor: anonymous networking support')
|
||||
provides=('triangles-qt' 'trianglesd')
|
||||
conflicts=('triangles-qt' 'trianglesd')
|
||||
source=(
|
||||
"triangles-qt-${pkgver}::https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${pkgver}/triangles-qt-linux"
|
||||
"trianglesd-${pkgver}::https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${pkgver}/trianglesd-linux"
|
||||
"triangles-qt-${pkgver}::https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${pkgver}/Cryptographic-Triangles-v${pkgver}-linux-x64-qt"
|
||||
"trianglesd-${pkgver}::https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${pkgver}/Cryptographic-Triangles-v${pkgver}-linux-x64-daemon"
|
||||
"triangles-qt.desktop"
|
||||
)
|
||||
sha256sums=(
|
||||
'19eaadfdf18b899ce8434fe714e690e2db0546597e36037de37a29854fc23aeb'
|
||||
'6f5c19d34a2e1f6cdadee095d9e11b25d18b41a0d1602a163ffca7ec80b3da37'
|
||||
'ed220eb8d0b403f62cdac28988541fd1a27864491e233216f9c00a4c2537b4a3'
|
||||
'4d2ab25d61127d6aff3e6f3069556d04f4b823f8849e97629c12871ad4779517'
|
||||
'SKIP'
|
||||
)
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ $ErrorActionPreference = 'Stop'
|
||||
$packageArgs = @{
|
||||
packageName = 'triangles'
|
||||
unzipLocation = "$(Split-Path -Parent $MyInvocation.MyCommand.Definition)"
|
||||
url64bit = 'https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/Triangles-v5.1.5-win-x64.zip'
|
||||
checksum64 = '777e475f366164b342e917111bcf3155ec39e0ab4bd97b2ac295885ad30a93c6'
|
||||
url64bit = 'https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-5.3.7-win-x64.zip'
|
||||
checksum64 = '6f002a669a7e92aaf3d8dd7b1ae80f06a086c99a15ca05cf107665009ffc06b7'
|
||||
checksumType64 = 'sha256'
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>triangles</id>
|
||||
<version>5.1.5</version>
|
||||
<version>5.3.7</version>
|
||||
<title>Cryptographic Triangles</title>
|
||||
<authors>Cryptographic Triangles Team</authors>
|
||||
<owners>SamiAhmed7777</owners>
|
||||
@@ -25,6 +25,6 @@ featuring the unique Hash9 algorithm (13-step hash cascade).
|
||||
- Encrypted peer-to-peer messaging
|
||||
- Tor v3 integration for anonymous transactions
|
||||
</description>
|
||||
<releaseNotes>https://github.com/SamiAhmed7777/triangles_v5/releases/tag/v5.1.5</releaseNotes>
|
||||
<releaseNotes>https://github.com/SamiAhmed7777/triangles_v5/releases/tag/v5.3.7</releaseNotes>
|
||||
</metadata>
|
||||
</package>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Package: triangles
|
||||
Version: 5.1.5-1
|
||||
Version: 5.3.7-1
|
||||
Section: net
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Run from the packaging/debian directory
|
||||
set -e
|
||||
|
||||
VERSION="5.1.5"
|
||||
VERSION="5.3.7"
|
||||
PKGDIR="triangles_${VERSION}-1_amd64"
|
||||
RELEASE_URL="https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${VERSION}"
|
||||
|
||||
@@ -20,8 +20,8 @@ cp DEBIAN/control "$PKGDIR/DEBIAN/"
|
||||
|
||||
# Download binaries
|
||||
echo "Downloading binaries..."
|
||||
curl -L -o "$PKGDIR/usr/bin/triangles-qt" "${RELEASE_URL}/triangles-qt-linux"
|
||||
curl -L -o "$PKGDIR/usr/bin/trianglesd" "${RELEASE_URL}/trianglesd-linux"
|
||||
curl -L -o "$PKGDIR/usr/bin/triangles-qt" "${RELEASE_URL}/Cryptographic-Triangles-v${VERSION}-linux-x64-qt"
|
||||
curl -L -o "$PKGDIR/usr/bin/trianglesd" "${RELEASE_URL}/Cryptographic-Triangles-v${VERSION}-linux-x64-daemon"
|
||||
chmod 755 "$PKGDIR/usr/bin/triangles-qt" "$PKGDIR/usr/bin/trianglesd"
|
||||
|
||||
# Create desktop entry
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
LABEL maintainer="Cryptographic Triangles Team"
|
||||
LABEL description="Cryptographic Triangles (TRI) headless daemon"
|
||||
LABEL version="5.3.7"
|
||||
|
||||
ARG VERSION=5.3.7
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
libssl3 \
|
||||
libevent-2.1-7 \
|
||||
libboost-system1.74.0 \
|
||||
libboost-filesystem1.74.0 \
|
||||
libboost-program-options1.74.0 \
|
||||
libboost-thread1.74.0 \
|
||||
libboost-chrono1.74.0 \
|
||||
libdb5.3++ \
|
||||
libminiupnpc17 \
|
||||
tor \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl -L -o /usr/local/bin/trianglesd \
|
||||
"https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${VERSION}/Cryptographic-Triangles-v${VERSION}-linux-x64-daemon" \
|
||||
&& chmod +x /usr/local/bin/trianglesd
|
||||
|
||||
RUN useradd -m -s /bin/bash triangles
|
||||
|
||||
USER triangles
|
||||
WORKDIR /home/triangles
|
||||
|
||||
RUN mkdir -p /home/triangles/.triangles
|
||||
|
||||
VOLUME /home/triangles/.triangles
|
||||
|
||||
EXPOSE 24112 19112
|
||||
|
||||
ENTRYPOINT ["trianglesd"]
|
||||
CMD ["-daemon=0", "-printtoconsole"]
|
||||
@@ -0,0 +1,17 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
trianglesd:
|
||||
build: .
|
||||
image: cryptographic-triangles/trianglesd:5.3.7
|
||||
container_name: trianglesd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "24112:24112"
|
||||
- "19112:19112"
|
||||
volumes:
|
||||
- triangles-data:/home/triangles/.triangles
|
||||
command: ["-daemon=0", "-printtoconsole", "-rpcallowip=172.16.0.0/12"]
|
||||
|
||||
volumes:
|
||||
triangles-data:
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"only-arches": ["x86_64"]
|
||||
}
|
||||
@@ -19,13 +19,35 @@ modules:
|
||||
build-commands:
|
||||
- install -Dm755 triangles-qt-linux /app/bin/triangles-qt
|
||||
- install -Dm644 triangles-qt.desktop /app/share/applications/org.cryptographic_triangles.TrianglesQt.desktop
|
||||
- install -Dm644 triangles.svg /app/share/icons/hicolor/scalable/apps/org.cryptographic_triangles.TrianglesQt.svg
|
||||
- install -Dm644 triangles-128.png /app/share/icons/hicolor/128x128/apps/org.cryptographic_triangles.TrianglesQt.png
|
||||
- install -Dm644 triangles-256.png /app/share/icons/hicolor/256x256/apps/org.cryptographic_triangles.TrianglesQt.png
|
||||
- install -Dm644 org.cryptographic_triangles.TrianglesQt.metainfo.xml /app/share/metainfo/org.cryptographic_triangles.TrianglesQt.metainfo.xml
|
||||
sources:
|
||||
- type: file
|
||||
url: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/triangles-qt-linux
|
||||
sha256: 19eaadfdf18b899ce8434fe714e690e2db0546597e36037de37a29854fc23aeb
|
||||
url: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-qt
|
||||
sha256: ed220eb8d0b403f62cdac28988541fd1a27864491e233216f9c00a4c2537b4a3
|
||||
dest-filename: triangles-qt-linux
|
||||
- type: file
|
||||
path: triangles-qt.desktop
|
||||
url: https://raw.githubusercontent.com/SamiAhmed7777/triangles_v5/master/packaging/flatpak/triangles-qt.desktop
|
||||
sha256: f56c4be5870fed6d3f0fb74398241ea909bd3b6f3305fe06ef5f58fba25602ca
|
||||
dest-filename: triangles-qt.desktop
|
||||
- type: file
|
||||
url: https://raw.githubusercontent.com/SamiAhmed7777/triangles_v5/master/src/qt/res/src/triangles.svg
|
||||
sha256: c08d0731e209b1941606709d7236526c4334ee52d1cbda2173cad417d6169486
|
||||
dest-filename: triangles.svg
|
||||
- type: file
|
||||
url: https://raw.githubusercontent.com/SamiAhmed7777/triangles_v5/master/src/qt/res/icons/triangles-128.png
|
||||
sha256: 3a9030b2141ba822059e1d32c29f004c5ed9a4d3c8fc1fba6188201cfdf4ccf5
|
||||
dest-filename: triangles-128.png
|
||||
- type: file
|
||||
url: https://raw.githubusercontent.com/SamiAhmed7777/triangles_v5/master/src/qt/res/icons/triangles.png
|
||||
sha256: eebe5b1890c4cf43b8ae3160f81bac93a2a10cd221c99815de9fcd850f225f4e
|
||||
dest-filename: triangles-256.png
|
||||
- type: file
|
||||
url: https://raw.githubusercontent.com/SamiAhmed7777/triangles_v5/master/packaging/appstream/org.cryptographic_triangles.TrianglesQt.metainfo.xml
|
||||
sha256: dd5ecf9f4916cf0ef3d7ceec763dbbbcf7c4bf806be1e404a96dcfc9423c9fad
|
||||
dest-filename: org.cryptographic_triangles.TrianglesQt.metainfo.xml
|
||||
|
||||
- name: trianglesd
|
||||
buildsystem: simple
|
||||
@@ -33,6 +55,6 @@ modules:
|
||||
- install -Dm755 trianglesd-linux /app/bin/trianglesd
|
||||
sources:
|
||||
- type: file
|
||||
url: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/trianglesd-linux
|
||||
sha256: 6f5c19d34a2e1f6cdadee095d9e11b25d18b41a0d1602a163ffca7ec80b3da37
|
||||
url: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-daemon
|
||||
sha256: 4d2ab25d61127d6aff3e6f3069556d04f4b823f8849e97629c12871ad4779517
|
||||
dest-filename: trianglesd-linux
|
||||
|
||||
@@ -2,21 +2,16 @@ class Triangles < Formula
|
||||
desc "Cryptographic Triangles (TRI) cryptocurrency wallet and daemon"
|
||||
homepage "https://cryptographic-triangles.org"
|
||||
license "MIT"
|
||||
version "5.1.5"
|
||||
version "5.3.7"
|
||||
|
||||
on_macos do
|
||||
if Hardware::CPU.intel?
|
||||
url "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/Cryptographic-Triangles-v5.1.5-macos-x64.dmg"
|
||||
sha256 "PLACEHOLDER_X64_HASH"
|
||||
else
|
||||
url "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/Cryptographic-Triangles-v5.1.5-macos-arm64.dmg"
|
||||
sha256 "PLACEHOLDER_ARM64_HASH"
|
||||
end
|
||||
url "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-macos-arm64.dmg"
|
||||
sha256 "3a58e795d898656b455fd639c0ea826a4457d390a64d00ace9a1257598d053be"
|
||||
end
|
||||
|
||||
on_linux do
|
||||
url "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/trianglesd-linux"
|
||||
sha256 "6f5c19d34a2e1f6cdadee095d9e11b25d18b41a0d1602a163ffca7ec80b3da37"
|
||||
url "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-daemon"
|
||||
sha256 "4d2ab25d61127d6aff3e6f3069556d04f4b823f8849e97629c12871ad4779517"
|
||||
end
|
||||
|
||||
depends_on "openssl@3"
|
||||
@@ -26,7 +21,7 @@ class Triangles < Formula
|
||||
prefix.install "Triangles-Qt.app"
|
||||
bin.write_exec_script prefix/"Triangles-Qt.app/Contents/MacOS/Triangles-Qt"
|
||||
else
|
||||
bin.install "trianglesd-linux" => "trianglesd"
|
||||
bin.install "Cryptographic-Triangles-v5.3.7-linux-x64-daemon" => "trianglesd"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
}:
|
||||
|
||||
let
|
||||
version = "5.1.5";
|
||||
version = "5.3.7";
|
||||
|
||||
desktopItem = makeDesktopItem {
|
||||
name = "triangles-qt";
|
||||
@@ -34,13 +34,13 @@ stdenv.mkDerivation {
|
||||
|
||||
srcs = [
|
||||
(fetchurl {
|
||||
url = "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${version}/triangles-qt-linux";
|
||||
sha256 = "19eaadfdf18b899ce8434fe714e690e2db0546597e36037de37a29854fc23aeb";
|
||||
url = "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${version}/Cryptographic-Triangles-v${version}-linux-x64-qt";
|
||||
sha256 = "ed220eb8d0b403f62cdac28988541fd1a27864491e233216f9c00a4c2537b4a3";
|
||||
name = "triangles-qt-linux";
|
||||
})
|
||||
(fetchurl {
|
||||
url = "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${version}/trianglesd-linux";
|
||||
sha256 = "6f5c19d34a2e1f6cdadee095d9e11b25d18b41a0d1602a163ffca7ec80b3da37";
|
||||
url = "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${version}/Cryptographic-Triangles-v${version}-linux-x64-daemon";
|
||||
sha256 = "4d2ab25d61127d6aff3e6f3069556d04f4b823f8849e97629c12871ad4779517";
|
||||
name = "trianglesd-linux";
|
||||
})
|
||||
];
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Install build tools: sudo dnf install rpm-build rpmdevtools
|
||||
set -e
|
||||
|
||||
VERSION="5.1.5"
|
||||
VERSION="5.3.7"
|
||||
RELEASE_URL="https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${VERSION}"
|
||||
|
||||
echo "Building RPM for Triangles v${VERSION}..."
|
||||
@@ -14,8 +14,8 @@ rpmdev-setuptree
|
||||
|
||||
# Download sources into SOURCES
|
||||
echo "Downloading binaries..."
|
||||
curl -L -o ~/rpmbuild/SOURCES/triangles-qt-linux "${RELEASE_URL}/triangles-qt-linux"
|
||||
curl -L -o ~/rpmbuild/SOURCES/trianglesd-linux "${RELEASE_URL}/trianglesd-linux"
|
||||
curl -L -o ~/rpmbuild/SOURCES/Cryptographic-Triangles-v${VERSION}-linux-x64-qt "${RELEASE_URL}/Cryptographic-Triangles-v${VERSION}-linux-x64-qt"
|
||||
curl -L -o ~/rpmbuild/SOURCES/Cryptographic-Triangles-v${VERSION}-linux-x64-daemon "${RELEASE_URL}/Cryptographic-Triangles-v${VERSION}-linux-x64-daemon"
|
||||
cp triangles-qt.desktop ~/rpmbuild/SOURCES/
|
||||
|
||||
# Copy spec file
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Name: triangles
|
||||
Version: 5.1.5
|
||||
Version: 5.3.7
|
||||
Release: 1%{?dist}
|
||||
Summary: Cryptographic Triangles (TRI) cryptocurrency wallet
|
||||
License: MIT
|
||||
URL: https://cryptographic-triangles.org
|
||||
Source0: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v%{version}/triangles-qt-linux
|
||||
Source1: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v%{version}/trianglesd-linux
|
||||
Source0: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v%{version}/Cryptographic-Triangles-v%{version}-linux-x64-qt
|
||||
Source1: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v%{version}/Cryptographic-Triangles-v%{version}-linux-x64-daemon
|
||||
Source2: triangles-qt.desktop
|
||||
|
||||
BuildArch: x86_64
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
PackageIdentifier: CryptographicTriangles.TrianglesQt
|
||||
PackageVersion: 5.1.5
|
||||
PackageVersion: 5.3.7
|
||||
PackageLocale: en-US
|
||||
Publisher: Cryptographic Triangles
|
||||
PublisherUrl: https://cryptographic-triangles.org
|
||||
@@ -27,7 +27,7 @@ Installers:
|
||||
- RelativeFilePath: triangles-qt.exe
|
||||
PortableCommandAlias: triangles-qt
|
||||
ArchiveBinariesDependOnPath: true
|
||||
InstallerUrl: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/Triangles-v5.1.5-win-x64.zip
|
||||
InstallerSha256: 777e475f366164b342e917111bcf3155ec39e0ab4bd97b2ac295885ad30a93c6
|
||||
InstallerUrl: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-5.3.7-win-x64.zip
|
||||
InstallerSha256: 6F002A669A7E92AAF3D8DD7B1AE80F06A086C99A15CA05CF107665009FFC06B7
|
||||
ManifestType: singleton
|
||||
ManifestVersion: 1.6.0
|
||||
|
||||
+11
-5
@@ -1,6 +1,6 @@
|
||||
name: triangles
|
||||
base: core22
|
||||
version: '5.1.5'
|
||||
version: '5.3.7'
|
||||
summary: Cryptographic Triangles (TRI) cryptocurrency wallet
|
||||
description: |
|
||||
Privacy-focused cryptocurrency featuring Proof-of-Stake consensus,
|
||||
@@ -51,10 +51,10 @@ apps:
|
||||
parts:
|
||||
triangles:
|
||||
plugin: dump
|
||||
source: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/triangles-qt-linux
|
||||
source: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-qt
|
||||
source-type: file
|
||||
organize:
|
||||
triangles-qt-linux: bin/triangles-qt
|
||||
Cryptographic-Triangles-v5.3.7-linux-x64-qt: bin/triangles-qt
|
||||
stage-packages:
|
||||
- libqt5widgets5
|
||||
- libqt5gui5
|
||||
@@ -73,13 +73,19 @@ parts:
|
||||
|
||||
trianglesd:
|
||||
plugin: dump
|
||||
source: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/trianglesd-linux
|
||||
source: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-daemon
|
||||
source-type: file
|
||||
organize:
|
||||
trianglesd-linux: bin/trianglesd
|
||||
Cryptographic-Triangles-v5.3.7-linux-x64-daemon: bin/trianglesd
|
||||
|
||||
desktop-entry:
|
||||
plugin: dump
|
||||
source: snap/gui
|
||||
organize:
|
||||
triangles-qt.desktop: share/applications/triangles-qt.desktop
|
||||
|
||||
appstream:
|
||||
plugin: dump
|
||||
source: packaging/appstream
|
||||
organize:
|
||||
org.cryptographic_triangles.TrianglesQt.metainfo.xml: share/metainfo/org.cryptographic_triangles.TrianglesQt.metainfo.xml
|
||||
|
||||
+2
-2
@@ -53,8 +53,8 @@ std::string CUnsignedAlert::ToString() const
|
||||
return strprintf(
|
||||
"CAlert(\n"
|
||||
" nVersion = %d\n"
|
||||
" nRelayUntil = %"PRId64"\n"
|
||||
" nExpiration = %"PRId64"\n"
|
||||
" nRelayUntil = %" PRId64 "\n"
|
||||
" nExpiration = %" PRId64 "\n"
|
||||
" nID = %d\n"
|
||||
" nCancel = %d\n"
|
||||
" setCancel = %s\n"
|
||||
|
||||
@@ -254,4 +254,9 @@ struct zero_after_free_allocator : public std::allocator<T>
|
||||
// This is exactly like std::string, but with a custom allocator.
|
||||
typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
|
||||
|
||||
static inline SecureString MakeSecureString(const std::string& value)
|
||||
{
|
||||
return SecureString(value.begin(), value.end());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,9 +8,20 @@
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "version.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
// Forward declarations to avoid pulling in heavy consensus headers
|
||||
extern bool fTestNet;
|
||||
namespace Checkpoints { bool IsKnownCheckpoint(int nHeight, const uint256& hash); }
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
using boost::asio::ip::tcp;
|
||||
@@ -181,4 +192,340 @@ bool FetchFileList(const std::string& host,
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- tar.gz bootstrap support ---
|
||||
|
||||
namespace {
|
||||
|
||||
// Parse a tar octal field (ASCII octal, null/space terminated)
|
||||
static int64_t ParseTarOctal(const char* field, size_t len)
|
||||
{
|
||||
int64_t result = 0;
|
||||
for (size_t i = 0; i < len && field[i] != '\0' && field[i] != ' '; i++) {
|
||||
if (field[i] < '0' || field[i] > '7') continue;
|
||||
result = (result << 3) | (field[i] - '0');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Extract a tar.gz file to a destination directory
|
||||
static bool ExtractTarGz(const fs::path& tarGzPath,
|
||||
const fs::path& destDir,
|
||||
std::string& strError)
|
||||
{
|
||||
gzFile gz = gzopen(tarGzPath.string().c_str(), "rb");
|
||||
if (!gz) {
|
||||
strError = "Cannot open " + tarGzPath.string();
|
||||
return false;
|
||||
}
|
||||
|
||||
gzbuffer(gz, 262144); // 256 KB buffer for performance
|
||||
|
||||
char header[512];
|
||||
|
||||
while (true) {
|
||||
int bytesRead = gzread(gz, header, 512);
|
||||
if (bytesRead == 0) break; // EOF
|
||||
if (bytesRead != 512) {
|
||||
strError = "Truncated tar header";
|
||||
gzclose(gz);
|
||||
return false;
|
||||
}
|
||||
|
||||
// End-of-archive marker (zero block)
|
||||
bool allZero = true;
|
||||
for (int i = 0; i < 512; i++) {
|
||||
if (header[i] != 0) { allZero = false; break; }
|
||||
}
|
||||
if (allZero) break;
|
||||
|
||||
// Parse filename: name (offset 0, 100 bytes) + optional prefix (offset 345, 155 bytes)
|
||||
char name[101] = {0};
|
||||
char prefix[156] = {0};
|
||||
memcpy(name, header, 100);
|
||||
memcpy(prefix, header + 345, 155);
|
||||
|
||||
std::string fullName;
|
||||
if (prefix[0] != '\0')
|
||||
fullName = std::string(prefix) + "/" + std::string(name);
|
||||
else
|
||||
fullName = std::string(name);
|
||||
|
||||
// Security: reject absolute paths and path traversal
|
||||
if (fullName.empty() || fullName[0] == '/' || fullName.find("..") != std::string::npos) {
|
||||
strError = "Unsafe path in tar archive: " + fullName;
|
||||
gzclose(gz);
|
||||
return false;
|
||||
}
|
||||
|
||||
char typeflag = header[156];
|
||||
int64_t fileSize = ParseTarOctal(header + 124, 12);
|
||||
|
||||
if (typeflag == '5' || (!fullName.empty() && fullName.back() == '/')) {
|
||||
// Directory entry
|
||||
fs::create_directories(destDir / fullName);
|
||||
} else if (typeflag == '0' || typeflag == '\0') {
|
||||
// Regular file
|
||||
fs::path filePath = destDir / fullName;
|
||||
fs::create_directories(filePath.parent_path());
|
||||
|
||||
FILE* outFile = fopen(filePath.string().c_str(), "wb");
|
||||
if (!outFile) {
|
||||
strError = "Cannot create file: " + filePath.string();
|
||||
gzclose(gz);
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t remaining = fileSize;
|
||||
char buf[65536];
|
||||
while (remaining > 0) {
|
||||
int toRead = (remaining > (int64_t)sizeof(buf)) ? (int)sizeof(buf) : (int)remaining;
|
||||
int n = gzread(gz, buf, toRead);
|
||||
if (n <= 0) {
|
||||
fclose(outFile);
|
||||
strError = "Truncated tar data for: " + fullName;
|
||||
gzclose(gz);
|
||||
return false;
|
||||
}
|
||||
fwrite(buf, 1, n, outFile);
|
||||
remaining -= n;
|
||||
}
|
||||
fclose(outFile);
|
||||
|
||||
// Skip padding to next 512-byte boundary
|
||||
int64_t pad = (512 - (fileSize % 512)) % 512;
|
||||
if (pad > 0) {
|
||||
char padBuf[512];
|
||||
if (gzread(gz, padBuf, (unsigned)pad) != (int)pad) {
|
||||
strError = "Truncated tar padding for: " + fullName;
|
||||
gzclose(gz);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unknown entry type - skip its data
|
||||
int64_t totalSkip = fileSize + ((512 - (fileSize % 512)) % 512);
|
||||
char skipBuf[512];
|
||||
while (totalSkip > 0) {
|
||||
int toRead = (totalSkip > 512) ? 512 : (int)totalSkip;
|
||||
if (gzread(gz, skipBuf, toRead) != toRead) break;
|
||||
totalSkip -= toRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gzclose(gz);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool ParseManifest(const fs::path& manifestPath,
|
||||
SnapshotManifest& manifest,
|
||||
std::string& strError)
|
||||
{
|
||||
std::ifstream in(manifestPath.string().c_str());
|
||||
if (!in.is_open()) {
|
||||
strError = "Cannot open " + manifestPath.string();
|
||||
return false;
|
||||
}
|
||||
|
||||
manifest.format = 0;
|
||||
manifest.network.clear();
|
||||
manifest.height = -1;
|
||||
manifest.hash.clear();
|
||||
manifest.dbversion = 0;
|
||||
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
boost::trim(line);
|
||||
if (line.empty() || line[0] == '#')
|
||||
continue;
|
||||
|
||||
size_t eq = line.find('=');
|
||||
if (eq == std::string::npos)
|
||||
continue;
|
||||
|
||||
std::string key = line.substr(0, eq);
|
||||
std::string val = line.substr(eq + 1);
|
||||
boost::trim(key);
|
||||
boost::trim(val);
|
||||
|
||||
if (key == "format")
|
||||
manifest.format = std::atoi(val.c_str());
|
||||
else if (key == "network")
|
||||
manifest.network = val;
|
||||
else if (key == "height")
|
||||
manifest.height = std::atoi(val.c_str());
|
||||
else if (key == "hash")
|
||||
manifest.hash = val;
|
||||
else if (key == "dbversion")
|
||||
manifest.dbversion = std::atoi(val.c_str());
|
||||
}
|
||||
in.close();
|
||||
|
||||
if (manifest.format == 0) {
|
||||
strError = "Manifest missing 'format' field";
|
||||
return false;
|
||||
}
|
||||
if (manifest.network.empty()) {
|
||||
strError = "Manifest missing 'network' field";
|
||||
return false;
|
||||
}
|
||||
if (manifest.height < 0) {
|
||||
strError = "Manifest missing or invalid 'height' field";
|
||||
return false;
|
||||
}
|
||||
if (manifest.hash.empty()) {
|
||||
strError = "Manifest missing 'hash' field";
|
||||
return false;
|
||||
}
|
||||
if (manifest.dbversion == 0) {
|
||||
strError = "Manifest missing 'dbversion' field";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VerifyManifest(const SnapshotManifest& manifest,
|
||||
std::string& strError)
|
||||
{
|
||||
if (manifest.format != 1) {
|
||||
strError = "Unsupported manifest format: " + std::to_string(manifest.format);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string expectedNetwork = fTestNet ? "test" : "main";
|
||||
if (manifest.network != expectedNetwork) {
|
||||
strError = "Network mismatch: manifest says '" + manifest.network
|
||||
+ "', expected '" + expectedNetwork + "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (manifest.dbversion != DATABASE_VERSION) {
|
||||
strError = "DB version mismatch: manifest says "
|
||||
+ std::to_string(manifest.dbversion)
|
||||
+ ", binary expects " + std::to_string(DATABASE_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint256 manifestHash(manifest.hash);
|
||||
if (manifestHash == 0) {
|
||||
strError = "Invalid hash in manifest: " + manifest.hash;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Checkpoints::IsKnownCheckpoint(manifest.height, manifestHash)) {
|
||||
strError = "Height " + std::to_string(manifest.height)
|
||||
+ " / hash " + manifest.hash
|
||||
+ " is not a known checkpoint";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DownloadBootstrap(const std::string& host,
|
||||
const fs::path& dataDir,
|
||||
ProgressCallback progressFn,
|
||||
std::string& strError)
|
||||
{
|
||||
bool gotBlockFile = false;
|
||||
|
||||
// Try downloading bootstrap.tar.gz first
|
||||
fs::path tmpTarGz = dataDir / "bootstrap.tar.gz.tmp";
|
||||
std::string tarUrl = std::string(BASE_PATH) + "bootstrap.tar.gz";
|
||||
|
||||
bool tarDownloaded = DownloadFile(host, tarUrl, tmpTarGz, progressFn, strError);
|
||||
|
||||
if (tarDownloaded) {
|
||||
bool extractOk = ExtractTarGz(tmpTarGz, dataDir, strError);
|
||||
fs::remove(tmpTarGz);
|
||||
|
||||
if (extractOk && fs::exists(dataDir / "blk0001.dat"))
|
||||
gotBlockFile = true;
|
||||
// If extraction failed, fall through to legacy path
|
||||
}
|
||||
|
||||
if (!gotBlockFile) {
|
||||
// Fallback: try filelist.txt + individual file downloads
|
||||
std::string fallbackError;
|
||||
std::vector<std::string> files;
|
||||
if (!FetchFileList(host, files, fallbackError)) {
|
||||
if (!tarDownloaded)
|
||||
strError = strError + " (fallback also failed: " + fallbackError + ")";
|
||||
else
|
||||
strError = "Extraction failed: " + strError + " (fallback also failed: " + fallbackError + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < files.size(); i++) {
|
||||
fs::path destPath = dataDir / files[i];
|
||||
fs::create_directories(destPath.parent_path());
|
||||
|
||||
std::string urlPath = std::string(BASE_PATH) + files[i];
|
||||
if (!DownloadFile(host, urlPath, destPath, progressFn, strError))
|
||||
return false;
|
||||
}
|
||||
|
||||
gotBlockFile = fs::exists(dataDir / "blk0001.dat");
|
||||
}
|
||||
|
||||
if (!gotBlockFile) {
|
||||
strError = "No blk0001.dat after download";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the archive included a trusted pre-built index (txleveldb/)
|
||||
// with a valid snapshot.manifest. If verified, keep it to skip the
|
||||
// multi-hour FastImportBlockFile() rebuild.
|
||||
fs::path txleveldb = dataDir / "txleveldb";
|
||||
fs::path database = dataDir / "database";
|
||||
fs::path manifestPath = dataDir / "snapshot.manifest";
|
||||
|
||||
bool keepIndex = false;
|
||||
|
||||
if (fs::exists(manifestPath) && fs::exists(txleveldb)) {
|
||||
SnapshotManifest manifest;
|
||||
std::string manifestError;
|
||||
|
||||
if (ParseManifest(manifestPath, manifest, manifestError)) {
|
||||
printf("Bootstrap: snapshot.manifest found (format=%d, network=%s, "
|
||||
"height=%d, dbversion=%d)\n",
|
||||
manifest.format, manifest.network.c_str(),
|
||||
manifest.height, manifest.dbversion);
|
||||
|
||||
if (VerifyManifest(manifest, manifestError)) {
|
||||
printf("Bootstrap: manifest verified - keeping pre-built index "
|
||||
"(height %d, checkpoint match)\n", manifest.height);
|
||||
keepIndex = true;
|
||||
} else {
|
||||
printf("Bootstrap: manifest verification failed: %s\n",
|
||||
manifestError.c_str());
|
||||
}
|
||||
} else {
|
||||
printf("Bootstrap: cannot parse snapshot.manifest: %s\n",
|
||||
manifestError.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepIndex) {
|
||||
// No valid manifest or verification failed - delete the index.
|
||||
// FastImportBlockFile() will rebuild from blk0001.dat on next startup.
|
||||
printf("Bootstrap: removing extracted txleveldb/ (will rebuild index from blk0001.dat)\n");
|
||||
if (fs::exists(txleveldb))
|
||||
fs::remove_all(txleveldb);
|
||||
}
|
||||
|
||||
// Always remove BDB database/ dir (wallet environment from another machine)
|
||||
if (fs::exists(database))
|
||||
fs::remove_all(database);
|
||||
|
||||
// Clean up manifest file (not needed after verification)
|
||||
if (fs::exists(manifestPath))
|
||||
fs::remove(manifestPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Bootstrap
|
||||
|
||||
@@ -34,6 +34,31 @@ namespace Bootstrap {
|
||||
std::vector<std::string>& files,
|
||||
std::string& strError);
|
||||
|
||||
// Download bootstrap.tar.gz and extract to dataDir.
|
||||
// Falls back to filelist.txt + individual file download if tar.gz unavailable.
|
||||
bool DownloadBootstrap(const std::string& host,
|
||||
const boost::filesystem::path& dataDir,
|
||||
ProgressCallback progressFn,
|
||||
std::string& strError);
|
||||
|
||||
// Snapshot manifest (parsed from snapshot.manifest in bootstrap archive)
|
||||
struct SnapshotManifest {
|
||||
int format; // format version, must be 1
|
||||
std::string network; // "main" or "test"
|
||||
int height; // block height of the snapshot tip
|
||||
std::string hash; // block hash at that height (hex, no 0x prefix)
|
||||
int dbversion; // DATABASE_VERSION the txleveldb was built with
|
||||
};
|
||||
|
||||
// Parse a snapshot.manifest file into a SnapshotManifest struct.
|
||||
bool ParseManifest(const boost::filesystem::path& manifestPath,
|
||||
SnapshotManifest& manifest,
|
||||
std::string& strError);
|
||||
|
||||
// Verify a parsed manifest against compiled-in checkpoints and config.
|
||||
bool VerifyManifest(const SnapshotManifest& manifest,
|
||||
std::string& strError);
|
||||
|
||||
} // namespace Bootstrap
|
||||
|
||||
#endif // TRIANGLES_BOOTSTRAP_H
|
||||
|
||||
@@ -60,6 +60,14 @@ namespace Checkpoints
|
||||
return hash == i->second;
|
||||
}
|
||||
|
||||
bool IsKnownCheckpoint(int nHeight, const uint256& hash)
|
||||
{
|
||||
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
|
||||
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
|
||||
if (i == checkpoints.end()) return false;
|
||||
return hash == i->second;
|
||||
}
|
||||
|
||||
int GetTotalBlocksEstimate()
|
||||
{
|
||||
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
|
||||
|
||||
@@ -39,6 +39,9 @@ namespace Checkpoints
|
||||
// Returns true if block passes checkpoint checks
|
||||
bool CheckHardened(int nHeight, const uint256& hash);
|
||||
|
||||
// Returns true only if (nHeight, hash) is an exact entry in mapCheckpoints
|
||||
bool IsKnownCheckpoint(int nHeight, const uint256& hash);
|
||||
|
||||
// Return conservative estimate of total number of blocks, 0 if unknown
|
||||
int GetTotalBlocksEstimate();
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
|
||||
#define CLIENT_VERSION_MAJOR 5
|
||||
#define CLIENT_VERSION_MINOR 3
|
||||
#define CLIENT_VERSION_REVISION 3
|
||||
#define CLIENT_VERSION_REVISION 7
|
||||
#define CLIENT_VERSION_BUILD 0
|
||||
|
||||
// Converts the parameter X to a string after macro replacement on X has been performed.
|
||||
|
||||
+1
-1
@@ -479,7 +479,7 @@ void CDBEnv::Flush(bool fShutdown)
|
||||
else
|
||||
mi++;
|
||||
}
|
||||
printf("DBFlush(%s)%s ended %15"PRId64"ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart);
|
||||
printf("DBFlush(%s)%s ended %15" PRId64 "ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart);
|
||||
if (fShutdown)
|
||||
{
|
||||
char** listp;
|
||||
|
||||
+75
-11
@@ -12,6 +12,7 @@
|
||||
#include "checkpoints.h"
|
||||
#include "smessage.h"
|
||||
#include "openssl_compat.h"
|
||||
#include "bootstrap.h"
|
||||
#include "tor/tor_embedded.h"
|
||||
#include "tor/onion_v3.h"
|
||||
#include "tor/tor_process.h"
|
||||
@@ -94,17 +95,17 @@ void ThreadDeferredStartup(void* parg)
|
||||
{
|
||||
int64_t nStart = GetTimeMillis();
|
||||
SecureMsgStart(fNoSmsg, GetBoolArg("-smsgscanchain"));
|
||||
printf(" securemsg %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
printf(" securemsg %15" PRId64 "ms\n", GetTimeMillis() - nStart);
|
||||
}
|
||||
|
||||
if (!fShutdown && pwalletMain)
|
||||
{
|
||||
int64_t nStart = GetTimeMillis();
|
||||
pwalletMain->ReacceptWalletTransactions();
|
||||
printf(" reaccept %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
printf(" reaccept %15" PRId64 "ms\n", GetTimeMillis() - nStart);
|
||||
}
|
||||
|
||||
printf("Deferred startup tasks finished %"PRId64"ms\n", GetTimeMillis() - nTotalStart);
|
||||
printf("Deferred startup tasks finished %" PRId64 "ms\n", GetTimeMillis() - nTotalStart);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
@@ -797,6 +798,43 @@ bool AppInit2()
|
||||
for (string strDest : mapMultiArgs["-seednode"])
|
||||
AddOneShot(strDest);
|
||||
|
||||
// ********************************************************* Step 6b: bootstrap download (daemon)
|
||||
#ifndef QT_GUI
|
||||
if (GetBoolArg("-bootstrap", false))
|
||||
{
|
||||
fs::path dataPath = GetDataDir();
|
||||
std::string host = Bootstrap::DEFAULT_HOST;
|
||||
std::string strError;
|
||||
|
||||
uiInterface.InitMessage(_("Downloading blockchain snapshot..."));
|
||||
printf("Bootstrap: contacting %s...\n", host.c_str());
|
||||
|
||||
auto progressFn = [](int64_t bytesDownloaded, int64_t totalBytes) {
|
||||
if (totalBytes > 0) {
|
||||
printf("\rBootstrap: %lld / %lld MB (%lld%%)",
|
||||
(long long)(bytesDownloaded / (1024*1024)),
|
||||
(long long)(totalBytes / (1024*1024)),
|
||||
(long long)((bytesDownloaded * 100) / totalBytes));
|
||||
fflush(stdout);
|
||||
}
|
||||
};
|
||||
|
||||
bool success = Bootstrap::DownloadBootstrap(host, dataPath, progressFn, strError);
|
||||
if (!success) {
|
||||
host = Bootstrap::FALLBACK_HOST;
|
||||
printf("\nBootstrap: primary host failed, trying fallback %s...\n", host.c_str());
|
||||
success = Bootstrap::DownloadBootstrap(host, dataPath, progressFn, strError);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
printf("\nBootstrap: failed: %s\n", strError.c_str());
|
||||
printf("Bootstrap: skipping, will sync from network.\n");
|
||||
} else {
|
||||
printf("\nBootstrap: done.\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ********************************************************* Step 7: load blockchain
|
||||
|
||||
if (!bitdb.Open(GetDataDir()))
|
||||
@@ -821,6 +859,16 @@ bool AppInit2()
|
||||
if (!LoadBlockIndex())
|
||||
return InitError(_("Error loading blkindex.dat"));
|
||||
|
||||
// If the block index is empty but blk0001.dat exists (bootstrap download),
|
||||
// fast-import: build the index directly from the block file without re-writing
|
||||
// data. Batches LevelDB commits every 200K blocks for speed.
|
||||
if (nBestHeight == 0 && boost::filesystem::exists(GetDataDir() / "blk0001.dat")
|
||||
&& mapBlockIndex.size() <= 1)
|
||||
{
|
||||
uiInterface.InitMessage(_("Importing bootstrap blocks..."));
|
||||
printf("Block index empty but blk0001.dat exists - running fast import...\n");
|
||||
FastImportBlockFile();
|
||||
}
|
||||
|
||||
// as LoadBlockIndex can take several minutes, it's possible the user
|
||||
// requested to kill triangles-qt during the last operation. If so, exit.
|
||||
@@ -830,7 +878,23 @@ bool AppInit2()
|
||||
printf("Shutdown requested. Exiting.\n");
|
||||
return false;
|
||||
}
|
||||
printf(" block index %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
printf(" block index %15" PRId64 "ms\n", GetTimeMillis() - nStart);
|
||||
|
||||
// Diagnostic: check for blocks in mapBlockIndex above pindexBest
|
||||
{
|
||||
int nMaxIndexHeight = 0;
|
||||
int nAboveBest = 0;
|
||||
for (std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.begin();
|
||||
it != mapBlockIndex.end(); ++it)
|
||||
{
|
||||
if (it->second->nHeight > nMaxIndexHeight)
|
||||
nMaxIndexHeight = it->second->nHeight;
|
||||
if (it->second->nHeight > nBestHeight)
|
||||
nAboveBest++;
|
||||
}
|
||||
printf("SYNC-DIAG: mapBlockIndex=%d entries, maxHeight=%d, bestHeight=%d, aboveBest=%d\n",
|
||||
(int)mapBlockIndex.size(), nMaxIndexHeight, nBestHeight, nAboveBest);
|
||||
}
|
||||
|
||||
if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree"))
|
||||
{
|
||||
@@ -924,7 +988,7 @@ bool AppInit2()
|
||||
}
|
||||
|
||||
printf("%s", strErrors.str().c_str());
|
||||
printf(" wallet %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
printf(" wallet %15" PRId64 "ms\n", GetTimeMillis() - nStart);
|
||||
|
||||
RegisterWallet(pwalletMain);
|
||||
|
||||
@@ -968,7 +1032,7 @@ bool AppInit2()
|
||||
if (!fScannedWithIndex)
|
||||
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
|
||||
|
||||
printf(" rescan %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
printf(" rescan %15" PRId64 "ms\n", GetTimeMillis() - nStart);
|
||||
}
|
||||
|
||||
// ********************************************************* Step 8.5: start Tor and initialize V3 identity
|
||||
@@ -1080,7 +1144,7 @@ bool AppInit2()
|
||||
printf("Invalid or missing peers.dat; recreating\n");
|
||||
}
|
||||
|
||||
printf("Loaded %i addresses from peers.dat %"PRId64"ms\n",
|
||||
printf("Loaded %i addresses from peers.dat %" PRId64 "ms\n",
|
||||
addrman.size(), GetTimeMillis() - nStart);
|
||||
|
||||
|
||||
@@ -1092,11 +1156,11 @@ bool AppInit2()
|
||||
RandAddSeedPerfmon();
|
||||
|
||||
//// debug print
|
||||
printf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size());
|
||||
printf("mapBlockIndex.size() = %" PRIszu "\n", mapBlockIndex.size());
|
||||
printf("nBestHeight = %d\n", nBestHeight);
|
||||
printf("setKeyPool.size() = %"PRIszu"\n", pwalletMain->setKeyPool.size());
|
||||
printf("mapWallet.size() = %"PRIszu"\n", pwalletMain->mapWallet.size());
|
||||
printf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain->mapAddressBook.size());
|
||||
printf("setKeyPool.size() = %" PRIszu "\n", pwalletMain->setKeyPool.size());
|
||||
printf("mapWallet.size() = %" PRIszu "\n", pwalletMain->mapWallet.size());
|
||||
printf("mapAddressBook.size() = %" PRIszu "\n", pwalletMain->mapAddressBook.size());
|
||||
|
||||
if (!NewThread(StartNode, NULL))
|
||||
InitError(_("Error: could not start node"));
|
||||
|
||||
+1
-1
@@ -260,7 +260,7 @@ void ThreadIRCSeed2(void* parg)
|
||||
if (!fNoListen && GetLocal(addrLocal, &addrIPv4) && nNameRetry<3)
|
||||
strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
|
||||
if (strMyName == "")
|
||||
strMyName = strprintf("x%"PRIu64"", GetRand(1000000000));
|
||||
strMyName = strprintf("x%" PRIu64 "", GetRand(1000000000));
|
||||
|
||||
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
|
||||
Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
|
||||
|
||||
Regular → Executable
+666
-78
File diff suppressed because it is too large
Load Diff
+5
-3
@@ -35,6 +35,7 @@ static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
|
||||
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
|
||||
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
|
||||
static const unsigned int MAX_ORPHAN_BLOCKS = 750;
|
||||
static const unsigned int MAX_ORPHAN_BLOCKS_IBD = 4000;
|
||||
static const unsigned int MAX_INV_SZ = 50000;
|
||||
static const int64_t MIN_TX_FEE = (1 * CENT) / 100;
|
||||
static const int64_t MIN_RELAY_TX_FEE = (1 * CENT) / 100;
|
||||
@@ -112,6 +113,7 @@ CBlockIndex* FindBlockByHeight(int nHeight);
|
||||
bool ProcessMessages(CNode* pfrom);
|
||||
bool SendMessages(CNode* pto, bool fSendTrickle);
|
||||
bool LoadExternalBlockFile(FILE* fileIn);
|
||||
bool FastImportBlockFile();
|
||||
|
||||
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
|
||||
unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake);
|
||||
@@ -641,7 +643,7 @@ public:
|
||||
{
|
||||
std::string str;
|
||||
str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
|
||||
str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%d)\n",
|
||||
str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%" PRIszu ", vout.size=%" PRIszu ", nLockTime=%d)\n",
|
||||
GetHash().ToString().substr(0,10).c_str(),
|
||||
nTime,
|
||||
nVersion,
|
||||
@@ -1068,7 +1070,7 @@ public:
|
||||
|
||||
void print() const
|
||||
{
|
||||
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu", vchBlockSig=%s)\n",
|
||||
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%" PRIszu ", vchBlockSig=%s)\n",
|
||||
GetHash().ToString().c_str(),
|
||||
nVersion,
|
||||
hashPrevBlock.ToString().c_str(),
|
||||
@@ -1329,7 +1331,7 @@ public:
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return strprintf("CBlockIndex(nprev=%p, pnext=%p, nFile=%u, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016"PRIx64", nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)",
|
||||
return strprintf("CBlockIndex(nprev=%p, pnext=%p, nFile=%u, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016" PRIx64 ", nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)",
|
||||
pprev, pnext, nFile, nBlockPos, nHeight,
|
||||
FormatMoney(nMint).c_str(), FormatMoney(nMoneySupply).c_str(),
|
||||
GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW",
|
||||
|
||||
@@ -111,6 +111,7 @@ OBJS= \
|
||||
obj/miner.o \
|
||||
obj/main.o \
|
||||
obj/net.o \
|
||||
obj/bootstrap.o \
|
||||
obj/net_bootstrap.o \
|
||||
obj/protocol.o \
|
||||
obj/trianglesrpc.o \
|
||||
@@ -232,6 +233,13 @@ obj/tor_embedded.o: tor/tor_embedded.cpp
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/bootstrap.o: bootstrap.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/net_bootstrap.o: net_bootstrap.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
|
||||
+21
-6
@@ -6,7 +6,7 @@ USE_UPNP:=0
|
||||
USE_IPV6:=1
|
||||
|
||||
LINK:=$(CXX)
|
||||
ARCH:=$(system lscpu | head -n 1 | awk '{print $2}')
|
||||
ARCH:=$(shell lscpu | head -n 1 | awk '{print $$2}')
|
||||
|
||||
DEFS=-DBOOST_SPIRIT_THREADSAFE
|
||||
|
||||
@@ -41,7 +41,6 @@ LIBS += \
|
||||
-l boost_chrono$(BOOST_LIB_SUFFIX) \
|
||||
-l db_cxx$(BDB_LIB_SUFFIX) \
|
||||
-l ssl \
|
||||
-l event \
|
||||
-l crypto
|
||||
|
||||
ifndef USE_UPNP
|
||||
@@ -146,6 +145,7 @@ OBJS= \
|
||||
obj/miner.o \
|
||||
obj/main.o \
|
||||
obj/net.o \
|
||||
obj/bootstrap.o \
|
||||
obj/net_bootstrap.o \
|
||||
obj/protocol.o \
|
||||
obj/trianglesrpc.o \
|
||||
@@ -201,6 +201,12 @@ endif
|
||||
|
||||
all: trianglesd
|
||||
|
||||
obj:
|
||||
@mkdir -p obj
|
||||
|
||||
obj-test:
|
||||
@mkdir -p obj-test
|
||||
|
||||
test check: test_triangles FORCE
|
||||
./test_triangles
|
||||
|
||||
@@ -230,14 +236,14 @@ obj/scrypt-x86_64.o: scrypt-x86_64.S
|
||||
obj/scrypt-arm.o: scrypt-arm.S
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
|
||||
|
||||
obj/%.o: %.cpp
|
||||
obj/%.o: %.cpp | obj
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/%.o: %.c
|
||||
obj/%.o: %.c | obj
|
||||
$(CXX) -c $(xCXXFLAGS) -fpermissive -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
@@ -279,6 +285,13 @@ obj/tor_embedded.o: tor/tor_embedded.cpp
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/bootstrap.o: bootstrap.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/net_bootstrap.o: net_bootstrap.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
@@ -289,9 +302,11 @@ obj/net_bootstrap.o: net_bootstrap.cpp
|
||||
trianglesd: $(OBJS:obj/%=obj/%)
|
||||
$(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS)
|
||||
|
||||
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
|
||||
# miner_tests.cpp references CreateNewBlock() which was never ported from Bitcoin
|
||||
TESTOBJS := $(filter-out obj-test/miner_tests.o, \
|
||||
$(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)))
|
||||
|
||||
obj-test/%.o: test/%.cpp
|
||||
obj-test/%.o: test/%.cpp | obj-test
|
||||
$(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
|
||||
+11
-1
@@ -354,7 +354,7 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake, int64_t* pFees)
|
||||
nLastBlockSize = nBlockSize;
|
||||
|
||||
if (fDebug && GetBoolArg("-printpriority"))
|
||||
printf("CreateNewBlock(): total size %"PRIu64"\n", nBlockSize);
|
||||
printf("CreateNewBlock(): total size %" PRIu64 "\n", nBlockSize);
|
||||
|
||||
if (!fProofOfStake)
|
||||
pblock->vtx[0].vout[0].nValue = GetProofOfWorkReward(nFees);
|
||||
@@ -558,6 +558,16 @@ void StakeMiner(CWallet *pwallet)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update cached stake weight for UI display (avoids heavy work on UI thread)
|
||||
//
|
||||
{
|
||||
uint64_t nMinWeight = 0, nMaxWeight = 0, nWeight = 0;
|
||||
pwallet->GetStakeWeight(*pwallet, nMinWeight, nMaxWeight, nWeight);
|
||||
pwallet->nCachedStakeWeight = nWeight;
|
||||
pwallet->nCachedStakeWeightTime = GetTime();
|
||||
}
|
||||
|
||||
//
|
||||
// Create new block
|
||||
//
|
||||
|
||||
@@ -422,7 +422,7 @@ public:
|
||||
// the key is the earliest time the request can be sent
|
||||
int64_t& nRequestTime = mapAlreadyAskedFor[inv];
|
||||
if (fDebugNet)
|
||||
printf("askfor %s %"PRId64" (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str());
|
||||
printf("askfor %s %" PRId64 " (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str());
|
||||
|
||||
// Make sure not to reuse time indexes to keep things in the same order
|
||||
int64_t nNow = (GetTime() - 1) * 1000000;
|
||||
|
||||
@@ -99,11 +99,9 @@ void AskPassphraseDialog::accept()
|
||||
oldpass.reserve(MAX_PASSPHRASE_SIZE);
|
||||
newpass1.reserve(MAX_PASSPHRASE_SIZE);
|
||||
newpass2.reserve(MAX_PASSPHRASE_SIZE);
|
||||
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
|
||||
// Alternately, find a way to make this input mlock()'d to begin with.
|
||||
oldpass.assign(ui->passEdit1->text().toStdString().c_str());
|
||||
newpass1.assign(ui->passEdit2->text().toStdString().c_str());
|
||||
newpass2.assign(ui->passEdit3->text().toStdString().c_str());
|
||||
oldpass = MakeSecureString(ui->passEdit1->text().toStdString());
|
||||
newpass1 = MakeSecureString(ui->passEdit2->text().toStdString());
|
||||
newpass2 = MakeSecureString(ui->passEdit3->text().toStdString());
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
|
||||
+20
-5
@@ -15,7 +15,7 @@ static const int64_t nClientStartupTime = GetTime();
|
||||
|
||||
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
|
||||
QObject(parent), optionsModel(optionsModel),
|
||||
cachedNumBlocks(0), cachedNumBlocksOfPeers(0), pollTimer(0)
|
||||
cachedNumBlocks(0), cachedNumBlocksOfPeers(0), cachedNumConnections(0), pollTimer(0)
|
||||
{
|
||||
numBlocksAtStartup = -1;
|
||||
|
||||
@@ -34,7 +34,14 @@ ClientModel::~ClientModel()
|
||||
|
||||
int ClientModel::getNumConnections() const
|
||||
{
|
||||
return vNodes.size();
|
||||
// Use TRY_LOCK to avoid blocking the UI thread when the network
|
||||
// thread holds cs_vNodes (e.g. during DNS resolution or connections).
|
||||
// Return the cached value if the lock is busy.
|
||||
TRY_LOCK(cs_vNodes, lockNodes);
|
||||
if (lockNodes) {
|
||||
cachedNumConnections = vNodes.size();
|
||||
}
|
||||
return cachedNumConnections;
|
||||
}
|
||||
|
||||
int ClientModel::getNumBlocks() const
|
||||
@@ -63,12 +70,20 @@ void ClientModel::updateTimer()
|
||||
int newNumBlocks = getNumBlocks();
|
||||
int newNumBlocksOfPeers = getNumBlocksOfPeers();
|
||||
|
||||
// Always emit during IBD so the speed/ETA display stays live
|
||||
if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers
|
||||
|| newNumBlocks < newNumBlocksOfPeers)
|
||||
// Always emit when values change or during IBD.
|
||||
// Also emit every ~30 seconds even when idle so setNumBlocks() can
|
||||
// re-evaluate sync status (e.g. when a new block arrives after a long gap).
|
||||
static int64_t nLastEmit = 0;
|
||||
int64_t nNow = GetTime();
|
||||
bool fChanged = (cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers);
|
||||
bool fCatchingUp = (newNumBlocks < newNumBlocksOfPeers);
|
||||
bool fPeriodicRefresh = (nNow - nLastEmit >= 30);
|
||||
|
||||
if(fChanged || fCatchingUp || fPeriodicRefresh)
|
||||
{
|
||||
cachedNumBlocks = newNumBlocks;
|
||||
cachedNumBlocksOfPeers = newNumBlocksOfPeers;
|
||||
nLastEmit = nNow;
|
||||
|
||||
emit numBlocksChanged(newNumBlocks, newNumBlocksOfPeers);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ private:
|
||||
|
||||
int cachedNumBlocks;
|
||||
int cachedNumBlocksOfPeers;
|
||||
mutable int cachedNumConnections;
|
||||
|
||||
int numBlocksAtStartup;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define GUICONSTANTS_H
|
||||
|
||||
/* Milliseconds between model updates */
|
||||
static const int MODEL_UPDATE_DELAY = 500;
|
||||
static const int MODEL_UPDATE_DELAY = 2500;
|
||||
|
||||
/* AskPassphraseDialog -- Maximum passphrase length */
|
||||
static const int MAX_PASSPHRASE_SIZE = 1024;
|
||||
|
||||
+47
-54
@@ -11,6 +11,7 @@
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QProgressDialog>
|
||||
#include <QCheckBox>
|
||||
#include <QApplication>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -204,79 +205,71 @@ bool IntroDialog::pickDataDirectory()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Offer bootstrap download once (tracks via QSettings so it only asks once)
|
||||
// Offer bootstrap download on each startup (unless user checked "don't ask again")
|
||||
fs::path dataDirPath(dataDir.toStdString());
|
||||
if (!settings.value("bootstrapOffered", false).toBool())
|
||||
if (!settings.value("bootstrapDontAsk", false).toBool())
|
||||
{
|
||||
settings.setValue("bootstrapOffered", true);
|
||||
|
||||
int ret = QMessageBox::question(0, "Triangles",
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Triangles");
|
||||
msgBox.setText(
|
||||
"Would you like to download the latest blockchain snapshot?\n\n"
|
||||
"This will download the blockchain data from the Triangles network "
|
||||
"and replace any existing chain data in your data directory.\n\n"
|
||||
"Click Yes to download, or No to sync from the network.",
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
"Click Yes to download, or No to sync from the network.");
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::Yes);
|
||||
QCheckBox *dontAskBox = new QCheckBox("Don't show this again");
|
||||
msgBox.setCheckBox(dontAskBox);
|
||||
|
||||
int ret = msgBox.exec();
|
||||
|
||||
if (dontAskBox->isChecked())
|
||||
settings.setValue("bootstrapDontAsk", true);
|
||||
|
||||
if (ret == QMessageBox::Yes)
|
||||
{
|
||||
std::string host = Bootstrap::DEFAULT_HOST;
|
||||
std::string strError;
|
||||
std::vector<std::string> files;
|
||||
|
||||
// Fetch file list (try domain first, then fallback to IP)
|
||||
if (!Bootstrap::FetchFileList(host, files, strError)) {
|
||||
host = Bootstrap::FALLBACK_HOST;
|
||||
if (!Bootstrap::FetchFileList(host, files, strError)) {
|
||||
QMessageBox::warning(0, "Triangles",
|
||||
QString("Could not reach bootstrap server:\n%1\n\n"
|
||||
"The wallet will sync from the network instead.")
|
||||
.arg(QString::fromStdString(strError)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Show progress dialog
|
||||
QProgressDialog progress("Downloading blockchain data...", "Cancel",
|
||||
0, (int)files.size(), 0);
|
||||
QProgressDialog progress("Downloading blockchain snapshot...", "Cancel",
|
||||
0, 100, 0);
|
||||
progress.setWindowTitle("Triangles - Bootstrap");
|
||||
progress.setWindowModality(Qt::ApplicationModal);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.setValue(0);
|
||||
|
||||
bool failed = false;
|
||||
for (int i = 0; i < (int)files.size(); i++) {
|
||||
if (progress.wasCanceled())
|
||||
break;
|
||||
|
||||
QString filename = QString::fromStdString(files[i]);
|
||||
progress.setLabelText(
|
||||
QString("Downloading %1 (%2 of %3)...")
|
||||
.arg(filename).arg(i + 1).arg((int)files.size()));
|
||||
progress.setValue(i);
|
||||
QApplication::processEvents();
|
||||
|
||||
// Create subdirectories if needed (e.g. txleveldb/)
|
||||
fs::path destPath = dataDirPath / files[i];
|
||||
fs::create_directories(destPath.parent_path());
|
||||
|
||||
// Download this file
|
||||
std::string urlPath = std::string(Bootstrap::BASE_PATH) + files[i];
|
||||
if (!Bootstrap::DownloadFile(host, urlPath, destPath,
|
||||
[](int64_t, int64_t) {
|
||||
QApplication::processEvents();
|
||||
}, strError))
|
||||
{
|
||||
QMessageBox::warning(0, "Triangles",
|
||||
QString("Download failed for %1:\n%2\n\n"
|
||||
"The wallet will sync remaining data from the network.")
|
||||
.arg(filename).arg(QString::fromStdString(strError)));
|
||||
failed = true;
|
||||
break;
|
||||
auto progressFn = [&progress](int64_t bytesDownloaded, int64_t totalBytes) {
|
||||
if (totalBytes > 0) {
|
||||
int pct = (int)((bytesDownloaded * 100) / totalBytes);
|
||||
progress.setValue(pct);
|
||||
progress.setLabelText(
|
||||
QString("Downloading blockchain snapshot... %1 MB / %2 MB")
|
||||
.arg(bytesDownloaded / (1024*1024))
|
||||
.arg(totalBytes / (1024*1024)));
|
||||
} else {
|
||||
progress.setLabelText(
|
||||
QString("Downloading blockchain snapshot... %1 MB")
|
||||
.arg(bytesDownloaded / (1024*1024)));
|
||||
}
|
||||
QApplication::processEvents();
|
||||
};
|
||||
|
||||
bool success = Bootstrap::DownloadBootstrap(host, dataDirPath, progressFn, strError);
|
||||
if (!success) {
|
||||
host = Bootstrap::FALLBACK_HOST;
|
||||
progress.setValue(0);
|
||||
success = Bootstrap::DownloadBootstrap(host, dataDirPath, progressFn, strError);
|
||||
}
|
||||
|
||||
if (!failed)
|
||||
progress.setValue((int)files.size());
|
||||
if (!success) {
|
||||
QMessageBox::warning(0, "Triangles",
|
||||
QString("Could not download blockchain snapshot:\n%1\n\n"
|
||||
"The wallet will sync from the network instead.")
|
||||
.arg(QString::fromStdString(strError)));
|
||||
} else {
|
||||
progress.setValue(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-1
@@ -19,6 +19,7 @@
|
||||
#include <QMenu>
|
||||
#include <QFont>
|
||||
#include <QColor>
|
||||
#include <QTextDocument>
|
||||
|
||||
Q_DECLARE_METATYPE(std::vector<unsigned char>);
|
||||
|
||||
@@ -27,6 +28,24 @@ QList<QString> ambiguous; /**< Specifies Ambiguous addresses */
|
||||
const QString MessageModel::Sent = "Sent";
|
||||
const QString MessageModel::Received = "Received";
|
||||
|
||||
namespace {
|
||||
|
||||
static QString FormatShortMessage(const QString& message)
|
||||
{
|
||||
static const int kMaxPreviewChars = 80;
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setHtml(message);
|
||||
|
||||
QString preview = doc.toPlainText().simplified();
|
||||
if (preview.length() <= kMaxPreviewChars)
|
||||
return preview;
|
||||
|
||||
return preview.left(kMaxPreviewChars - 3) + "...";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct MessageTableEntryLessThan
|
||||
{
|
||||
bool operator()(const MessageTableEntry &a, const MessageTableEntry &b) const {return a.received_datetime < b.received_datetime;};
|
||||
@@ -485,7 +504,7 @@ QVariant MessageModel::data(const QModelIndex &index, int role) const
|
||||
case FilterAddressRole: return (rec->type == MessageTableEntry::Sent ? rec->to_address + rec->from_address : rec->from_address + rec->to_address);
|
||||
case LabelRole: return rec->label;
|
||||
case MessageRole: return rec->message;
|
||||
case ShortMessageRole: return rec->message; // TODO: Short message
|
||||
case ShortMessageRole: return FormatShortMessage(rec->message);
|
||||
case HTMLRole: return rec->received_datetime.toString() + "<br>" + (rec->label.isEmpty() ? rec->from_address : rec->label) + "<br>" + rec->message;
|
||||
case Ambiguous:
|
||||
int it;
|
||||
|
||||
@@ -126,6 +126,8 @@ OverviewPage::~OverviewPage()
|
||||
|
||||
void OverviewPage::setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance)
|
||||
{
|
||||
if (!model || !model->getOptionsModel())
|
||||
return;
|
||||
int unit = model->getOptionsModel()->getDisplayUnit();
|
||||
currentBalance = balance;
|
||||
currentStake = stake;
|
||||
|
||||
@@ -52,11 +52,13 @@ class TransactionTablePriv
|
||||
public:
|
||||
TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent):
|
||||
wallet(wallet),
|
||||
parent(parent)
|
||||
parent(parent),
|
||||
fInitialLoadDone(false)
|
||||
{
|
||||
}
|
||||
CWallet *wallet;
|
||||
TransactionTableModel *parent;
|
||||
bool fInitialLoadDone;
|
||||
|
||||
/* Local cache of wallet.
|
||||
* As it is in the same order as the CWallet, by definition
|
||||
@@ -68,22 +70,19 @@ public:
|
||||
*/
|
||||
void refreshWallet()
|
||||
{
|
||||
OutputDebugStringF("refreshWallet\n");
|
||||
OutputDebugStringF("refreshWallet: fInitialLoadDone=%d mapWallet.size=%u\n",
|
||||
(int)fInitialLoadDone, (unsigned)wallet->mapWallet.size());
|
||||
cachedWallet.clear();
|
||||
{
|
||||
TRY_LOCK(wallet->cs_wallet, lockWallet);
|
||||
if(!lockWallet)
|
||||
{
|
||||
// Lock busy (block processing), retry in 500ms
|
||||
QTimer::singleShot(500, parent, SLOT(refreshWallet()));
|
||||
return;
|
||||
}
|
||||
LOCK(wallet->cs_wallet);
|
||||
for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
|
||||
{
|
||||
if(TransactionRecord::showTransaction(it->second))
|
||||
cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
|
||||
}
|
||||
fInitialLoadDone = true;
|
||||
}
|
||||
OutputDebugStringF("refreshWallet: loaded %d transaction records\n", cachedWallet.size());
|
||||
}
|
||||
|
||||
/* Update our model of the wallet incrementally, to synchronize our model of the wallet
|
||||
@@ -95,7 +94,14 @@ public:
|
||||
{
|
||||
OutputDebugStringF("updateWallet %s %i\n", hash.ToString().c_str(), status);
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
TRY_LOCK(wallet->cs_wallet, lockWallet);
|
||||
if (!lockWallet)
|
||||
{
|
||||
// Lock busy - schedule a full refresh to pick up missed updates.
|
||||
// This avoids silently dropping CT_NEW notifications.
|
||||
QTimer::singleShot(500, parent, SLOT(refreshWallet()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Find transaction in wallet
|
||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
|
||||
@@ -190,8 +196,12 @@ public:
|
||||
// simply re-use the cached status.
|
||||
if(rec->statusUpdateNeeded())
|
||||
{
|
||||
// Never block the GUI thread while the core is holding cs_wallet.
|
||||
// If the lock is busy, keep showing the cached status and refresh
|
||||
// it on a later paint/update cycle.
|
||||
TRY_LOCK(wallet->cs_wallet, lockWallet);
|
||||
if (lockWallet)
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
|
||||
|
||||
if(mi != wallet->mapWallet.end())
|
||||
@@ -210,8 +220,14 @@ public:
|
||||
|
||||
QString describe(TransactionRecord *rec)
|
||||
{
|
||||
// Transaction details are generated on demand from wallet/db state.
|
||||
// If the wallet is busy, return a lightweight placeholder instead of
|
||||
// freezing the UI until the lock becomes available.
|
||||
TRY_LOCK(wallet->cs_wallet, lockWallet);
|
||||
if (!lockWallet)
|
||||
return parent->tr("Transaction details are temporarily unavailable while the wallet is busy.");
|
||||
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
|
||||
if(mi != wallet->mapWallet.end())
|
||||
{
|
||||
@@ -231,7 +247,12 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
|
||||
cachedNumBlocks(0)
|
||||
{
|
||||
columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount");
|
||||
QTimer::singleShot(0, this, SLOT(refreshWallet()));
|
||||
|
||||
// Load transactions synchronously in the constructor so they're
|
||||
// available before the event loop starts. The deferred QTimer approach
|
||||
// was never firing because queued updateTransaction events from sync
|
||||
// would flood the event queue first.
|
||||
priv->refreshWallet();
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations()));
|
||||
@@ -255,8 +276,10 @@ void TransactionTableModel::updateTransaction(const QString &hash, int status)
|
||||
|
||||
void TransactionTableModel::refreshWallet()
|
||||
{
|
||||
beginResetModel();
|
||||
priv->refreshWallet();
|
||||
reset();
|
||||
endResetModel();
|
||||
OutputDebugStringF("TransactionTableModel::refreshWallet: rowCount=%d\n", priv->size());
|
||||
}
|
||||
|
||||
void TransactionTableModel::updateConfirmations()
|
||||
|
||||
+43
-24
@@ -799,19 +799,23 @@ void TrianglesGUI::setNumConnections(int count)
|
||||
|
||||
void TrianglesGUI::setNumBlocks(int count, int nTotalBlocks)
|
||||
{
|
||||
// don't show / hide progress bar and its label if we have no connection to the network
|
||||
if (!clientModel || clientModel->getNumConnections() == 0)
|
||||
if (!clientModel)
|
||||
return;
|
||||
|
||||
int nConnections = clientModel->getNumConnections();
|
||||
|
||||
// Hide progress bar when disconnected, but don't return early -
|
||||
// we still need to update sync state and the out-of-sync warning
|
||||
if (nConnections == 0)
|
||||
{
|
||||
progressBarLabel->setVisible(false);
|
||||
progressBar->setVisible(false);
|
||||
ui->label_blocks->setVisible(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QString tooltip;
|
||||
|
||||
if(count < nTotalBlocks)
|
||||
if(nConnections > 0 && count < nTotalBlocks)
|
||||
{
|
||||
// Calculate blocks/sec - only update rate when new blocks arrive
|
||||
static int lastCount = 0;
|
||||
@@ -899,20 +903,20 @@ void TrianglesGUI::setNumBlocks(int count, int nTotalBlocks)
|
||||
text = tr("%n day(s) ago","",secs/(60*60*24));
|
||||
}
|
||||
|
||||
// Set icon state: spinning if catching up, tick otherwise
|
||||
if(secs < 90*60 && count >= nTotalBlocks)
|
||||
// Set icon state: spinning if catching up, tick otherwise.
|
||||
// For PoS chains with few stakers, blocks can be hours or days apart.
|
||||
// Sync status is based purely on block count - NOT block timestamp.
|
||||
// A stale chain (no recent blocks) is still "synced" if we have all blocks.
|
||||
if(count >= nTotalBlocks)
|
||||
{
|
||||
tooltip = tr("Up to date") + QString(".<br>") + tooltip;
|
||||
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
|
||||
|
||||
|
||||
overviewPage->showOutOfSyncWarning(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
|
||||
//syncIconMovie doesn't work for some reason - using fallback png
|
||||
//labelBlocksIcon->setMovie(syncIconMovie);
|
||||
//syncIconMovie->start();
|
||||
labelBlocksIcon->setPixmap(QIcon(":/icons/notsynced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
|
||||
|
||||
overviewPage->showOutOfSyncWarning(true);
|
||||
@@ -1590,32 +1594,47 @@ void TrianglesGUI::toggleHidden()
|
||||
|
||||
void TrianglesGUI::updateStakingIcon()
|
||||
{
|
||||
uint64_t nMinWeight = 0, nMaxWeight = 0, nWeight = 0;
|
||||
// Read cached staking info computed by the staking thread.
|
||||
// No locks needed - these are volatile values written by the miner thread
|
||||
// and are display-only. This keeps the UI thread completely non-blocking.
|
||||
|
||||
uint64_t nWeight = 0;
|
||||
bool fWalletLocked = false;
|
||||
bool fHasPeers = false;
|
||||
|
||||
if (pwalletMain)
|
||||
pwalletMain->GetStakeWeight(*pwalletMain, nMinWeight, nMaxWeight, nWeight);
|
||||
{
|
||||
TRY_LOCK(pwalletMain->cs_wallet, lockWallet);
|
||||
if (lockWallet)
|
||||
fWalletLocked = pwalletMain->IsLocked();
|
||||
else
|
||||
return; // Skip this cycle, try again in 30 seconds
|
||||
|
||||
// Use cached weight from the staking thread instead of computing on UI thread.
|
||||
// The staking thread updates this every ~500ms-1s loop iteration.
|
||||
nWeight = pwalletMain->nCachedStakeWeight;
|
||||
}
|
||||
|
||||
{
|
||||
TRY_LOCK(cs_vNodes, lockNodes);
|
||||
if (lockNodes)
|
||||
fHasPeers = !vNodes.empty();
|
||||
}
|
||||
|
||||
if (nLastCoinStakeSearchInterval && nWeight)
|
||||
{
|
||||
uint64_t nNetworkWeight = GetPoSKernelPS();
|
||||
unsigned nEstimateTime = nTargetSpacing * nNetworkWeight / nWeight;
|
||||
unsigned nEstimateTime = nWeight > 0 ? nTargetSpacing * nNetworkWeight / nWeight : 0;
|
||||
|
||||
QString text;
|
||||
if (nEstimateTime < 60)
|
||||
{
|
||||
text = tr("%n second(s)", "", nEstimateTime);
|
||||
}
|
||||
else if (nEstimateTime < 60*60)
|
||||
{
|
||||
text = tr("%n minute(s)", "", nEstimateTime/60);
|
||||
}
|
||||
else if (nEstimateTime < 24*60*60)
|
||||
{
|
||||
text = tr("%n hour(s)", "", nEstimateTime/(60*60));
|
||||
}
|
||||
else
|
||||
{
|
||||
text = tr("%n day(s)", "", nEstimateTime/(60*60*24));
|
||||
}
|
||||
|
||||
labelStakingIcon->setPixmap(QIcon(":/icons/staking_on").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||
labelStakingIcon->setToolTip(tr("Staking.<br>Your weight is %1<br>Network weight is %2<br>Expected time to earn reward is %3").arg(nWeight).arg(nNetworkWeight).arg(text));
|
||||
@@ -1623,9 +1642,9 @@ void TrianglesGUI::updateStakingIcon()
|
||||
else
|
||||
{
|
||||
labelStakingIcon->setPixmap(QIcon(":/icons/staking_off").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||
if (pwalletMain && pwalletMain->IsLocked())
|
||||
if (fWalletLocked)
|
||||
labelStakingIcon->setToolTip(tr("Not staking because wallet is locked"));
|
||||
else if (vNodes.empty())
|
||||
else if (!fHasPeers)
|
||||
labelStakingIcon->setToolTip(tr("Not staking because wallet is offline"));
|
||||
else if (IsInitialBlockDownload())
|
||||
labelStakingIcon->setToolTip(tr("Not staking because wallet is syncing"));
|
||||
|
||||
+29
-21
@@ -78,24 +78,22 @@ void WalletModel::pollBalanceChanged()
|
||||
{
|
||||
if(nBestHeight != cachedNumBlocks)
|
||||
{
|
||||
// Don't block the UI thread waiting for cs_wallet - skip this
|
||||
// update cycle if the lock is held by the block processing thread
|
||||
TRY_LOCK(wallet->cs_wallet, lockWallet);
|
||||
if(!lockWallet)
|
||||
return;
|
||||
|
||||
// Balance and number of transactions might have changed
|
||||
cachedNumBlocks = nBestHeight;
|
||||
checkBalanceChanged();
|
||||
// Balance and number of transactions might have changed.
|
||||
// Only update cachedNumBlocks AFTER a successful balance check,
|
||||
// otherwise a TRY_LOCK failure loses the update permanently.
|
||||
if(checkBalanceChanged())
|
||||
cachedNumBlocks = nBestHeight;
|
||||
}
|
||||
}
|
||||
|
||||
void WalletModel::checkBalanceChanged()
|
||||
bool WalletModel::checkBalanceChanged()
|
||||
{
|
||||
qint64 newBalance = getBalance();
|
||||
qint64 newStake = getStake();
|
||||
qint64 newUnconfirmedBalance = getUnconfirmedBalance();
|
||||
qint64 newImmatureBalance = getImmatureBalance();
|
||||
// Get all balances in a single lock acquisition + single pass.
|
||||
// Uses TRY_LOCK internally - if cs_wallet is busy (block processing),
|
||||
// skip this cycle. The timer will retry in 2.5 seconds.
|
||||
int64_t newBalance = 0, newStake = 0, newUnconfirmedBalance = 0, newImmatureBalance = 0;
|
||||
if (!wallet->GetAllBalances(newBalance, newStake, newUnconfirmedBalance, newImmatureBalance))
|
||||
return false;
|
||||
|
||||
if(cachedBalance != newBalance || cachedStake != newStake || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance)
|
||||
{
|
||||
@@ -105,6 +103,7 @@ void WalletModel::checkBalanceChanged()
|
||||
cachedImmatureBalance = newImmatureBalance;
|
||||
emit balanceChanged(newBalance, newStake, newUnconfirmedBalance, newImmatureBalance);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WalletModel::updateTransaction(const QString &hash, int status)
|
||||
@@ -112,14 +111,20 @@ void WalletModel::updateTransaction(const QString &hash, int status)
|
||||
if(transactionTableModel)
|
||||
transactionTableModel->updateTransaction(hash, status);
|
||||
|
||||
// Balance and number of transactions might have changed
|
||||
checkBalanceChanged();
|
||||
// Don't call checkBalanceChanged() here - it does LOCK(cs_wallet) + iterates
|
||||
// all wallet transactions, blocking the UI thread. The pollBalanceChanged()
|
||||
// timer already handles balance updates every 2.5 seconds with TRY_LOCK.
|
||||
|
||||
int newNumTransactions = getNumTransactions();
|
||||
if(cachedNumTransactions != newNumTransactions)
|
||||
// Same for getNumTransactions() - use cached count from the transaction model
|
||||
// to avoid another LOCK(cs_wallet) on the UI thread.
|
||||
if(transactionTableModel)
|
||||
{
|
||||
cachedNumTransactions = newNumTransactions;
|
||||
emit numTransactionsChanged(newNumTransactions);
|
||||
int newNumTransactions = transactionTableModel->rowCount(QModelIndex());
|
||||
if(cachedNumTransactions != newNumTransactions)
|
||||
{
|
||||
cachedNumTransactions = newNumTransactions;
|
||||
emit numTransactionsChanged(newNumTransactions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +251,10 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
|
||||
|
||||
if(!fCreated)
|
||||
{
|
||||
if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future
|
||||
// NOTE: Potential edge case in fee calculation. The term "collisions" is unclear
|
||||
// from original comment - may refer to transaction conflicts or UTXO selection issues.
|
||||
// Consider reviewing Bitcoin Core's current implementation of this balance check.
|
||||
if((total + nFeeRequired) > nBalance)
|
||||
{
|
||||
return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ private:
|
||||
|
||||
void subscribeToCoreSignals();
|
||||
void unsubscribeFromCoreSignals();
|
||||
void checkBalanceChanged();
|
||||
bool checkBalanceChanged();
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
+6
-2
@@ -229,7 +229,8 @@ Value getworkex(const Array& params, bool fHelp)
|
||||
if(coinbase.size() == 0)
|
||||
pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
|
||||
else
|
||||
CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - DRM!
|
||||
// Deserialize custom coinbase transaction from miner
|
||||
CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0];
|
||||
|
||||
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
||||
|
||||
@@ -260,7 +261,10 @@ Value getwork(const Array& params, bool fHelp)
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "No more PoW blocks");
|
||||
|
||||
typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
|
||||
static mapNewBlock_t mapNewBlock; // FIXME: thread safety
|
||||
// NOTE: Thread safety issue - static variables accessed by multiple RPC threads
|
||||
// without mutex protection. Low priority since PoW ended at block 9000 and
|
||||
// getwork is rarely used. Consider adding std::mutex if usage increases.
|
||||
static mapNewBlock_t mapNewBlock;
|
||||
static vector<CBlock*> vNewBlock;
|
||||
static CReserveKey reservekey(pwalletMain);
|
||||
|
||||
|
||||
+45
-1
@@ -8,19 +8,62 @@
|
||||
#include "wallet.h"
|
||||
#include "db.h"
|
||||
#include "walletdb.h"
|
||||
#include "net_bootstrap.h"
|
||||
|
||||
using namespace json_spirit;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
const char* BootstrapModeToString(NetBootstrap::BootstrapMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case NetBootstrap::BOOTSTRAP_LEGACY:
|
||||
return "legacy";
|
||||
case NetBootstrap::BOOTSTRAP_TOR_MIXED:
|
||||
return "tor_mixed";
|
||||
case NetBootstrap::BOOTSTRAP_TOR_ONLY:
|
||||
return "tor_only";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
NetBootstrap::BootstrapMode GetBootstrapModeForRPC()
|
||||
{
|
||||
const bool torEnabled = GetBoolArg("-tor", false) || GetBoolArg("-proxy", false);
|
||||
const bool onlyTor = GetBoolArg("-onlynet", false) && GetArg("-onlynet", "") == "tor";
|
||||
|
||||
if (onlyTor)
|
||||
return NetBootstrap::BOOTSTRAP_TOR_ONLY;
|
||||
if (torEnabled)
|
||||
return NetBootstrap::BOOTSTRAP_TOR_MIXED;
|
||||
return NetBootstrap::BOOTSTRAP_LEGACY;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Value getnetworkinfo(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 0)
|
||||
throw runtime_error(
|
||||
"getnetworkinfo\n"
|
||||
"Returns an object containing various state info regarding P2P networking.");
|
||||
"Returns an object containing various state info regarding P2P networking,\n"
|
||||
"including peer mix, bootstrap mode, and basic sync health.");
|
||||
|
||||
proxyType proxy;
|
||||
GetProxy(NET_IPV4, proxy);
|
||||
const NetBootstrap::NetworkHealth health = NetBootstrap::GetNetworkHealth();
|
||||
|
||||
Object healthObj;
|
||||
healthObj.push_back(Pair("connectedpeers", health.connectedPeers));
|
||||
healthObj.push_back(Pair("torpeers", health.torPeers));
|
||||
healthObj.push_back(Pair("clearnetpeers", health.clearnetPeers));
|
||||
healthObj.push_back(Pair("bootstrapped", health.isBootstrapped));
|
||||
healthObj.push_back(Pair("syncing", health.isSyncing));
|
||||
healthObj.push_back(Pair("lastblocktime", static_cast<boost::int64_t>(health.lastBlockTime)));
|
||||
healthObj.push_back(Pair("bootstrapmode", BootstrapModeToString(GetBootstrapModeForRPC())));
|
||||
|
||||
Object obj;
|
||||
obj.push_back(Pair("version", FormatFullVersion()));
|
||||
@@ -30,6 +73,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
|
||||
obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
|
||||
obj.push_back(Pair("localservices", strprintf("%016"PRIx64, nLocalServices)));
|
||||
obj.push_back(Pair("testnet", fTestNet));
|
||||
obj.push_back(Pair("networkhealth", healthObj));
|
||||
obj.push_back(Pair("errors", GetWarnings("statusbar")));
|
||||
return obj;
|
||||
}
|
||||
|
||||
+4
-10
@@ -1471,9 +1471,7 @@ Value walletpassphrase(const Array& params, bool fHelp)
|
||||
// Note that the walletpassphrase is stored in params[0] which is not mlock()ed
|
||||
SecureString strWalletPass;
|
||||
strWalletPass.reserve(100);
|
||||
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
|
||||
// Alternately, find a way to make params[0] mlock()'d to begin with.
|
||||
strWalletPass = params[0].get_str().c_str();
|
||||
strWalletPass = MakeSecureString(params[0].get_str());
|
||||
|
||||
if (strWalletPass.length() > 0)
|
||||
{
|
||||
@@ -1510,15 +1508,13 @@ Value walletpassphrasechange(const Array& params, bool fHelp)
|
||||
if (!pwalletMain->IsCrypted())
|
||||
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
|
||||
|
||||
// TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
|
||||
// Alternately, find a way to make params[0] mlock()'d to begin with.
|
||||
SecureString strOldWalletPass;
|
||||
strOldWalletPass.reserve(100);
|
||||
strOldWalletPass = params[0].get_str().c_str();
|
||||
strOldWalletPass = MakeSecureString(params[0].get_str());
|
||||
|
||||
SecureString strNewWalletPass;
|
||||
strNewWalletPass.reserve(100);
|
||||
strNewWalletPass = params[1].get_str().c_str();
|
||||
strNewWalletPass = MakeSecureString(params[1].get_str());
|
||||
|
||||
if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
|
||||
throw runtime_error(
|
||||
@@ -1566,11 +1562,9 @@ Value encryptwallet(const Array& params, bool fHelp)
|
||||
if (pwalletMain->IsCrypted())
|
||||
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
|
||||
|
||||
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
|
||||
// Alternately, find a way to make params[0] mlock()'d to begin with.
|
||||
SecureString strWalletPass;
|
||||
strWalletPass.reserve(100);
|
||||
strWalletPass = params[0].get_str().c_str();
|
||||
strWalletPass = MakeSecureString(params[0].get_str());
|
||||
|
||||
if (strWalletPass.length() < 1)
|
||||
throw runtime_error(
|
||||
|
||||
+286
-66
@@ -29,8 +29,12 @@ Notes:
|
||||
|
||||
#include "smessage.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cctype>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
@@ -95,6 +99,187 @@ leveldb::DB *smsgDB = NULL;
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
const long int SMSG_BUCKET_FILE_SIZE_LIMIT = 0x70000000L;
|
||||
const int64_t SMSG_THREAD_SHUTDOWN_WAIT_MS = 5000;
|
||||
const int64_t SMSG_THREAD_SHUTDOWN_POLL_MS = 50;
|
||||
|
||||
std::atomic<int> nSecureMsgThreadsRunning(0);
|
||||
|
||||
class CSecureMsgThreadGuard
|
||||
{
|
||||
public:
|
||||
CSecureMsgThreadGuard()
|
||||
{
|
||||
++nSecureMsgThreadsRunning;
|
||||
};
|
||||
|
||||
~CSecureMsgThreadGuard()
|
||||
{
|
||||
--nSecureMsgThreadsRunning;
|
||||
};
|
||||
};
|
||||
|
||||
bool SecureMsgAllDigits(const std::string& value)
|
||||
{
|
||||
if (value.empty())
|
||||
return false;
|
||||
|
||||
for (std::string::const_iterator it = value.begin(); it != value.end(); ++it)
|
||||
{
|
||||
if (!std::isdigit((unsigned char) *it))
|
||||
return false;
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool SecureMsgParseBucketFilename(const std::string& fileName, int64_t& bucket, uint32_t& fileIndex, bool& fWalletLocked)
|
||||
{
|
||||
if (!boost::algorithm::ends_with(fileName, ".dat"))
|
||||
return false;
|
||||
|
||||
std::string baseName = fileName.substr(0, fileName.size() - 4);
|
||||
fWalletLocked = false;
|
||||
if (boost::algorithm::ends_with(baseName, "_wl"))
|
||||
{
|
||||
fWalletLocked = true;
|
||||
baseName.erase(baseName.size() - 3);
|
||||
};
|
||||
|
||||
size_t sep = baseName.find_first_of("_");
|
||||
if (sep == std::string::npos
|
||||
|| sep == 0
|
||||
|| sep + 1 >= baseName.size())
|
||||
return false;
|
||||
|
||||
std::string sBucket = baseName.substr(0, sep);
|
||||
std::string sIndex = baseName.substr(sep + 1);
|
||||
|
||||
if (!SecureMsgAllDigits(sBucket)
|
||||
|| !SecureMsgAllDigits(sIndex))
|
||||
return false;
|
||||
|
||||
try {
|
||||
bucket = std::stoll(sBucket);
|
||||
unsigned long nIndex = std::stoul(sIndex);
|
||||
if (nIndex < 1
|
||||
|| nIndex > (unsigned long) std::numeric_limits<uint32_t>::max())
|
||||
return false;
|
||||
|
||||
fileIndex = (uint32_t) nIndex;
|
||||
} catch (const std::exception&)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
std::string SecureMsgBucketFilename(int64_t bucket, uint32_t fileIndex, bool fWalletLocked)
|
||||
{
|
||||
std::string sIndex = std::to_string(fileIndex);
|
||||
if (fileIndex < 10)
|
||||
sIndex.insert(0, "0");
|
||||
|
||||
return std::to_string(bucket) + "_" + sIndex + (fWalletLocked ? "_wl.dat" : ".dat");
|
||||
};
|
||||
|
||||
void SecureMsgGetBucketFiles(const fs::path& pathSmsgDir, int64_t bucket, bool fWalletLocked, std::vector<std::pair<uint32_t, fs::path> >& bucketFiles)
|
||||
{
|
||||
bucketFiles.clear();
|
||||
|
||||
if (!fs::exists(pathSmsgDir)
|
||||
|| !fs::is_directory(pathSmsgDir))
|
||||
return;
|
||||
|
||||
fs::directory_iterator itend;
|
||||
for (fs::directory_iterator itd(pathSmsgDir) ; itd != itend ; ++itd)
|
||||
{
|
||||
if (!fs::is_regular_file(itd->status()))
|
||||
continue;
|
||||
|
||||
int64_t fileBucket;
|
||||
uint32_t fileIndex;
|
||||
bool fFileWalletLocked;
|
||||
std::string fileName = (*itd).path().filename().string();
|
||||
if (!SecureMsgParseBucketFilename(fileName, fileBucket, fileIndex, fFileWalletLocked))
|
||||
continue;
|
||||
|
||||
if (fileBucket != bucket
|
||||
|| fFileWalletLocked != fWalletLocked)
|
||||
continue;
|
||||
|
||||
bucketFiles.push_back(std::make_pair(fileIndex, (*itd).path()));
|
||||
};
|
||||
|
||||
std::sort(bucketFiles.begin(), bucketFiles.end(),
|
||||
[](const std::pair<uint32_t, fs::path>& a, const std::pair<uint32_t, fs::path>& b)
|
||||
{
|
||||
return a.first < b.first;
|
||||
});
|
||||
};
|
||||
|
||||
void SecureMsgRemoveBucketFiles(const fs::path& pathSmsgDir, int64_t bucket, bool fWalletLocked)
|
||||
{
|
||||
std::vector<std::pair<uint32_t, fs::path> > bucketFiles;
|
||||
SecureMsgGetBucketFiles(pathSmsgDir, bucket, fWalletLocked, bucketFiles);
|
||||
|
||||
for (std::vector<std::pair<uint32_t, fs::path> >::iterator it = bucketFiles.begin(); it != bucketFiles.end(); ++it)
|
||||
{
|
||||
try {
|
||||
fs::remove(it->second);
|
||||
} catch (const fs::filesystem_error& ex)
|
||||
{
|
||||
printf("Error removing %s file %s.\n", fWalletLocked ? "wallet locked" : "bucket", ex.what());
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
bool SecureMsgSelectBucketFile(const fs::path& pathSmsgDir, int64_t bucket, bool fWalletLocked, uint32_t nPayload, fs::path& fullPath, uint32_t& fileIndex)
|
||||
{
|
||||
std::vector<std::pair<uint32_t, fs::path> > bucketFiles;
|
||||
SecureMsgGetBucketFiles(pathSmsgDir, bucket, fWalletLocked, bucketFiles);
|
||||
|
||||
fileIndex = 1;
|
||||
if (!bucketFiles.empty())
|
||||
{
|
||||
fileIndex = bucketFiles.back().first;
|
||||
|
||||
try {
|
||||
uintmax_t nFileSize = fs::file_size(bucketFiles.back().second);
|
||||
if (nFileSize + SMSG_HDR_LEN + nPayload > (uintmax_t) SMSG_BUCKET_FILE_SIZE_LIMIT)
|
||||
fileIndex++;
|
||||
} catch (const fs::filesystem_error&)
|
||||
{
|
||||
fileIndex++;
|
||||
};
|
||||
};
|
||||
|
||||
fullPath = pathSmsgDir / SecureMsgBucketFilename(bucket, fileIndex, fWalletLocked);
|
||||
return true;
|
||||
};
|
||||
|
||||
bool SecureMsgWaitForThreadsToStop()
|
||||
{
|
||||
int64_t nDeadline = GetTimeMillis() + SMSG_THREAD_SHUTDOWN_WAIT_MS;
|
||||
while (nSecureMsgThreadsRunning.load() > 0
|
||||
&& GetTimeMillis() < nDeadline)
|
||||
{
|
||||
MilliSleep(SMSG_THREAD_SHUTDOWN_POLL_MS);
|
||||
};
|
||||
|
||||
if (nSecureMsgThreadsRunning.load() > 0)
|
||||
{
|
||||
printf("Timed out waiting for secure messaging threads to stop (%d still running).\n", nSecureMsgThreadsRunning.load());
|
||||
return false;
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
bool SecMsgCrypter::SetKey(const std::vector<unsigned char>& vchNewKey, unsigned char* chNewIV)
|
||||
{
|
||||
|
||||
@@ -591,6 +776,7 @@ void ThreadSecureMsg(void* parg)
|
||||
{
|
||||
// -- bucket management thread
|
||||
RenameThread("shadowcoin-smsg"); // Make this thread recognisable
|
||||
CSecureMsgThreadGuard threadGuard;
|
||||
|
||||
uint32_t delay = 0;
|
||||
|
||||
@@ -627,31 +813,9 @@ void ThreadSecureMsg(void* parg)
|
||||
{
|
||||
if (fDebugSmsg)
|
||||
printf("Removing bucket %"PRId64" \n", it->first);
|
||||
std::string fileName = std::to_string(it->first) + "_01.dat";
|
||||
fs::path fullPath = GetDataDir() / "smsgStore" / fileName;
|
||||
if (fs::exists(fullPath))
|
||||
{
|
||||
try {
|
||||
fs::remove(fullPath);
|
||||
} catch (const fs::filesystem_error& ex)
|
||||
{
|
||||
printf("Error removing bucket file %s.\n", ex.what());
|
||||
};
|
||||
} else
|
||||
printf("Path %s does not exist \n", fullPath.string().c_str());
|
||||
|
||||
// -- look for a wl file, it stores incoming messages when wallet is locked
|
||||
fileName = std::to_string(it->first) + "_01_wl.dat";
|
||||
fullPath = GetDataDir() / "smsgStore" / fileName;
|
||||
if (fs::exists(fullPath))
|
||||
{
|
||||
try {
|
||||
fs::remove(fullPath);
|
||||
} catch (const fs::filesystem_error& ex)
|
||||
{
|
||||
printf("Error removing wallet locked file %s.\n", ex.what());
|
||||
};
|
||||
};
|
||||
fs::path pathSmsgDir = GetDataDir() / "smsgStore";
|
||||
SecureMsgRemoveBucketFiles(pathSmsgDir, it->first, false);
|
||||
SecureMsgRemoveBucketFiles(pathSmsgDir, it->first, true);
|
||||
|
||||
smsgBuckets.erase(it++);
|
||||
} else
|
||||
@@ -702,6 +866,7 @@ void ThreadSecureMsgPow(void* parg)
|
||||
{
|
||||
// -- proof of work thread
|
||||
RenameThread("shadowcoin-smsg-pow"); // Make this thread recognisable
|
||||
CSecureMsgThreadGuard threadGuard;
|
||||
|
||||
int rv;
|
||||
std::vector<unsigned char> vchKey;
|
||||
@@ -860,15 +1025,15 @@ int SecureMsgBuildBucketSet()
|
||||
|
||||
nFiles++;
|
||||
|
||||
// TODO files must be split if > 2GB
|
||||
// time_noFile.dat
|
||||
size_t sep = fileName.find_first_of("_");
|
||||
if (sep == std::string::npos)
|
||||
int64_t fileTime;
|
||||
uint32_t fileIndex;
|
||||
bool fWalletLocked;
|
||||
if (!SecureMsgParseBucketFilename(fileName, fileTime, fileIndex, fWalletLocked))
|
||||
{
|
||||
if (fDebugSmsg)
|
||||
printf("Skipping unrecognised bucket file: %s.\n", fileName.c_str());
|
||||
continue;
|
||||
|
||||
std::string stime = fileName.substr(0, sep);
|
||||
|
||||
int64_t fileTime = std::stoll(stime);
|
||||
};
|
||||
|
||||
if (fileTime < now - SMSG_RETENTION)
|
||||
{
|
||||
@@ -882,7 +1047,7 @@ int SecureMsgBuildBucketSet()
|
||||
continue;
|
||||
};
|
||||
|
||||
if (boost::algorithm::ends_with(fileName, "_wl.dat"))
|
||||
if (fWalletLocked)
|
||||
{
|
||||
if (fDebugSmsg)
|
||||
printf("Skipping wallet locked file: %s.\n", fileName.c_str());
|
||||
@@ -907,6 +1072,7 @@ int SecureMsgBuildBucketSet()
|
||||
{
|
||||
long int ofs = ftell(fp);
|
||||
SecMsgToken token;
|
||||
token.fileIndex = fileIndex;
|
||||
token.offset = ofs;
|
||||
errno = 0;
|
||||
if (fread(&smsg.hash[0], sizeof(unsigned char), SMSG_HDR_LEN, fp) != (size_t)SMSG_HDR_LEN)
|
||||
@@ -937,15 +1103,14 @@ int SecureMsgBuildBucketSet()
|
||||
break;
|
||||
};
|
||||
|
||||
tokenSet.insert(token);
|
||||
if (tokenSet.insert(token).second)
|
||||
nMessages++;
|
||||
};
|
||||
|
||||
fclose(fp);
|
||||
};
|
||||
smsgBuckets[fileTime].hashBucket();
|
||||
|
||||
nMessages += tokenSet.size();
|
||||
|
||||
if (fDebugSmsg)
|
||||
printf("Bucket %"PRId64" contains %"PRIszu" messages.\n", fileTime, tokenSet.size());
|
||||
};
|
||||
@@ -1176,6 +1341,7 @@ bool SecureMsgStart(bool fDontStart, bool fScanChain)
|
||||
{
|
||||
printf("SecureMsg could not start threads, secure messaging disabled.\n");
|
||||
fSecMsgEnabled = false;
|
||||
SecureMsgWaitForThreadsToStop();
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -1195,6 +1361,7 @@ bool SecureMsgShutdown()
|
||||
printf("Failed to save smsg.ini\n");
|
||||
|
||||
fSecMsgEnabled = false;
|
||||
SecureMsgWaitForThreadsToStop();
|
||||
|
||||
if (smsgDB)
|
||||
{
|
||||
@@ -1249,6 +1416,7 @@ bool SecureMsgEnable()
|
||||
{
|
||||
printf("SecureMsgEnable could not start threads, secure messaging disabled.\n");
|
||||
fSecMsgEnabled = false;
|
||||
SecureMsgWaitForThreadsToStop();
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -1308,9 +1476,7 @@ bool SecureMsgDisable()
|
||||
|
||||
}; // LOCK(cs_smsg);
|
||||
|
||||
// -- allow time for threads to stop
|
||||
MilliSleep(3000); // milliseconds
|
||||
// TODO be certain that threads have stopped
|
||||
SecureMsgWaitForThreadsToStop();
|
||||
|
||||
if (smsgDB)
|
||||
{
|
||||
@@ -1659,6 +1825,7 @@ bool SecureMsgReceiveData(CNode* pfrom, std::string strCommand, CDataStream& vRe
|
||||
} else
|
||||
{
|
||||
//printf("Have message at %"PRId64".\n", it->offset); // DEBUG
|
||||
token.fileIndex = it->fileIndex;
|
||||
token.offset = it->offset;
|
||||
//printf("winb before SecureMsgRetrieve %"PRId64".\n", token.timestamp);
|
||||
|
||||
@@ -2216,15 +2383,15 @@ bool SecureMsgScanBuckets()
|
||||
|
||||
nFiles++;
|
||||
|
||||
// TODO files must be split if > 2GB
|
||||
// time_noFile.dat
|
||||
size_t sep = fileName.find_first_of("_");
|
||||
if (sep == std::string::npos)
|
||||
int64_t fileTime;
|
||||
uint32_t fileIndex;
|
||||
bool fWalletLocked;
|
||||
if (!SecureMsgParseBucketFilename(fileName, fileTime, fileIndex, fWalletLocked))
|
||||
{
|
||||
if (fDebugSmsg)
|
||||
printf("Skipping unrecognised bucket file: %s.\n", fileName.c_str());
|
||||
continue;
|
||||
|
||||
std::string stime = fileName.substr(0, sep);
|
||||
|
||||
int64_t fileTime = std::stoll(stime);
|
||||
};
|
||||
|
||||
if (fileTime < now - SMSG_RETENTION)
|
||||
{
|
||||
@@ -2238,7 +2405,7 @@ bool SecureMsgScanBuckets()
|
||||
continue;
|
||||
};
|
||||
|
||||
if (boost::algorithm::ends_with(fileName, "_wl.dat"))
|
||||
if (fWalletLocked)
|
||||
{
|
||||
if (fDebugSmsg)
|
||||
printf("Skipping wallet locked file: %s.\n", fileName.c_str());
|
||||
@@ -2362,7 +2529,17 @@ int SecureMsgWalletUnlocked()
|
||||
|
||||
std::string fileName = (*itd).path().filename().string();
|
||||
|
||||
if (!boost::algorithm::ends_with(fileName, "_wl.dat"))
|
||||
int64_t fileTime;
|
||||
uint32_t fileIndex;
|
||||
bool fWalletLocked;
|
||||
if (!SecureMsgParseBucketFilename(fileName, fileTime, fileIndex, fWalletLocked))
|
||||
{
|
||||
if (fDebugSmsg)
|
||||
printf("Skipping unrecognised bucket file: %s.\n", fileName.c_str());
|
||||
continue;
|
||||
};
|
||||
|
||||
if (!fWalletLocked)
|
||||
continue;
|
||||
|
||||
if (fDebugSmsg)
|
||||
@@ -2370,16 +2547,6 @@ int SecureMsgWalletUnlocked()
|
||||
|
||||
nFiles++;
|
||||
|
||||
// TODO files must be split if > 2GB
|
||||
// time_noFile_wl.dat
|
||||
size_t sep = fileName.find_first_of("_");
|
||||
if (sep == std::string::npos)
|
||||
continue;
|
||||
|
||||
std::string stime = fileName.substr(0, sep);
|
||||
|
||||
int64_t fileTime = std::stoll(stime);
|
||||
|
||||
if (fileTime < now - SMSG_RETENTION)
|
||||
{
|
||||
printf("Dropping wallet locked file %s, expired.\n", fileName.c_str());
|
||||
@@ -2769,7 +2936,7 @@ int SecureMsgRetrieve(SecMsgToken &token, std::vector<unsigned char>& vchData)
|
||||
|
||||
//printf("token.offset %"PRId64".\n", token.offset); // DEBUG
|
||||
int64_t bucket = token.timestamp - (token.timestamp % SMSG_BUCKET_LEN);
|
||||
std::string fileName = std::to_string(bucket) + "_01.dat";
|
||||
std::string fileName = SecureMsgBucketFilename(bucket, token.fileIndex, false);
|
||||
fs::path fullpath = pathSmsgDir / fileName;
|
||||
|
||||
//printf("bucket %"PRId64".\n", bucket);
|
||||
@@ -2971,9 +3138,9 @@ int SecureMsgStoreUnscanned(unsigned char *pHeader, unsigned char *pPayload, uin
|
||||
};
|
||||
|
||||
int64_t bucket = psmsg->timestamp - (psmsg->timestamp % SMSG_BUCKET_LEN);
|
||||
|
||||
std::string fileName = std::to_string(bucket) + "_01_wl.dat";
|
||||
fs::path fullpath = pathSmsgDir / fileName;
|
||||
fs::path fullpath;
|
||||
uint32_t fileIndex;
|
||||
SecureMsgSelectBucketFile(pathSmsgDir, bucket, true, nPayload, fullpath, fileIndex);
|
||||
|
||||
FILE *fp;
|
||||
errno = 0;
|
||||
@@ -2982,6 +3149,31 @@ int SecureMsgStoreUnscanned(unsigned char *pHeader, unsigned char *pPayload, uin
|
||||
printf("Error opening file: %s\n", strerror(errno));
|
||||
return 1;
|
||||
};
|
||||
|
||||
errno = 0;
|
||||
if (fseek(fp, 0, SEEK_END) != 0)
|
||||
{
|
||||
printf("Error fseek failed: %s\n", strerror(errno));
|
||||
fclose(fp);
|
||||
return 1;
|
||||
};
|
||||
|
||||
long int ofs = ftell(fp);
|
||||
long int nRecordSize = SMSG_HDR_LEN + nPayload;
|
||||
if (ofs > 0
|
||||
&& ofs > SMSG_BUCKET_FILE_SIZE_LIMIT - nRecordSize)
|
||||
{
|
||||
fclose(fp);
|
||||
|
||||
fileIndex++;
|
||||
fullpath = pathSmsgDir / SecureMsgBucketFilename(bucket, fileIndex, true);
|
||||
errno = 0;
|
||||
if (!(fp = fopen(fullpath.string().c_str(), "ab")))
|
||||
{
|
||||
printf("Error opening file: %s\n", strerror(errno));
|
||||
return 1;
|
||||
};
|
||||
};
|
||||
|
||||
if (fwrite(pHeader, sizeof(unsigned char), SMSG_HDR_LEN, fp) != (size_t)SMSG_HDR_LEN
|
||||
|| fwrite(pPayload, sizeof(unsigned char), nPayload, fp) != nPayload)
|
||||
@@ -3073,8 +3265,9 @@ int SecureMsgStore(unsigned char *pHeader, unsigned char *pPayload, uint32_t nPa
|
||||
return 1;
|
||||
};
|
||||
|
||||
std::string fileName = std::to_string(bucket) + "_01.dat";
|
||||
fs::path fullpath = pathSmsgDir / fileName;
|
||||
fs::path fullpath;
|
||||
uint32_t fileIndex;
|
||||
SecureMsgSelectBucketFile(pathSmsgDir, bucket, false, nPayload, fullpath, fileIndex);
|
||||
|
||||
FILE *fp;
|
||||
errno = 0;
|
||||
@@ -3089,11 +3282,37 @@ int SecureMsgStore(unsigned char *pHeader, unsigned char *pPayload, uint32_t nPa
|
||||
if (fseek(fp, 0, SEEK_END) != 0)
|
||||
{
|
||||
printf("Error fseek failed: %s\n", strerror(errno));
|
||||
fclose(fp);
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
ofs = ftell(fp);
|
||||
long int nRecordSize = SMSG_HDR_LEN + nPayload;
|
||||
if (ofs > 0
|
||||
&& ofs > SMSG_BUCKET_FILE_SIZE_LIMIT - nRecordSize)
|
||||
{
|
||||
fclose(fp);
|
||||
|
||||
fileIndex++;
|
||||
fullpath = pathSmsgDir / SecureMsgBucketFilename(bucket, fileIndex, false);
|
||||
errno = 0;
|
||||
if (!(fp = fopen(fullpath.string().c_str(), "ab")))
|
||||
{
|
||||
printf("Error opening file: %s\n", strerror(errno));
|
||||
return 1;
|
||||
};
|
||||
|
||||
errno = 0;
|
||||
if (fseek(fp, 0, SEEK_END) != 0)
|
||||
{
|
||||
printf("Error fseek failed: %s\n", strerror(errno));
|
||||
fclose(fp);
|
||||
return 1;
|
||||
};
|
||||
|
||||
ofs = ftell(fp);
|
||||
};
|
||||
|
||||
if (fwrite(pHeader, sizeof(unsigned char), SMSG_HDR_LEN, fp) != (size_t)SMSG_HDR_LEN
|
||||
|| fwrite(pPayload, sizeof(unsigned char), nPayload, fp) != nPayload)
|
||||
@@ -3105,6 +3324,7 @@ int SecureMsgStore(unsigned char *pHeader, unsigned char *pPayload, uint32_t nPa
|
||||
|
||||
fclose(fp);
|
||||
|
||||
token.fileIndex = fileIndex;
|
||||
token.offset = ofs;
|
||||
|
||||
//printf("token.offset: %"PRId64"\n", token.offset); // DEBUG
|
||||
|
||||
+10
-2
@@ -109,7 +109,7 @@ public:
|
||||
class SecMsgToken
|
||||
{
|
||||
public:
|
||||
SecMsgToken(int64_t ts, unsigned char* p, int np, long int o)
|
||||
SecMsgToken(int64_t ts, unsigned char* p, int np, long int o, uint32_t nFile = 1)
|
||||
{
|
||||
timestamp = ts;
|
||||
|
||||
@@ -117,10 +117,17 @@ public:
|
||||
memset(sample, 0, 8);
|
||||
else
|
||||
memcpy(sample, p, 8);
|
||||
fileIndex = nFile;
|
||||
offset = o;
|
||||
};
|
||||
|
||||
SecMsgToken() {};
|
||||
SecMsgToken()
|
||||
{
|
||||
timestamp = 0;
|
||||
memset(sample, 0, 8);
|
||||
fileIndex = 1;
|
||||
offset = 0;
|
||||
};
|
||||
|
||||
~SecMsgToken() {};
|
||||
|
||||
@@ -134,6 +141,7 @@ public:
|
||||
|
||||
int64_t timestamp; // doesn't need to be full 64 bytes?
|
||||
unsigned char sample[8]; // first 8 bytes of payload - a hash
|
||||
uint32_t fileIndex; // rotated bucket file suffix, eg _02.dat
|
||||
int64_t offset; // offset
|
||||
|
||||
};
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
//
|
||||
// Unit tests for block-chain checkpoints
|
||||
//
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "../checkpoints.h"
|
||||
#include "../util.h"
|
||||
|
||||
using namespace std;
|
||||
#include "../uint256.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Checkpoints_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(sanity)
|
||||
BOOST_AUTO_TEST_CASE(hardened_checkpoints_match_current_chain)
|
||||
{
|
||||
uint256 p11111 = uint256("0x05cbc42d0421207a39427f1b44610a30380e0e3dd593c154276d7c8d4ae8c9b2");
|
||||
uint256 p16666 = uint256("0x682d99d096441e046dae8dd86d5bdfaa32d4e29dea6cf38273bb2b261905f1e2");
|
||||
BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111));
|
||||
BOOST_CHECK(Checkpoints::CheckBlock(16666, p16666));
|
||||
BOOST_CHECK(Checkpoints::CheckHardened(0, uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021")));
|
||||
BOOST_CHECK(Checkpoints::CheckHardened(9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")));
|
||||
BOOST_CHECK(Checkpoints::CheckHardened(9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")));
|
||||
BOOST_CHECK(Checkpoints::CheckHardened(2186940, uint256("0xbd952e8d4a612e336d840ad924a7e09395e36bcd9d929b302e47e60b5c3098c0")));
|
||||
}
|
||||
|
||||
|
||||
// Wrong hashes at checkpoints should fail:
|
||||
BOOST_CHECK(!Checkpoints::CheckBlock(11111, p16666));
|
||||
BOOST_CHECK(!Checkpoints::CheckBlock(16666, p11111));
|
||||
BOOST_AUTO_TEST_CASE(hardened_checkpoints_reject_wrong_hashes_and_allow_unknown_heights)
|
||||
{
|
||||
const uint256 wrongHash("0x0000000000000000000000000000000000000000000000000000000000000001");
|
||||
|
||||
// ... but any hash not at a checkpoint should succeed:
|
||||
BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p16666));
|
||||
BOOST_CHECK(Checkpoints::CheckBlock(16666+1, p11111));
|
||||
BOOST_CHECK(!Checkpoints::CheckHardened(9000, wrongHash));
|
||||
BOOST_CHECK(!Checkpoints::CheckHardened(9001, wrongHash));
|
||||
BOOST_CHECK(!Checkpoints::CheckHardened(2186940, wrongHash));
|
||||
|
||||
BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 16666);
|
||||
}
|
||||
BOOST_CHECK(Checkpoints::CheckHardened(2186941, wrongHash));
|
||||
BOOST_CHECK(Checkpoints::CheckHardened(42, wrongHash));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(total_blocks_estimate_tracks_latest_hardened_checkpoint)
|
||||
{
|
||||
BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 2186940);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
|
||||
BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
{
|
||||
CNode::ClearBanned();
|
||||
int64 nStartTime = GetTime();
|
||||
int64_t nStartTime = GetTime();
|
||||
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
||||
|
||||
CAddress addr(ip(0xa0b0c001));
|
||||
@@ -80,11 +80,11 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
BOOST_CHECK(!CNode::IsBanned(addr));
|
||||
}
|
||||
|
||||
static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)\
|
||||
static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, int64_t time2)\
|
||||
{
|
||||
if (time1 > time2)
|
||||
return CheckNBits(nbits2, time2, nbits1, time1);
|
||||
int64 deltaTime = time2-time1;
|
||||
int64_t deltaTime = time2-time1;
|
||||
|
||||
CBigNum required;
|
||||
required.SetCompact(ComputeMinWork(nbits1, deltaTime));
|
||||
@@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits)
|
||||
{
|
||||
// Timestamps,nBits from the Triangles blockchain.
|
||||
// These are the block-chain checkpoint blocks
|
||||
typedef std::map<int64, unsigned int> BlockData;
|
||||
typedef std::map<int64_t, unsigned int> BlockData;
|
||||
BlockData chainData = {
|
||||
{1239852051,486604799},{1262749024,486594666},
|
||||
{1279305360,469854461},{1280200847,469830746},{1281678674,469809688},
|
||||
@@ -275,7 +275,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
|
||||
mst1 = boost::posix_time::microsec_clock::local_time();
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++)
|
||||
BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
|
||||
BOOST_CHECK(VerifySignature(orphans[j], tx, j, SIGHASH_ALL));
|
||||
mst2 = boost::posix_time::microsec_clock::local_time();
|
||||
msdiff = mst2 - mst1;
|
||||
long nManyValidate = msdiff.total_milliseconds();
|
||||
@@ -286,13 +286,13 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
|
||||
// Empty a signature, validation should fail:
|
||||
CScript save = tx.vin[0].scriptSig;
|
||||
tx.vin[0].scriptSig = CScript();
|
||||
BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
|
||||
BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, SIGHASH_ALL));
|
||||
tx.vin[0].scriptSig = save;
|
||||
|
||||
// Swap signatures, validation should fail:
|
||||
std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
|
||||
BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
|
||||
BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL));
|
||||
BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, SIGHASH_ALL));
|
||||
BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, SIGHASH_ALL));
|
||||
std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
|
||||
|
||||
// Exercise -maxsigcachesize code:
|
||||
@@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
|
||||
BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
|
||||
BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
|
||||
for (unsigned int j = 0; j < tx.vin.size(); j++)
|
||||
BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
|
||||
BOOST_CHECK(VerifySignature(orphans[j], tx, j, SIGHASH_ALL));
|
||||
mapArgs.erase("-maxsigcachesize");
|
||||
|
||||
LimitOrphanTxSize(0);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
BOOST_AUTO_TEST_SUITE(accounting_tests)
|
||||
|
||||
static void
|
||||
GetResults(CWalletDB& walletdb, std::map<int64, CAccountingEntry>& results)
|
||||
GetResults(CWalletDB& walletdb, std::map<int64_t, CAccountingEntry>& results)
|
||||
{
|
||||
std::list<CAccountingEntry> aes;
|
||||
|
||||
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
|
||||
std::vector<CWalletTx*> vpwtx;
|
||||
CWalletTx wtx;
|
||||
CAccountingEntry ae;
|
||||
std::map<int64, CAccountingEntry> results;
|
||||
std::map<int64_t, CAccountingEntry> results;
|
||||
|
||||
ae.strAccount = "";
|
||||
ae.nCreditDebit = 1;
|
||||
|
||||
@@ -46,7 +46,7 @@ BOOST_AUTO_TEST_SUITE(bignum_tests)
|
||||
// Let's force this code not to be inlined, in order to actually
|
||||
// test a generic version of the function. This increases the chance
|
||||
// that -ftrapv will detect overflows.
|
||||
NOINLINE void mysetint64(CBigNum& num, int64 n)
|
||||
NOINLINE void mysetint64(CBigNum& num, int64_t n)
|
||||
{
|
||||
num.setint64(n);
|
||||
}
|
||||
@@ -55,7 +55,7 @@ NOINLINE void mysetint64(CBigNum& num, int64 n)
|
||||
// value to 0, then the second one with a non-inlined function.
|
||||
BOOST_AUTO_TEST_CASE(bignum_setint64)
|
||||
{
|
||||
int64 n;
|
||||
int64_t n;
|
||||
|
||||
{
|
||||
n = 0;
|
||||
@@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(bignum_setint64)
|
||||
BOOST_CHECK(num.ToString() == "-5");
|
||||
}
|
||||
{
|
||||
n = std::numeric_limits<int64>::min();
|
||||
n = std::numeric_limits<int64_t>::min();
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "-9223372036854775808");
|
||||
num.setulong(0);
|
||||
@@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE(bignum_setint64)
|
||||
BOOST_CHECK(num.ToString() == "-9223372036854775808");
|
||||
}
|
||||
{
|
||||
n = std::numeric_limits<int64>::max();
|
||||
n = std::numeric_limits<int64_t>::max();
|
||||
CBigNum num(n);
|
||||
BOOST_CHECK(num.ToString() == "9223372036854775807");
|
||||
num.setulong(0);
|
||||
|
||||
@@ -53,7 +53,7 @@ ParseScript(string s)
|
||||
(starts_with(w, "-") && all(string(w.begin()+1, w.end()), is_digit())))
|
||||
{
|
||||
// Number
|
||||
int64 n = atoi64(w);
|
||||
int64_t n = atoi64(w);
|
||||
result << n;
|
||||
}
|
||||
else if (starts_with(w, "0x") && IsHex(string(w.begin()+2, w.end())))
|
||||
|
||||
@@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(util_FormatMoney)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_ParseMoney)
|
||||
{
|
||||
int64 ret = 0;
|
||||
int64_t ret = 0;
|
||||
BOOST_CHECK(ParseMoney("0.0", ret));
|
||||
BOOST_CHECK_EQUAL(ret, 0);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ BOOST_AUTO_TEST_SUITE(wallet_tests)
|
||||
static CWallet wallet;
|
||||
static vector<COutput> vCoins;
|
||||
|
||||
static void add_coin(int64 nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
|
||||
static void add_coin(int64_t nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
|
||||
{
|
||||
static int i;
|
||||
CTransaction* tx = new CTransaction;
|
||||
@@ -56,7 +56,7 @@ static bool equal_sets(CoinSet a, CoinSet b)
|
||||
BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
{
|
||||
static CoinSet setCoinsRet, setCoinsRet2;
|
||||
static int64 nValueRet;
|
||||
static int64_t nValueRet;
|
||||
|
||||
// test multiple times to allow for differences in the shuffle order
|
||||
for (int i = 0; i < RUN_TESTS; i++)
|
||||
|
||||
@@ -430,7 +430,7 @@ static string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
|
||||
"HTTP/1.1 %d %s\r\n"
|
||||
"Date: %s\r\n"
|
||||
"Connection: %s\r\n"
|
||||
"Content-Length: %"PRIszu"\r\n"
|
||||
"Content-Length: %" PRIszu "\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Server: Triangles-json-rpc/%s\r\n"
|
||||
"\r\n"
|
||||
@@ -787,10 +787,16 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
|
||||
|
||||
AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn);
|
||||
|
||||
// TODO: Actually handle errors
|
||||
if (error)
|
||||
{
|
||||
if (error != asio::error::operation_aborted)
|
||||
printf("RPC accept error from %s: %s (%d)\n",
|
||||
tcp_conn ? tcp_conn->peer.address().to_string().c_str() : "unknown peer",
|
||||
error.message().c_str(),
|
||||
error.value());
|
||||
delete conn;
|
||||
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
||||
return;
|
||||
}
|
||||
|
||||
// Restrict callers by IP. It is important to
|
||||
@@ -1064,7 +1070,7 @@ static void HandleSSEConnection(AcceptedConnection* conn)
|
||||
// Send events
|
||||
for (size_t i = 0; i < vEvents.size(); i++)
|
||||
{
|
||||
std::string strSSE = strprintf("id: %"PRIu64"\ndata: %s\n\n", nLastId - vEvents.size() + i + 1, vEvents[i].c_str());
|
||||
std::string strSSE = strprintf("id: %" PRIu64 "\ndata: %s\n\n", nLastId - vEvents.size() + i + 1, vEvents[i].c_str());
|
||||
try {
|
||||
conn->stream() << strSSE << std::flush;
|
||||
} catch (...) {
|
||||
|
||||
+11
-1
@@ -34,6 +34,12 @@ static leveldb::Options GetOptions() {
|
||||
int nCacheSizeMB = GetArg("-dbcache", 2048);
|
||||
options.block_cache = leveldb::NewLRUCache(nCacheSizeMB * 1048576);
|
||||
options.filter_policy = leveldb::NewBloomFilterPolicy(10);
|
||||
// Larger write buffer (64MB vs default 4MB) reduces the frequency of
|
||||
// memtable flushes and compactions, which is a big win during IBD
|
||||
// when millions of tx index entries are written sequentially.
|
||||
options.write_buffer_size = 64 * 1048576;
|
||||
// Allow more open files for better read performance on large chains
|
||||
options.max_open_files = 1000;
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -138,7 +144,11 @@ void CTxDB::Close()
|
||||
|
||||
bool CTxDB::TxnBegin()
|
||||
{
|
||||
assert(!activeBatch);
|
||||
// Allow calling TxnBegin when a batch is already active (no-op).
|
||||
// This lets callers like SetBestChain share a batch that was opened
|
||||
// earlier by AddToBlockIndex, merging two commits into one.
|
||||
if (activeBatch)
|
||||
return true;
|
||||
activeBatch = new leveldb::WriteBatch();
|
||||
return true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -237,7 +237,7 @@ void runCommand(std::string strCommand);
|
||||
|
||||
inline std::string i64tostr(int64_t n)
|
||||
{
|
||||
return strprintf("%"PRId64, n);
|
||||
return strprintf("%" PRId64, n);
|
||||
}
|
||||
|
||||
inline std::string itostr(int n)
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ static const int MEMPOOL_GD_VERSION = 60002;
|
||||
|
||||
#define DISPLAY_VERSION_MAJOR 5
|
||||
#define DISPLAY_VERSION_MINOR 3
|
||||
#define DISPLAY_VERSION_REVISION 3
|
||||
#define DISPLAY_VERSION_REVISION 7
|
||||
#define DISPLAY_VERSION_BUILD 0
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1476,6 +1476,34 @@ int64_t CWallet::GetNewMint() const
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
bool CWallet::GetAllBalances(int64_t& nBalance, int64_t& nStake, int64_t& nUnconfirmed, int64_t& nImmature) const
|
||||
{
|
||||
nBalance = 0;
|
||||
nStake = 0;
|
||||
nUnconfirmed = 0;
|
||||
nImmature = 0;
|
||||
TRY_LOCK(cs_wallet, lockWallet);
|
||||
if (!lockWallet)
|
||||
return false;
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx& pcoin = (*it).second;
|
||||
|
||||
if (pcoin.IsCoinStake() && pcoin.GetBlocksToMaturity() > 0 && pcoin.GetDepthInMainChain() > 0)
|
||||
nStake += CWallet::GetCredit(pcoin);
|
||||
|
||||
if (pcoin.IsCoinBase() && pcoin.GetBlocksToMaturity() > 0 && pcoin.IsInMainChain())
|
||||
nImmature += GetCredit(pcoin);
|
||||
|
||||
if (pcoin.IsTrusted())
|
||||
nBalance += pcoin.GetAvailableCredit();
|
||||
|
||||
if (!pcoin.IsFinal() || !pcoin.IsTrusted())
|
||||
nUnconfirmed += pcoin.GetAvailableCredit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, vector<COutput> vCoins, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const
|
||||
{
|
||||
setCoinsRet.clear();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -107,6 +108,8 @@ public:
|
||||
nMasterKeyMaxID = 0;
|
||||
pwalletdbEncryption = NULL;
|
||||
nOrderPosNext = 0;
|
||||
nCachedStakeWeight = 0;
|
||||
nCachedStakeWeightTime = 0;
|
||||
}
|
||||
CWallet(std::string strWalletFileIn)
|
||||
{
|
||||
@@ -117,6 +120,8 @@ public:
|
||||
nMasterKeyMaxID = 0;
|
||||
pwalletdbEncryption = NULL;
|
||||
nOrderPosNext = 0;
|
||||
nCachedStakeWeight = 0;
|
||||
nCachedStakeWeightTime = 0;
|
||||
}
|
||||
|
||||
std::map<uint256, CWalletTx> mapWallet;
|
||||
@@ -190,6 +195,8 @@ public:
|
||||
int64_t GetImmatureBalance() const;
|
||||
int64_t GetStake() const;
|
||||
int64_t GetNewMint() const;
|
||||
// Get all balances in a single lock acquisition + single pass (avoids 4x lock + 4x iteration)
|
||||
bool GetAllBalances(int64_t& nBalance, int64_t& nStake, int64_t& nUnconfirmed, int64_t& nImmature) const;
|
||||
bool CreateTransaction(const std::vector<std::pair<CScript, int64_t> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl *coinControl=NULL);
|
||||
bool CreateTransaction(CScript scriptPubKey, int64_t nValue, std::string& sNarr, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl *coinControl=NULL);
|
||||
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
|
||||
@@ -197,6 +204,10 @@ public:
|
||||
bool GetStakeWeight(const CKeyStore& keystore, uint64_t& nMinWeight, uint64_t& nMaxWeight, uint64_t& nWeight);
|
||||
bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, int64_t nFees, CTransaction& txNew, CKey& key);
|
||||
|
||||
// Cached staking info - updated by the staking thread, read by the UI thread.
|
||||
std::atomic<uint64_t> nCachedStakeWeight;
|
||||
std::atomic<int64_t> nCachedStakeWeightTime; // GetTime() when last updated
|
||||
|
||||
std::string SendMoney(CScript scriptPubKey, int64_t nValue, std::string& sNarr, CWalletTx& wtxNew, bool fAskFee=false);
|
||||
std::string SendMoneyToDestination(const CTxDestination& address, int64_t nValue, std::string& sNarr, CWalletTx& wtxNew, bool fAskFee=false);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user