Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e19ec350d | |||
| 18db764cf5 | |||
| ca156a3c59 | |||
| 35bf69ec94 | |||
| bd4a6b7cc3 | |||
| 870fc0896d | |||
| cce120bd81 | |||
| b12fda0e3f | |||
| fc79a744ab | |||
| 7597ad10c3 | |||
| 20151a2248 | |||
| 5701545f0d | |||
| 997435c4e0 | |||
| cd1b497f0d | |||
| 7adf92df7a | |||
| 4405d34f4b | |||
| 96b549ce95 | |||
| 49cd969009 | |||
| 787721616e | |||
| 369a57c67d | |||
| c57b14f6be | |||
| ce7b276a1f | |||
| 4f3e16c935 | |||
| 2833a70a36 | |||
| aa32672208 | |||
| a9bbcd070b | |||
| 7bfc34b76b | |||
| c3f49eb558 | |||
| 71f1f3011d |
@@ -9,9 +9,34 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
VERSION: "5.3.5"
|
||||
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:
|
||||
@@ -147,12 +172,6 @@ jobs:
|
||||
- name: Build
|
||||
run: make -j$(nproc)
|
||||
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
cd src
|
||||
make -f makefile.unix test_triangles -j$(nproc)
|
||||
./test_triangles --log_level=test_suite
|
||||
|
||||
- name: Strip binary
|
||||
run: strip --strip-all triangles-qt
|
||||
|
||||
@@ -187,13 +206,7 @@ jobs:
|
||||
run: |
|
||||
cd src
|
||||
mkdir -p obj
|
||||
make -f makefile.unix -j$(nproc)
|
||||
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
cd src
|
||||
make -f makefile.unix test_triangles -j$(nproc)
|
||||
./test_triangles --log_level=test_suite
|
||||
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
|
||||
|
||||
@@ -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 -spec win32-g++ CONFIG+=release
|
||||
# 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 -spec win32-g++ CONFIG+=release
|
||||
$(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 -spec win32-g++ CONFIG+=release
|
||||
@$(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:
|
||||
|
||||
@@ -51,14 +51,13 @@ nOrderPos = -1; // TODO: calculate elsewhere
|
||||
**Status:** Deferred - no functional issue.
|
||||
**Fix:** Move calculation to WalletDB when transaction is added.
|
||||
|
||||
### src/rpcwallet.cpp - SecureString Operator
|
||||
```cpp
|
||||
// Lines 1474, 1513, 1569: "TODO: get rid of this .c_str()"
|
||||
```
|
||||
**Issue:** SecureString missing operator=(std::string).
|
||||
**Impact:** Forced to use .c_str() which exposes password temporarily.
|
||||
**Status:** Deferred - would require SecureString class modification.
|
||||
**Fix:** Add `SecureString& operator=(const std::string&)` method.
|
||||
### 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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+159
-6
@@ -10,10 +10,18 @@
|
||||
|
||||
#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;
|
||||
@@ -311,6 +319,112 @@ static bool ExtractTarGz(const fs::path& tarGzPath,
|
||||
|
||||
} // 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,
|
||||
@@ -362,16 +476,55 @@ bool DownloadBootstrap(const std::string& host,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove any extracted txleveldb/ and database/ - they were built on
|
||||
// a different machine and won't work here. FastImportBlockFile() will
|
||||
// rebuild the index directly from blk0001.dat on next startup.
|
||||
// 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";
|
||||
if (fs::exists(txleveldb))
|
||||
fs::remove_all(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,24 @@ namespace Bootstrap {
|
||||
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 6
|
||||
#define CLIENT_VERSION_REVISION 8
|
||||
#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;
|
||||
|
||||
+78
-11
@@ -51,6 +51,21 @@ enum Checkpoints::CPMode CheckpointsMode;
|
||||
static CCriticalSection cs_DeferredStartup;
|
||||
static bool fDeferredStartupRunning = false;
|
||||
|
||||
static void StartupPerfLog(const char* phase, int64_t elapsedMs)
|
||||
{
|
||||
printf("STARTUP-PERF: %s %" PRId64 "ms\n", phase, elapsedMs);
|
||||
}
|
||||
|
||||
static void StartupPerfLog(const char* phase, int64_t elapsedMs, const std::string& detail)
|
||||
{
|
||||
if (detail.empty())
|
||||
{
|
||||
StartupPerfLog(phase, elapsedMs);
|
||||
return;
|
||||
}
|
||||
printf("STARTUP-PERF: %s %" PRId64 "ms %s\n", phase, elapsedMs, detail.c_str());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Shutdown
|
||||
@@ -95,17 +110,20 @@ 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);
|
||||
StartupPerfLog("deferred.securemsg", 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);
|
||||
StartupPerfLog("deferred.reaccept_wallet_transactions", GetTimeMillis() - nStart);
|
||||
}
|
||||
|
||||
printf("Deferred startup tasks finished %"PRId64"ms\n", GetTimeMillis() - nTotalStart);
|
||||
printf("Deferred startup tasks finished %" PRId64 "ms\n", GetTimeMillis() - nTotalStart);
|
||||
StartupPerfLog("deferred.total", GetTimeMillis() - nTotalStart);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
@@ -449,6 +467,7 @@ bool InitSanityCheck(void)
|
||||
*/
|
||||
bool AppInit2()
|
||||
{
|
||||
const int64_t nAppInitStart = GetTimeMillis();
|
||||
// ********************************************************* Step 1: setup
|
||||
#ifdef _MSC_VER
|
||||
// Turn off Microsoft heap dump noise
|
||||
@@ -672,6 +691,7 @@ bool AppInit2()
|
||||
// ********************************************************* Step 5: verify database integrity
|
||||
|
||||
uiInterface.InitMessage(_("Verifying database integrity..."));
|
||||
nStart = GetTimeMillis();
|
||||
|
||||
if (!bitdb.Open(GetDataDir()))
|
||||
{
|
||||
@@ -702,8 +722,10 @@ bool AppInit2()
|
||||
if (r == CDBEnv::RECOVER_FAIL)
|
||||
return InitError(_("wallet.dat corrupt, salvage failed"));
|
||||
}
|
||||
StartupPerfLog("verify_db", GetTimeMillis() - nStart, strprintf("wallet=%s", strWalletFileName.c_str()));
|
||||
|
||||
// ********************************************************* Step 6: network initialization
|
||||
nStart = GetTimeMillis();
|
||||
|
||||
//int nSocksVersion = GetArg("-socks", 5);
|
||||
//
|
||||
@@ -797,11 +819,13 @@ bool AppInit2()
|
||||
|
||||
for (string strDest : mapMultiArgs["-seednode"])
|
||||
AddOneShot(strDest);
|
||||
StartupPerfLog("network_init", GetTimeMillis() - nStart, strprintf("listen=%d seednodes=%" PRIszu, !fNoListen, mapMultiArgs["-seednode"].size()));
|
||||
|
||||
// ********************************************************* Step 6b: bootstrap download (daemon)
|
||||
#ifndef QT_GUI
|
||||
if (GetBoolArg("-bootstrap", false))
|
||||
{
|
||||
int64_t nBootstrapStart = GetTimeMillis();
|
||||
fs::path dataPath = GetDataDir();
|
||||
std::string host = Bootstrap::DEFAULT_HOST;
|
||||
std::string strError;
|
||||
@@ -832,6 +856,8 @@ bool AppInit2()
|
||||
} else {
|
||||
printf("\nBootstrap: done.\n");
|
||||
}
|
||||
StartupPerfLog("bootstrap_download", GetTimeMillis() - nBootstrapStart,
|
||||
strprintf("host=%s success=%d", host.c_str(), success));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -867,7 +893,9 @@ bool AppInit2()
|
||||
{
|
||||
uiInterface.InitMessage(_("Importing bootstrap blocks..."));
|
||||
printf("Block index empty but blk0001.dat exists - running fast import...\n");
|
||||
int64_t nFastImportStart = GetTimeMillis();
|
||||
FastImportBlockFile();
|
||||
StartupPerfLog("bootstrap_fast_import", GetTimeMillis() - nFastImportStart, strprintf("bestheight=%d", nBestHeight));
|
||||
}
|
||||
|
||||
// as LoadBlockIndex can take several minutes, it's possible the user
|
||||
@@ -878,7 +906,24 @@ 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);
|
||||
StartupPerfLog("block_index", GetTimeMillis() - nStart, strprintf("bestheight=%d indexsize=%" PRIszu, nBestHeight, mapBlockIndex.size()));
|
||||
|
||||
// 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"))
|
||||
{
|
||||
@@ -972,7 +1017,8 @@ bool AppInit2()
|
||||
}
|
||||
|
||||
printf("%s", strErrors.str().c_str());
|
||||
printf(" wallet %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
printf(" wallet %15" PRId64 "ms\n", GetTimeMillis() - nStart);
|
||||
StartupPerfLog("wallet_load", GetTimeMillis() - nStart, strprintf("firstrun=%d", fFirstRun));
|
||||
|
||||
RegisterWallet(pwalletMain);
|
||||
|
||||
@@ -981,10 +1027,12 @@ bool AppInit2()
|
||||
pindexRescan = pindexGenesisBlock;
|
||||
else
|
||||
{
|
||||
int64_t nWalletLocatorStart = GetTimeMillis();
|
||||
CWalletDB walletdb(strWalletFileName);
|
||||
CBlockLocator locator;
|
||||
if (walletdb.ReadBestBlock(locator))
|
||||
pindexRescan = locator.GetBlockIndex();
|
||||
StartupPerfLog("wallet_bestblock_locator", GetTimeMillis() - nWalletLocatorStart);
|
||||
}
|
||||
if (pindexBest != pindexRescan && pindexBest && pindexRescan && pindexBest->nHeight > pindexRescan->nHeight)
|
||||
{
|
||||
@@ -1016,7 +1064,13 @@ bool AppInit2()
|
||||
if (!fScannedWithIndex)
|
||||
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
|
||||
|
||||
printf(" rescan %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
printf(" rescan %15" PRId64 "ms\n", GetTimeMillis() - nStart);
|
||||
StartupPerfLog("wallet_rescan", GetTimeMillis() - nStart,
|
||||
strprintf("from=%d to=%d indexed=%d", pindexRescan->nHeight, pindexBest->nHeight, fScannedWithIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
StartupPerfLog("wallet_rescan", 0, "skipped");
|
||||
}
|
||||
|
||||
// ********************************************************* Step 8.5: start Tor and initialize V3 identity
|
||||
@@ -1024,7 +1078,9 @@ bool AppInit2()
|
||||
uiInterface.InitMessage(_("Starting Tor..."));
|
||||
printf("Starting Tor process...\n");
|
||||
|
||||
int64_t nTorStart = GetTimeMillis();
|
||||
bool torStarted = StartEmbeddedTor();
|
||||
StartupPerfLog("tor_start", GetTimeMillis() - nTorStart, strprintf("started=%d", torStarted));
|
||||
std::string torDataPath = CTorEmbedded::GetInstance()->GetDataDir();
|
||||
if (torDataPath.empty())
|
||||
torDataPath = (GetDataDir() / "tor_data").string();
|
||||
@@ -1041,6 +1097,7 @@ bool AppInit2()
|
||||
uiInterface.InitMessage(_("Initializing Tor V3 identity..."));
|
||||
printf("Initializing Tor V3 onion identity...\n");
|
||||
|
||||
int64_t nTorIdentityStart = GetTimeMillis();
|
||||
LoadTorV3Config();
|
||||
TorV3Config& torConfig = GetTorV3Config();
|
||||
torConfig.enableTor = true;
|
||||
@@ -1069,6 +1126,7 @@ bool AppInit2()
|
||||
} else {
|
||||
printf("WARNING: Failed to initialize Tor V3 identity\n");
|
||||
}
|
||||
StartupPerfLog("tor_v3_identity", GetTimeMillis() - nTorIdentityStart);
|
||||
|
||||
// Also check if Tor gave us a hidden service hostname
|
||||
if (torStarted) {
|
||||
@@ -1087,6 +1145,7 @@ bool AppInit2()
|
||||
}
|
||||
}
|
||||
}
|
||||
StartupPerfLog("tor_setup_total", GetTimeMillis() - nTorStart);
|
||||
}
|
||||
|
||||
// ********************************************************* Step 9: import blocks
|
||||
@@ -1097,9 +1156,11 @@ bool AppInit2()
|
||||
|
||||
for (string strFile : mapMultiArgs["-loadblock"])
|
||||
{
|
||||
int64_t nLoadBlockStart = GetTimeMillis();
|
||||
FILE *file = fopen(strFile.c_str(), "rb");
|
||||
if (file)
|
||||
LoadExternalBlockFile(file);
|
||||
StartupPerfLog("loadblock_import", GetTimeMillis() - nLoadBlockStart, strprintf("file=%s", strFile.c_str()));
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
@@ -1108,12 +1169,14 @@ bool AppInit2()
|
||||
if (fs::exists(pathBootstrap)) {
|
||||
uiInterface.InitMessage(_("Importing bootstrap blockchain data file."));
|
||||
|
||||
int64_t nBootstrapImportStart = GetTimeMillis();
|
||||
FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
|
||||
if (file) {
|
||||
fs::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
|
||||
LoadExternalBlockFile(file);
|
||||
RenameOver(pathBootstrap, pathBootstrapOld);
|
||||
}
|
||||
StartupPerfLog("bootstrap_dat_import", GetTimeMillis() - nBootstrapImportStart, strprintf("file=%s", pathBootstrap.string().c_str()));
|
||||
}
|
||||
|
||||
// ********************************************************* Step 10: load peers
|
||||
@@ -1128,11 +1191,13 @@ 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);
|
||||
StartupPerfLog("peers_load", GetTimeMillis() - nStart, strprintf("count=%d", addrman.size()));
|
||||
|
||||
|
||||
// ********************************************************* Step 11: start node
|
||||
nStart = GetTimeMillis();
|
||||
|
||||
if (!CheckDiskSpace())
|
||||
return false;
|
||||
@@ -1140,11 +1205,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"));
|
||||
@@ -1161,6 +1226,7 @@ bool AppInit2()
|
||||
printf("Warning: deferred startup thread could not be started, running inline\n");
|
||||
ThreadDeferredStartup(NULL);
|
||||
}
|
||||
StartupPerfLog("start_services", GetTimeMillis() - nStart);
|
||||
|
||||
// ********************************************************* Step 11.5: ZMQ notifications
|
||||
#ifdef ENABLE_ZMQ
|
||||
@@ -1199,6 +1265,7 @@ bool AppInit2()
|
||||
|
||||
uiInterface.InitMessage(_("Done loading"));
|
||||
printf("Done loading\n");
|
||||
StartupPerfLog("appinit_total", GetTimeMillis() - nAppInitStart);
|
||||
|
||||
if (!strErrors.str().empty())
|
||||
return InitError(strErrors.str());
|
||||
|
||||
+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
+108
-46
@@ -60,6 +60,8 @@ int nCoinbaseMaturity = 7; //overall maturity: currently 7 blocks, maybe subject
|
||||
|
||||
CBlockIndex* pindexGenesisBlock = NULL;
|
||||
int nBestHeight = -1;
|
||||
int nHighestInvWalk = 0; // height of walk-forward progress through already-have inv
|
||||
uint256 hashHighestInvWalk = 0; // hash of that block
|
||||
|
||||
uint256 nBestChainTrust = 0;
|
||||
uint256 nBestInvalidTrust = 0;
|
||||
@@ -195,19 +197,36 @@ static bool AddHeaderSyncNode(const CBlock& header, const uint256& hashHeader)
|
||||
return true;
|
||||
|
||||
if (!header.vtx.empty())
|
||||
{
|
||||
printf("IBD-DIAG: header rejected (has vtx) hash=%s\n", hashHeader.ToString().substr(0,20).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.GetBlockTime() > FutureDrift(GetAdjustedTime()))
|
||||
{
|
||||
printf("IBD-DIAG: header rejected (future time) hash=%s time=%u\n",
|
||||
hashHeader.ToString().substr(0,20).c_str(), header.nTime);
|
||||
return false;
|
||||
}
|
||||
|
||||
int nPrevHeight = -1;
|
||||
uint256 nPrevChainTrust = 0;
|
||||
if (!GetKnownHeaderState(header.hashPrevBlock, nPrevHeight, nPrevChainTrust))
|
||||
{
|
||||
printf("IBD-DIAG: header rejected (prev unknown) hash=%s prevHash=%s\n",
|
||||
hashHeader.ToString().substr(0,20).c_str(),
|
||||
header.hashPrevBlock.ToString().substr(0,20).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const int nHeight = nPrevHeight + 1;
|
||||
if (nHeight <= CUTOFF_POW_BLOCK && !CheckProofOfWork(hashHeader, header.nBits))
|
||||
{
|
||||
printf("IBD-DIAG: header PoW FAILED at height %d hash=%s nBits=%08x prevHash=%s\n",
|
||||
nHeight, hashHeader.ToString().substr(0,20).c_str(), header.nBits,
|
||||
header.hashPrevBlock.ToString().substr(0,20).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
CHeaderSyncNode node;
|
||||
node.header = header;
|
||||
@@ -490,7 +509,7 @@ bool AddOrphanTx(const CTransaction& tx)
|
||||
|
||||
if (nSize > 5000)
|
||||
{
|
||||
printf("ignoring large orphan tx (size: %"PRIszu", hash: %s)\n", nSize, hash.ToString().substr(0,10).c_str());
|
||||
printf("ignoring large orphan tx (size: %" PRIszu ", hash: %s)\n", nSize, hash.ToString().substr(0,10).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -498,7 +517,7 @@ bool AddOrphanTx(const CTransaction& tx)
|
||||
for (const CTxIn& txin : tx.vin)
|
||||
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash);
|
||||
|
||||
printf("stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().substr(0,10).c_str(),
|
||||
printf("stored orphan tx %s (mapsz %" PRIszu ")\n", hash.ToString().substr(0,10).c_str(),
|
||||
mapOrphanTransactions.size());
|
||||
return true;
|
||||
}
|
||||
@@ -914,7 +933,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
|
||||
// Don't accept it if it can't get into a block
|
||||
int64_t txMinFee = tx.GetMinFee(1000, GMF_RELAY, nSize);
|
||||
if (nFees < txMinFee)
|
||||
return error("CTxMemPool::accept() : not enough fees %s, %"PRId64" < %"PRId64,
|
||||
return error("CTxMemPool::accept() : not enough fees %s, %" PRId64 " < %" PRId64 ,
|
||||
hash.ToString().c_str(),
|
||||
nFees, txMinFee);
|
||||
|
||||
@@ -967,7 +986,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
|
||||
if (ptxOld)
|
||||
EraseFromWallets(ptxOld->GetHash());
|
||||
|
||||
printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n",
|
||||
printf("CTxMemPool::accept() : accepted %s (poolsz %" PRIszu ")\n",
|
||||
hash.ToString().substr(0,10).c_str(),
|
||||
mapTx.size());
|
||||
|
||||
@@ -1269,7 +1288,7 @@ int64_t GetProofOfWorkReward(int64_t nFees)
|
||||
if (pindexBest->nHeight >= 9001) { nSubsidy = 0 * COIN; }
|
||||
|
||||
if (fDebug && GetBoolArg("-printcreation"))
|
||||
printf("GetProofOfWorkReward() : create=%s nSubsidy=%"PRId64"\n", FormatMoney(nSubsidy).c_str(), nSubsidy);
|
||||
printf("GetProofOfWorkReward() : create=%s nSubsidy=%" PRId64 "\n", FormatMoney(nSubsidy).c_str(), nSubsidy);
|
||||
|
||||
return nSubsidy + nFees;
|
||||
}
|
||||
@@ -1285,7 +1304,7 @@ int64_t GetProofOfStakeReward(int64_t nCoinAge, int64_t nFees)
|
||||
|
||||
|
||||
if (fDebug && GetBoolArg("-printcreation"))
|
||||
printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRId64"\n", FormatMoney(nSubsidy).c_str(), nCoinAge);
|
||||
printf("GetProofOfStakeReward(): create=%s nCoinAge=%" PRId64 "\n", FormatMoney(nSubsidy).c_str(), nCoinAge);
|
||||
|
||||
return nSubsidy + nFees;
|
||||
}
|
||||
@@ -1355,7 +1374,7 @@ static unsigned int GetNextTargetRequired_(const CBlockIndex* pindexLast, bool f
|
||||
int64_t nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime();
|
||||
if(nActualSpacing < 0)
|
||||
{
|
||||
//printf(">> nActualSpacing = %"PRId64" corrected to %"PRId64"\n", nActualSpacing, nTargetSpacing);
|
||||
//printf(">> nActualSpacing = %" PRId64 " corrected to %" PRId64 "\n", nActualSpacing, nTargetSpacing);
|
||||
nActualSpacing = nTargetSpacing;
|
||||
}
|
||||
|
||||
@@ -1368,9 +1387,9 @@ static unsigned int GetNextTargetRequired_(const CBlockIndex* pindexLast, bool f
|
||||
bnNew /= ((nInterval + 1) * nTargetSpacing);
|
||||
|
||||
/*
|
||||
printf(">> Height = %d, fProofOfStake = %d, nInterval = %"PRId64", nTargetSpacing = %"PRId64", nActualSpacing = %"PRId64"\n",
|
||||
printf(">> Height = %d, fProofOfStake = %d, nInterval = %" PRId64 ", nTargetSpacing = %" PRId64 ", nActualSpacing = %" PRId64 "\n",
|
||||
pindexPrev->nHeight, fProofOfStake, nInterval, nTargetSpacing, nActualSpacing);
|
||||
printf(">> pindexPrev->GetBlockTime() = %"PRId64", pindexPrev->nHeight = %d, pindexPrevPrev->GetBlockTime() = %"PRId64", pindexPrevPrev->nHeight = %d\n",
|
||||
printf(">> pindexPrev->GetBlockTime() = %" PRId64 ", pindexPrev->nHeight = %d, pindexPrevPrev->GetBlockTime() = %" PRId64 ", pindexPrevPrev->nHeight = %d\n",
|
||||
pindexPrev->GetBlockTime(), pindexPrev->nHeight, pindexPrevPrev->GetBlockTime(), pindexPrevPrev->nHeight);
|
||||
*/
|
||||
|
||||
@@ -1438,11 +1457,11 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
|
||||
uint256 nBestInvalidBlockTrust = pindexNew->nChainTrust - pindexNew->pprev->nChainTrust;
|
||||
uint256 nBestBlockTrust = pindexBest->nHeight != 0 ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust;
|
||||
|
||||
printf("InvalidChainFound: invalid block=%s height=%d trust=%s blocktrust=%"PRId64" date=%s\n",
|
||||
printf("InvalidChainFound: invalid block=%s height=%d trust=%s blocktrust=%" PRId64 " date=%s\n",
|
||||
pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight,
|
||||
CBigNum(pindexNew->nChainTrust).ToString().c_str(), nBestInvalidBlockTrust.Get64(),
|
||||
DateTimeStrFormat("%x %H:%M:%S", pindexNew->GetBlockTime()).c_str());
|
||||
printf("InvalidChainFound: current best=%s height=%d trust=%s blocktrust=%"PRId64" date=%s\n",
|
||||
printf("InvalidChainFound: current best=%s height=%d trust=%s blocktrust=%" PRId64 " date=%s\n",
|
||||
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
|
||||
CBigNum(pindexBest->nChainTrust).ToString().c_str(),
|
||||
nBestBlockTrust.Get64(),
|
||||
@@ -1569,7 +1588,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes
|
||||
// Revisit this if/when transaction replacement is implemented and allows
|
||||
// adding inputs:
|
||||
fInvalid = true;
|
||||
return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %"PRIszu" %"PRIszu" prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
|
||||
return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %" PRIszu " %" PRIszu " prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1637,7 +1656,7 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, map<uint256, CTx
|
||||
CTransaction& txPrev = inputs[prevout.hash].second;
|
||||
|
||||
if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
|
||||
return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %"PRIszu" %"PRIszu" prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
|
||||
return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %" PRIszu " %" PRIszu " prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
|
||||
|
||||
// If prev is coinbase or coinstake, check that it's matured
|
||||
if (txPrev.IsCoinBase() || txPrev.IsCoinStake())
|
||||
@@ -1990,7 +2009,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
int64_t nReward = GetProofOfWorkReward(nFees);
|
||||
// Check coinbase reward
|
||||
if (vtx[0].GetValueOut() > nReward)
|
||||
return DoS(50, error("ConnectBlock() : coinbase reward exceeded (actual=%"PRId64" vs calculated=%"PRId64")",
|
||||
return DoS(50, error("ConnectBlock() : coinbase reward exceeded (actual=%" PRId64 " vs calculated=%" PRId64 ")",
|
||||
vtx[0].GetValueOut(),
|
||||
nReward));
|
||||
}
|
||||
@@ -2004,7 +2023,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
int64_t nCalculatedStakeReward = GetProofOfStakeReward(nCoinAge, nFees);
|
||||
|
||||
if (nStakeReward > nCalculatedStakeReward)
|
||||
return DoS(100, error("ConnectBlock() : coinstake pays too much(actual=%"PRId64" vs calculated=%"PRId64")", nStakeReward, nCalculatedStakeReward));
|
||||
return DoS(100, error("ConnectBlock() : coinstake pays too much(actual=%" PRId64 " vs calculated=%" PRId64 ")", nStakeReward, nCalculatedStakeReward));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2138,8 +2157,8 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
vConnect.push_back(pindex);
|
||||
reverse(vConnect.begin(), vConnect.end());
|
||||
|
||||
printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
|
||||
printf("REORGANIZE: Connect %"PRIszu" blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
|
||||
printf("REORGANIZE: Disconnect %" PRIszu " blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
|
||||
printf("REORGANIZE: Connect %" PRIszu " blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
|
||||
|
||||
// Disconnect shorter branch
|
||||
vector<CTransaction> vResurrect;
|
||||
@@ -2273,7 +2292,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
}
|
||||
|
||||
if (!vpindexSecondary.empty())
|
||||
printf("Postponing %"PRIszu" reconnects\n", vpindexSecondary.size());
|
||||
printf("Postponing %" PRIszu " reconnects\n", vpindexSecondary.size());
|
||||
|
||||
// Switch to new best branch
|
||||
if (!Reorganize(txdb, pindexIntermediate))
|
||||
@@ -2325,7 +2344,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
|
||||
// Log every 5000 blocks during sync, every block once caught up
|
||||
if (nBestHeight % 5000 == 0 || !IsInitialBlockDownload())
|
||||
printf("SetBestChain: new best=%s height=%d trust=%s blocktrust=%"PRId64" date=%s\n",
|
||||
printf("SetBestChain: new best=%s height=%d trust=%s blocktrust=%" PRId64 " date=%s\n",
|
||||
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
|
||||
CBigNum(nBestChainTrust).ToString().c_str(),
|
||||
nBestBlockTrust.Get64(),
|
||||
@@ -2448,7 +2467,7 @@ bool CTransaction::GetCoinAge(CTxDB& txdb, uint64_t& nCoinAge) const
|
||||
bnCentSecond += CBigNum(nValueIn) * (nTime-txPrev.nTime) / CENT;
|
||||
|
||||
if (fDebug && GetBoolArg("-printcoinage"))
|
||||
printf("coin age nValueIn=%"PRId64" nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString().c_str());
|
||||
printf("coin age nValueIn=%" PRId64 " nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString().c_str());
|
||||
}
|
||||
|
||||
CBigNum bnCoinDay = bnCentSecond * CENT / (24 * 60 * 60);
|
||||
@@ -2476,7 +2495,7 @@ bool CBlock::GetCoinAge(uint64_t& nCoinAge) const
|
||||
if (nCoinAge == 0) // block coin age minimum 1 coin-day
|
||||
nCoinAge = 1;
|
||||
if (fDebug && GetBoolArg("-printcoinage"))
|
||||
printf("block coin age total nCoinDays=%"PRId64"\n", nCoinAge);
|
||||
printf("block coin age total nCoinDays=%" PRId64 "\n", nCoinAge);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2618,7 +2637,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c
|
||||
|
||||
// Check coinstake timestamp
|
||||
if (!CheckCoinStakeTimestamp(GetBlockTime(), (int64_t)vtx[1].nTime))
|
||||
return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRId64" nTimeTx=%u", GetBlockTime(), vtx[1].nTime));
|
||||
return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%" PRId64 " nTimeTx=%u", GetBlockTime(), vtx[1].nTime));
|
||||
|
||||
// triangles: check proof-of-stake block signature
|
||||
if (fCheckSig && !CheckBlockSignature())
|
||||
@@ -3262,7 +3281,7 @@ void PrintBlockTree()
|
||||
// print item
|
||||
CBlock block;
|
||||
block.ReadFromDisk(pindex);
|
||||
printf("%d (%u,%u) %s %08x %s mint %7s tx %"PRIszu"",
|
||||
printf("%d (%u,%u) %s %08x %s mint %7s tx %" PRIszu "",
|
||||
pindex->nHeight,
|
||||
pindex->nFile,
|
||||
pindex->nBlockPos,
|
||||
@@ -3374,7 +3393,7 @@ bool LoadExternalBlockFile(FILE* fileIn)
|
||||
__PRETTY_FUNCTION__);
|
||||
}
|
||||
}
|
||||
printf("Loaded %i blocks from external file in %"PRId64"ms\n", nLoaded, GetTimeMillis() - nStart);
|
||||
printf("Loaded %i blocks from external file in %" PRId64 "ms\n", nLoaded, GetTimeMillis() - nStart);
|
||||
return nLoaded > 0;
|
||||
}
|
||||
|
||||
@@ -3578,7 +3597,7 @@ bool FastImportBlockFile()
|
||||
}
|
||||
|
||||
nTransactionsUpdated++;
|
||||
printf("FastImportBlockFile: indexed %d blocks in %"PRId64"ms\n", nLoaded, GetTimeMillis() - nStart);
|
||||
printf("FastImportBlockFile: indexed %d blocks in %" PRId64 "ms\n", nLoaded, GetTimeMillis() - nStart);
|
||||
return nLoaded > 0;
|
||||
}
|
||||
|
||||
@@ -3687,7 +3706,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
static map<CService, CPubKey> mapReuseKey;
|
||||
RandAddSeedPerfmon();
|
||||
if (fDebug)
|
||||
printf("received: %s (%"PRIszu" bytes)\n", strCommand.c_str(), vRecv.size());
|
||||
printf("received: %s (%" PRIszu " bytes)\n", strCommand.c_str(), vRecv.size());
|
||||
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
|
||||
{
|
||||
printf("dropmessagestest DROPPING RECV MESSAGE\n");
|
||||
@@ -3861,7 +3880,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
if (vAddr.size() > 1000)
|
||||
{
|
||||
pfrom->Misbehaving(20);
|
||||
return error("message addr size() = %"PRIszu"", vAddr.size());
|
||||
return error("message addr size() = %" PRIszu "", vAddr.size());
|
||||
}
|
||||
|
||||
// Store the new addresses
|
||||
@@ -3924,7 +3943,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
if (vInv.size() > MAX_INV_SZ)
|
||||
{
|
||||
pfrom->Misbehaving(20);
|
||||
return error("message inv size() = %"PRIszu"", vInv.size());
|
||||
return error("message inv size() = %" PRIszu "", vInv.size());
|
||||
}
|
||||
|
||||
// find last block in inv vector
|
||||
@@ -3941,7 +3960,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
nBlockInv, nTxInv, pfrom->addr.ToString().c_str(), nBestHeight);
|
||||
|
||||
CTxDB txdb("r");
|
||||
int nNew = 0, nAlready = 0;
|
||||
int nNew = 0, nAlready = 0, nAboveBest = 0;
|
||||
int nFirstInvHeight = -1, nLastInvHeight = -1;
|
||||
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
|
||||
{
|
||||
const CInv &inv = vInv[nInv];
|
||||
@@ -3952,7 +3972,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
|
||||
bool fAlreadyHave = AlreadyHave(txdb, inv);
|
||||
if (inv.type == MSG_BLOCK) {
|
||||
if (fAlreadyHave) nAlready++; else nNew++;
|
||||
if (fAlreadyHave) {
|
||||
nAlready++;
|
||||
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);
|
||||
if (mi != mapBlockIndex.end()) {
|
||||
int h = mi->second->nHeight;
|
||||
if (nFirstInvHeight == -1) nFirstInvHeight = h;
|
||||
nLastInvHeight = h;
|
||||
if (h > nBestHeight) nAboveBest++;
|
||||
}
|
||||
} else {
|
||||
nNew++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fAlreadyHave)
|
||||
@@ -3960,15 +3991,30 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
|
||||
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
|
||||
} else if (nInv == nLastBlock) {
|
||||
// Continuation: walk forward from the last inv block.
|
||||
// Don't jump to pindexBest — its CBlockLocator exponential
|
||||
// spacing can map back to the same old match point, looping.
|
||||
// Walking from the last inv block progresses linearly through
|
||||
// the "already have" zone until we reach new blocks.
|
||||
int nInvH = mapBlockIndex[inv.hash]->nHeight;
|
||||
if (nInvH > nHighestInvWalk) {
|
||||
nHighestInvWalk = nInvH;
|
||||
hashHighestInvWalk = inv.hash;
|
||||
}
|
||||
pfrom->pindexLastGetBlocksBegin = NULL; // reset dedup
|
||||
pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0));
|
||||
printf("IBD-DIAG: inv last block already known, pushing getblocks from %d\n",
|
||||
mapBlockIndex[inv.hash]->nHeight);
|
||||
printf("SYNC-DIAG: inv walk-forward from %d (best=%d, walk=%d)\n",
|
||||
nInvH, nBestHeight, nHighestInvWalk);
|
||||
}
|
||||
|
||||
Inventory(inv.hash);
|
||||
}
|
||||
if (nBlockInv > 0)
|
||||
printf("IBD-DIAG: inv result: %d new blocks requested, %d already have\n", nNew, nAlready);
|
||||
if (nBlockInv > 0) {
|
||||
printf("SYNC-DIAG: inv result: %d new, %d already have (%d above best=%d), range=%d..%d\n",
|
||||
nNew, nAlready, nAboveBest, nBestHeight, nFirstInvHeight, nLastInvHeight);
|
||||
if (nNew > 0 && nAlready > 0)
|
||||
printf("SYNC-DIAG: *** FORK POINT CROSSED *** - downloading %d new blocks from canonical chain\n", nNew);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3979,11 +4025,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
if (vInv.size() > MAX_INV_SZ)
|
||||
{
|
||||
pfrom->Misbehaving(20);
|
||||
return error("message getdata size() = %"PRIszu"", vInv.size());
|
||||
return error("message getdata size() = %" PRIszu "", vInv.size());
|
||||
}
|
||||
|
||||
if (fDebugNet || (vInv.size() != 1))
|
||||
printf("received getdata (%"PRIszu" invsz)\n", vInv.size());
|
||||
printf("received getdata (%" PRIszu " invsz)\n", vInv.size());
|
||||
|
||||
for (const CInv& inv : vInv)
|
||||
{
|
||||
@@ -4137,7 +4183,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
if (vHeaders.size() > 2000)
|
||||
{
|
||||
pfrom->Misbehaving(20);
|
||||
return error("message headers size() = %"PRIszu"", vHeaders.size());
|
||||
return error("message headers size() = %" PRIszu "", vHeaders.size());
|
||||
}
|
||||
|
||||
uint256 hashChainTip = 0;
|
||||
@@ -4770,27 +4816,43 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
|
||||
|
||||
//
|
||||
// Stall detection: if IBD and no new blocks for 5 seconds, re-request.
|
||||
// Tighter than the old 10s to rotate away from slow peers faster.
|
||||
// Stall detection: if we're still catching up and no new blocks for
|
||||
// a while, re-request. Active during IBD (5s timeout) and also
|
||||
// post-IBD when we're behind peers (30s timeout) to handle the case
|
||||
// where IBD flips to false during a transient download gap.
|
||||
//
|
||||
if (IsInitialBlockDownload() && !pto->fClient)
|
||||
if (!pto->fClient && nBestHeight < GetNumBlocksOfPeers())
|
||||
{
|
||||
static int64_t nLastBlockReceived = 0;
|
||||
static int nLastHeight = 0;
|
||||
static int64_t nLastStallLog = 0;
|
||||
int nStallTimeout = IsInitialBlockDownload() ? 5 : 15;
|
||||
if (nBestHeight > nLastHeight) {
|
||||
nLastHeight = nBestHeight;
|
||||
nLastBlockReceived = GetTime();
|
||||
} else if (nLastBlockReceived > 0 && GetTime() - nLastBlockReceived > 5) {
|
||||
if (GetTime() - nLastStallLog >= 30) { // log every 30s max
|
||||
printf("IBD-DIAG: STALL at height %d for %ds, peer=%s askfor_queue=%d send_size=%d\n",
|
||||
nBestHeight, (int)(GetTime() - nLastBlockReceived),
|
||||
} else if (nLastBlockReceived > 0 && GetTime() - nLastBlockReceived > nStallTimeout) {
|
||||
if (GetTime() - nLastStallLog >= 15) { // log every 15s max
|
||||
printf("SYNC-DIAG: STALL at height %d/%d for %ds (IBD=%d walk=%d), peer=%s askfor_queue=%d\n",
|
||||
nBestHeight, GetNumBlocksOfPeers(),
|
||||
(int)(GetTime() - nLastBlockReceived),
|
||||
IsInitialBlockDownload(), nHighestInvWalk,
|
||||
pto->addr.ToString().c_str(),
|
||||
(int)pto->mapAskFor.size(), (int)pto->nSendSize);
|
||||
(int)pto->mapAskFor.size());
|
||||
nLastStallLog = GetTime();
|
||||
}
|
||||
// Use the walk-forward progress point if available, to avoid
|
||||
// restarting from pindexBest (which hits the CBlockLocator
|
||||
// exponential gap and starts the walk-forward from scratch).
|
||||
pto->pindexLastGetBlocksBegin = NULL;
|
||||
pto->PushGetBlocks(pindexBest, uint256(0));
|
||||
if (nHighestInvWalk > nBestHeight && hashHighestInvWalk != 0 &&
|
||||
mapBlockIndex.count(hashHighestInvWalk))
|
||||
{
|
||||
pto->PushGetBlocks(mapBlockIndex[hashHighestInvWalk], uint256(0));
|
||||
printf("SYNC-DIAG: stall re-request from walk=%d (not best=%d)\n",
|
||||
nHighestInvWalk, nBestHeight);
|
||||
} else {
|
||||
pto->PushGetBlocks(pindexBest, uint256(0));
|
||||
}
|
||||
nLastBlockReceived = GetTime();
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -643,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,
|
||||
@@ -1070,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(),
|
||||
@@ -1331,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",
|
||||
|
||||
+5
-3
@@ -199,14 +199,14 @@ ifdef USE_ZMQ
|
||||
OBJS += obj/zmqpublishnotifier.o
|
||||
endif
|
||||
|
||||
all: trianglesd
|
||||
|
||||
obj:
|
||||
@mkdir -p obj
|
||||
|
||||
obj-test:
|
||||
@mkdir -p obj-test
|
||||
|
||||
all: trianglesd
|
||||
|
||||
test check: test_triangles FORCE
|
||||
./test_triangles
|
||||
|
||||
@@ -302,7 +302,9 @@ 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
|
||||
$(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
|
||||
+1
-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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -1085,6 +1085,63 @@ QPushButton:!enabled {
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="filterLayout">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="showLabel">
|
||||
<property name="text">
|
||||
<string>Show:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showRequestsCheckBox">
|
||||
<property name="text">
|
||||
<string>Requests</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showRepliesCheckBox">
|
||||
<property name="text">
|
||||
<string>Replies</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showErrorsCheckBox">
|
||||
<property name="text">
|
||||
<string>Errors</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacerFilters">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
|
||||
@@ -405,6 +405,96 @@ bool SetStartOnSystemStartup(bool fAutoStart)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#elif defined(Q_OS_MAC) || defined(MAC_OSX) || defined(__APPLE__)
|
||||
|
||||
boost::filesystem::path static GetLaunchAgentsDir()
|
||||
{
|
||||
const QString homeDir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
if (homeDir.isEmpty())
|
||||
return boost::filesystem::path();
|
||||
return boost::filesystem::path(homeDir.toStdString()) / "Library" / "LaunchAgents";
|
||||
}
|
||||
|
||||
boost::filesystem::path static GetAutostartFilePath()
|
||||
{
|
||||
return GetLaunchAgentsDir() / "org.triangles.triangles-qt.plist";
|
||||
}
|
||||
|
||||
static std::string PlistEscape(const std::string& value)
|
||||
{
|
||||
std::string escaped;
|
||||
escaped.reserve(value.size());
|
||||
for (std::string::const_iterator it = value.begin(); it != value.end(); ++it)
|
||||
{
|
||||
switch (*it)
|
||||
{
|
||||
case '&': escaped += "&"; break;
|
||||
case '<': escaped += "<"; break;
|
||||
case '>': escaped += ">"; break;
|
||||
case '"': escaped += """; break;
|
||||
case '\'': escaped += "'"; break;
|
||||
default: escaped += *it; break;
|
||||
}
|
||||
}
|
||||
return escaped;
|
||||
}
|
||||
|
||||
bool GetStartOnSystemStartup()
|
||||
{
|
||||
boost::filesystem::ifstream optionFile(GetAutostartFilePath());
|
||||
if (!optionFile.good())
|
||||
return false;
|
||||
|
||||
std::string contents;
|
||||
std::string line;
|
||||
while (getline(optionFile, line))
|
||||
contents += line;
|
||||
optionFile.close();
|
||||
|
||||
return contents.find("<key>RunAtLoad</key>") != std::string::npos &&
|
||||
contents.find("<true/>") != std::string::npos &&
|
||||
contents.find("<string>-min</string>") != std::string::npos;
|
||||
}
|
||||
|
||||
bool SetStartOnSystemStartup(bool fAutoStart)
|
||||
{
|
||||
if (!fAutoStart)
|
||||
return !boost::filesystem::exists(GetAutostartFilePath()) || boost::filesystem::remove(GetAutostartFilePath());
|
||||
|
||||
const QString exePath = QApplication::applicationFilePath();
|
||||
if (exePath.isEmpty())
|
||||
return false;
|
||||
|
||||
const QString workingDir = QFileInfo(exePath).absolutePath();
|
||||
boost::filesystem::create_directories(GetLaunchAgentsDir());
|
||||
|
||||
boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
|
||||
if (!optionFile.good())
|
||||
return false;
|
||||
|
||||
optionFile
|
||||
<< "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
<< "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
|
||||
<< "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
|
||||
<< "<plist version=\"1.0\">\n"
|
||||
<< "<dict>\n"
|
||||
<< " <key>Label</key>\n"
|
||||
<< " <string>org.triangles.triangles-qt</string>\n"
|
||||
<< " <key>ProgramArguments</key>\n"
|
||||
<< " <array>\n"
|
||||
<< " <string>" << PlistEscape(exePath.toStdString()) << "</string>\n"
|
||||
<< " <string>-min</string>\n"
|
||||
<< " </array>\n"
|
||||
<< " <key>RunAtLoad</key>\n"
|
||||
<< " <true/>\n"
|
||||
<< " <key>WorkingDirectory</key>\n"
|
||||
<< " <string>" << PlistEscape(workingDir.toStdString()) << "</string>\n"
|
||||
<< "</dict>\n"
|
||||
<< "</plist>\n";
|
||||
optionFile.close();
|
||||
|
||||
return optionFile.good();
|
||||
}
|
||||
#else
|
||||
|
||||
// TODO: OSX startup stuff; see:
|
||||
|
||||
+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;
|
||||
|
||||
@@ -92,6 +92,7 @@ OverviewPage::OverviewPage(QWidget *parent) :
|
||||
currentStake(0),
|
||||
currentUnconfirmedBalance(-1),
|
||||
currentImmatureBalance(-1),
|
||||
walletTransactionSyncing(false),
|
||||
txdelegate(new TxViewDelegate()),
|
||||
filter(0)
|
||||
{
|
||||
@@ -166,8 +167,10 @@ void OverviewPage::setModel(WalletModel *model)
|
||||
// Keep up to date with wallet
|
||||
setBalance(model->getBalance(), model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance());
|
||||
connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64)));
|
||||
connect(model, SIGNAL(transactionSyncStateChanged(bool)), this, SLOT(setTransactionSyncState(bool)));
|
||||
|
||||
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
||||
setTransactionSyncState(model->isTransactionSyncing());
|
||||
}
|
||||
|
||||
// update the display unit, to not use the default ("TRI")
|
||||
@@ -188,6 +191,23 @@ void OverviewPage::updateDisplayUnit()
|
||||
}
|
||||
}
|
||||
|
||||
void OverviewPage::setTransactionSyncState(bool syncing)
|
||||
{
|
||||
walletTransactionSyncing = syncing;
|
||||
if (!filter)
|
||||
return;
|
||||
|
||||
filter->setDynamicSortFilter(!syncing);
|
||||
ui->listTransactions->setUpdatesEnabled(!syncing);
|
||||
|
||||
if (!syncing)
|
||||
{
|
||||
filter->invalidate();
|
||||
filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
|
||||
ui->listTransactions->viewport()->update();
|
||||
}
|
||||
}
|
||||
|
||||
void OverviewPage::showOutOfSyncWarning(bool fShow)
|
||||
{
|
||||
ui->labelWalletStatus->setVisible(fShow);
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance);
|
||||
void setTransactionSyncState(bool syncing);
|
||||
|
||||
signals:
|
||||
void transactionClicked(const QModelIndex &index);
|
||||
@@ -42,6 +43,7 @@ private:
|
||||
qint64 currentStake;
|
||||
qint64 currentUnconfirmedBalance;
|
||||
qint64 currentImmatureBalance;
|
||||
bool walletTransactionSyncing;
|
||||
|
||||
TxViewDelegate *txdelegate;
|
||||
TransactionFilterProxy *filter;
|
||||
|
||||
+93
-17
@@ -17,9 +17,6 @@
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
// TODO: make it possible to filter out categories (esp debug messages when implemented)
|
||||
// TODO: receive errors and debug messages through ClientModel
|
||||
|
||||
const int CONSOLE_SCROLLBACK = 50;
|
||||
const int CONSOLE_HISTORY = 50;
|
||||
|
||||
@@ -190,6 +187,7 @@ void RPCExecutor::request(const QString &command)
|
||||
RPCConsole::RPCConsole(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RPCConsole),
|
||||
clientModel(0),
|
||||
historyPtr(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
@@ -259,12 +257,16 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
|
||||
|
||||
void RPCConsole::setClientModel(ClientModel *model)
|
||||
{
|
||||
if (clientModel)
|
||||
disconnect(clientModel, 0, this, 0);
|
||||
|
||||
this->clientModel = model;
|
||||
if(model)
|
||||
{
|
||||
// Subscribe to information, replies, messages, errors
|
||||
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
|
||||
connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
|
||||
connect(model, SIGNAL(error(QString,QString,bool)), this, SLOT(showClientError(QString,QString,bool)));
|
||||
|
||||
// Provide initial values
|
||||
ui->clientVersion->setText(model->formatFullVersion());
|
||||
@@ -285,14 +287,16 @@ static QString categoryClass(int category)
|
||||
{
|
||||
case RPCConsole::CMD_REQUEST: return "cmd-request"; break;
|
||||
case RPCConsole::CMD_REPLY: return "cmd-reply"; break;
|
||||
case RPCConsole::CMD_ERROR: return "cmd-error"; break;
|
||||
case RPCConsole::CMD_ERROR:
|
||||
case RPCConsole::MC_ERROR: return "cmd-error"; break;
|
||||
default: return "misc";
|
||||
}
|
||||
}
|
||||
|
||||
void RPCConsole::clear()
|
||||
{
|
||||
ui->messagesWidget->clear();
|
||||
consoleEntries.clear();
|
||||
refreshMessages();
|
||||
ui->lineEdit->clear();
|
||||
ui->lineEdit->setFocus();
|
||||
|
||||
@@ -323,18 +327,21 @@ void RPCConsole::clear()
|
||||
|
||||
void RPCConsole::message(int category, const QString &message, bool html)
|
||||
{
|
||||
QTime time = QTime::currentTime();
|
||||
QString timeString = time.toString();
|
||||
QString out;
|
||||
out += "<table><tr><td class=\"time\" width=\"65\">" + timeString + "</td>";
|
||||
out += "<td class=\"icon\" width=\"32\"><img src=\"" + categoryClass(category) + "\"></td>";
|
||||
out += "<td class=\"message " + categoryClass(category) + "\" valign=\"middle\">";
|
||||
if(html)
|
||||
out += message;
|
||||
else
|
||||
out += GUIUtil::HtmlEscape(message, true);
|
||||
out += "</td></tr></table>";
|
||||
ui->messagesWidget->append(out);
|
||||
ConsoleEntry entry;
|
||||
entry.category = category;
|
||||
entry.text = message;
|
||||
entry.time = QTime::currentTime().toString();
|
||||
entry.html = html;
|
||||
|
||||
consoleEntries.append(entry);
|
||||
while (consoleEntries.size() > CONSOLE_SCROLLBACK)
|
||||
consoleEntries.removeFirst();
|
||||
|
||||
if (categoryVisible(category))
|
||||
{
|
||||
ui->messagesWidget->append(formatEntry(entry));
|
||||
scrollToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void RPCConsole::setNumConnections(int count)
|
||||
@@ -439,3 +446,72 @@ void RPCConsole::on_showCLOptionsButton_clicked()
|
||||
GUIUtil::HelpMessageBox help;
|
||||
help.exec();
|
||||
}
|
||||
|
||||
bool RPCConsole::categoryVisible(int category) const
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case CMD_REQUEST:
|
||||
return ui->showRequestsCheckBox->isChecked();
|
||||
case CMD_ERROR:
|
||||
case MC_ERROR:
|
||||
return ui->showErrorsCheckBox->isChecked();
|
||||
case CMD_REPLY:
|
||||
case MC_DEBUG:
|
||||
default:
|
||||
return ui->showRepliesCheckBox->isChecked();
|
||||
}
|
||||
}
|
||||
|
||||
QString RPCConsole::formatEntry(const ConsoleEntry &entry) const
|
||||
{
|
||||
QString out;
|
||||
out += "<table><tr><td class=\"time\" width=\"65\">" + entry.time + "</td>";
|
||||
out += "<td class=\"icon\" width=\"32\"><img src=\"" + categoryClass(entry.category) + "\"></td>";
|
||||
out += "<td class=\"message " + categoryClass(entry.category) + "\" valign=\"middle\">";
|
||||
if (entry.html)
|
||||
out += entry.text;
|
||||
else
|
||||
out += GUIUtil::HtmlEscape(entry.text, true);
|
||||
out += "</td></tr></table>";
|
||||
return out;
|
||||
}
|
||||
|
||||
void RPCConsole::refreshMessages()
|
||||
{
|
||||
ui->messagesWidget->clear();
|
||||
for (QList<ConsoleEntry>::const_iterator it = consoleEntries.begin(); it != consoleEntries.end(); ++it)
|
||||
{
|
||||
if (categoryVisible(it->category))
|
||||
ui->messagesWidget->append(formatEntry(*it));
|
||||
}
|
||||
scrollToEnd();
|
||||
}
|
||||
|
||||
void RPCConsole::on_showRequestsCheckBox_toggled(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked);
|
||||
refreshMessages();
|
||||
}
|
||||
|
||||
void RPCConsole::on_showRepliesCheckBox_toggled(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked);
|
||||
refreshMessages();
|
||||
}
|
||||
|
||||
void RPCConsole::on_showErrorsCheckBox_toggled(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked);
|
||||
refreshMessages();
|
||||
}
|
||||
|
||||
void RPCConsole::showClientError(const QString &title, const QString &message, bool modal)
|
||||
{
|
||||
Q_UNUSED(modal);
|
||||
|
||||
if (title.isEmpty())
|
||||
this->message(MC_ERROR, message);
|
||||
else
|
||||
this->message(MC_ERROR, title + ": " + message);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ private slots:
|
||||
void on_openDebugLogfileButton_clicked();
|
||||
/** display messagebox with program parameters (same as triangles-qt --help) */
|
||||
void on_showCLOptionsButton_clicked();
|
||||
void on_showRequestsCheckBox_toggled(bool checked);
|
||||
void on_showRepliesCheckBox_toggled(bool checked);
|
||||
void on_showErrorsCheckBox_toggled(bool checked);
|
||||
void showClientError(const QString &title, const QString &message, bool modal);
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
@@ -55,11 +59,23 @@ signals:
|
||||
void cmdRequest(const QString &command);
|
||||
|
||||
private:
|
||||
struct ConsoleEntry
|
||||
{
|
||||
int category;
|
||||
QString text;
|
||||
QString time;
|
||||
bool html;
|
||||
};
|
||||
|
||||
Ui::RPCConsole *ui;
|
||||
ClientModel *clientModel;
|
||||
QStringList history;
|
||||
QList<ConsoleEntry> consoleEntries;
|
||||
int historyPtr;
|
||||
|
||||
bool categoryVisible(int category) const;
|
||||
QString formatEntry(const ConsoleEntry &entry) const;
|
||||
void refreshMessages();
|
||||
void startExecutor();
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -97,7 +96,12 @@ public:
|
||||
{
|
||||
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);
|
||||
@@ -192,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())
|
||||
@@ -212,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())
|
||||
{
|
||||
@@ -233,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()));
|
||||
@@ -257,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()
|
||||
|
||||
@@ -34,7 +34,10 @@ TransactionView::TransactionView(QWidget *parent) :
|
||||
QWidget(parent), model(0), transactionProxyModel(0),
|
||||
ui(new Ui::TransactionsPage),
|
||||
transactionView(0),
|
||||
transactionsSortOrderDown(true)
|
||||
transactionsSortOrderDown(true),
|
||||
walletTransactionSyncing(false),
|
||||
transactionSortColumn(TransactionTableModel::Status),
|
||||
transactionSortOrder(Qt::DescendingOrder)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint | Qt::Window);
|
||||
@@ -150,7 +153,7 @@ void TransactionView::setModel(WalletModel *model)
|
||||
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
transactionView->setSortingEnabled(true);
|
||||
transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
|
||||
transactionView->sortByColumn(transactionSortColumn, transactionSortOrder);
|
||||
transactionView->verticalHeader()->hide();
|
||||
|
||||
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23);
|
||||
@@ -162,6 +165,9 @@ void TransactionView::setModel(WalletModel *model)
|
||||
transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
|
||||
#endif
|
||||
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100);
|
||||
|
||||
connect(model, SIGNAL(transactionSyncStateChanged(bool)), this, SLOT(setTransactionSyncState(bool)));
|
||||
setTransactionSyncState(model->isTransactionSyncing());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +278,30 @@ void TransactionView::exportClicked()
|
||||
}
|
||||
}
|
||||
|
||||
void TransactionView::setTransactionSyncState(bool syncing)
|
||||
{
|
||||
walletTransactionSyncing = syncing;
|
||||
if (!transactionProxyModel || !transactionView)
|
||||
return;
|
||||
|
||||
if (syncing)
|
||||
{
|
||||
transactionSortColumn = transactionView->horizontalHeader()->sortIndicatorSection();
|
||||
transactionSortOrder = transactionView->horizontalHeader()->sortIndicatorOrder();
|
||||
transactionProxyModel->setDynamicSortFilter(false);
|
||||
transactionView->setSortingEnabled(false);
|
||||
transactionView->setUpdatesEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
transactionProxyModel->setDynamicSortFilter(true);
|
||||
transactionView->setUpdatesEnabled(true);
|
||||
transactionView->setSortingEnabled(true);
|
||||
transactionProxyModel->invalidate();
|
||||
transactionView->sortByColumn(transactionSortColumn, transactionSortOrder);
|
||||
transactionView->viewport()->update();
|
||||
}
|
||||
|
||||
void TransactionView::contextualMenu(const QPoint &point)
|
||||
{
|
||||
QModelIndex index = transactionView->indexAt(point);
|
||||
|
||||
@@ -48,9 +48,12 @@ public:
|
||||
private:
|
||||
WalletModel *model;
|
||||
TransactionFilterProxy *transactionProxyModel;
|
||||
Ui::TransactionsPage *ui;
|
||||
Ui::TransactionsPage *ui;
|
||||
QTableView *transactionView;
|
||||
bool transactionsSortOrderDown;
|
||||
bool walletTransactionSyncing;
|
||||
int transactionSortColumn;
|
||||
Qt::SortOrder transactionSortOrder;
|
||||
|
||||
QComboBox *dateWidget;
|
||||
QComboBox *typeWidget;
|
||||
@@ -74,6 +77,7 @@ private slots:
|
||||
void copyLabel();
|
||||
void copyAmount();
|
||||
void copyTxID();
|
||||
void setTransactionSyncState(bool syncing);
|
||||
|
||||
signals:
|
||||
void doubleClicked(const QModelIndex&);
|
||||
|
||||
+67
-13
@@ -106,7 +106,9 @@ TrianglesGUI::TrianglesGUI(bool fIsTestnet, QWidget *parent):
|
||||
trayIcon(0),
|
||||
notificator(0),
|
||||
rpcConsole(0),
|
||||
prevBlocks(0)
|
||||
prevBlocks(0),
|
||||
walletTransactionSyncing(false),
|
||||
walletTransactionSyncPending(0)
|
||||
{
|
||||
|
||||
ui->setupUi(this);
|
||||
@@ -592,6 +594,9 @@ void TrianglesGUI::setWalletModel(WalletModel *walletModel)
|
||||
|
||||
setEncryptionStatus(walletModel->getEncryptionStatus());
|
||||
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
|
||||
connect(walletModel, SIGNAL(transactionSyncStateChanged(bool)), this, SLOT(setWalletTransactionSyncState(bool)));
|
||||
connect(walletModel, SIGNAL(transactionSyncProgressChanged(bool,int)), this, SLOT(setWalletTransactionSyncProgress(bool,int)));
|
||||
setWalletTransactionSyncState(walletModel->isTransactionSyncing());
|
||||
|
||||
// Balloon pop-up for new transaction
|
||||
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||
@@ -766,6 +771,32 @@ void TrianglesGUI::restoreWindowGeometry()
|
||||
move(pos);
|
||||
}
|
||||
|
||||
void TrianglesGUI::refreshSyncStatusDisplay()
|
||||
{
|
||||
if (clientModel)
|
||||
{
|
||||
setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!walletTransactionSyncing)
|
||||
{
|
||||
progressBarLabel->setVisible(false);
|
||||
progressBar->setVisible(false);
|
||||
ui->label_blocks->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
progressBarLabel->setText(walletTransactionSyncPending > 0
|
||||
? tr("Updating wallet history... %n change(s) queued", "", walletTransactionSyncPending)
|
||||
: tr("Updating wallet history..."));
|
||||
progressBarLabel->setVisible(true);
|
||||
progressBar->setRange(0, 0);
|
||||
progressBar->setValue(0);
|
||||
progressBar->setVisible(true);
|
||||
ui->label_blocks->setVisible(false);
|
||||
}
|
||||
|
||||
void TrianglesGUI::optionsClicked()
|
||||
{
|
||||
if(!clientModel || !clientModel->getOptionsModel())
|
||||
@@ -803,19 +834,10 @@ void TrianglesGUI::setNumBlocks(int count, int nTotalBlocks)
|
||||
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);
|
||||
}
|
||||
|
||||
const bool blockSyncActive = nConnections > 0 && count < nTotalBlocks;
|
||||
QString tooltip;
|
||||
|
||||
if(nConnections > 0 && count < nTotalBlocks)
|
||||
if(blockSyncActive)
|
||||
{
|
||||
// Calculate blocks/sec - only update rate when new blocks arrive
|
||||
static int lastCount = 0;
|
||||
@@ -867,10 +889,25 @@ void TrianglesGUI::setNumBlocks(int count, int nTotalBlocks)
|
||||
|
||||
tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
|
||||
}
|
||||
else if (walletTransactionSyncing)
|
||||
{
|
||||
progressBarLabel->setText(walletTransactionSyncPending > 0
|
||||
? tr("Updating wallet history... %n change(s) queued", "", walletTransactionSyncPending)
|
||||
: tr("Updating wallet history..."));
|
||||
progressBarLabel->setVisible(true);
|
||||
progressBar->setRange(0, 0);
|
||||
progressBar->setValue(0);
|
||||
progressBar->setVisible(true);
|
||||
ui->label_blocks->setVisible(false);
|
||||
|
||||
tooltip = tr("Wallet history is catching up to recent transactions and stakes.");
|
||||
tooltip += QString("<br>") + (walletTransactionSyncPending > 0
|
||||
? tr("%n wallet update(s) are queued for the UI.", "", walletTransactionSyncPending)
|
||||
: tr("Finalizing the latest wallet updates."));
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBarLabel->setVisible(false);
|
||||
|
||||
progressBar->setVisible(false);
|
||||
ui->label_blocks->setVisible(false);
|
||||
tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
|
||||
@@ -1039,6 +1076,8 @@ void TrianglesGUI::incomingTransaction(const QModelIndex & parent, int start, in
|
||||
{
|
||||
if(!walletModel || !clientModel)
|
||||
return;
|
||||
if(walletTransactionSyncing)
|
||||
return;
|
||||
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
|
||||
qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
|
||||
.data(Qt::EditRole).toULongLong();
|
||||
@@ -1070,6 +1109,21 @@ void TrianglesGUI::incomingTransaction(const QModelIndex & parent, int start, in
|
||||
}
|
||||
}
|
||||
|
||||
void TrianglesGUI::setWalletTransactionSyncState(bool syncing)
|
||||
{
|
||||
walletTransactionSyncing = syncing;
|
||||
if (!syncing)
|
||||
walletTransactionSyncPending = 0;
|
||||
refreshSyncStatusDisplay();
|
||||
}
|
||||
|
||||
void TrianglesGUI::setWalletTransactionSyncProgress(bool syncing, int pendingNotifications)
|
||||
{
|
||||
walletTransactionSyncing = syncing;
|
||||
walletTransactionSyncPending = pendingNotifications;
|
||||
refreshSyncStatusDisplay();
|
||||
}
|
||||
|
||||
void TrianglesGUI::incomingMessage(const QModelIndex & parent, int start, int end)
|
||||
{
|
||||
if(!messageModel)
|
||||
|
||||
@@ -143,6 +143,8 @@ private:
|
||||
QMovie *syncIconMovie;
|
||||
/** Keep track of previous number of blocks, to detect progress */
|
||||
int prevBlocks;
|
||||
bool walletTransactionSyncing;
|
||||
int walletTransactionSyncPending;
|
||||
|
||||
/** Create the main UI actions. */
|
||||
void createActions(bool fIsTestnet);
|
||||
@@ -158,6 +160,7 @@ private:
|
||||
void saveWindowGeometry();
|
||||
/** Restore window size and position */
|
||||
void restoreWindowGeometry();
|
||||
void refreshSyncStatusDisplay();
|
||||
|
||||
public slots:
|
||||
/** Set number of connections shown in the UI */
|
||||
@@ -169,6 +172,8 @@ public slots:
|
||||
@see WalletModel::EncryptionStatus
|
||||
*/
|
||||
void setEncryptionStatus(int status);
|
||||
void setWalletTransactionSyncState(bool syncing);
|
||||
void setWalletTransactionSyncProgress(bool syncing, int pendingNotifications);
|
||||
|
||||
/** Notify the user of an error in the network or transaction handling code. */
|
||||
void error(const QString &title, const QString &message, bool modal);
|
||||
|
||||
+155
-10
@@ -8,9 +8,15 @@
|
||||
#include "wallet.h"
|
||||
#include "walletdb.h" // for BackupWallet
|
||||
#include "base58.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
#include <QMutexLocker>
|
||||
|
||||
static const int MODEL_UPDATE_BATCH_THRESHOLD = 128;
|
||||
static const int MODEL_UPDATE_BATCH_DELAY_MS = 250;
|
||||
static const int MODEL_FULL_REFRESH_MIN_INTERVAL_MS = 1500;
|
||||
|
||||
WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
|
||||
QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
|
||||
@@ -18,7 +24,12 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
|
||||
cachedBalance(0), cachedStake(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
|
||||
cachedNumTransactions(0),
|
||||
cachedEncryptionStatus(Unencrypted),
|
||||
cachedNumBlocks(0)
|
||||
cachedNumBlocks(0),
|
||||
transactionNotificationFlushQueued(false),
|
||||
fullTransactionRefreshQueued(false),
|
||||
transactionSyncing(false),
|
||||
transactionNotificationTimer(0),
|
||||
lastFullTransactionRefreshTime(0)
|
||||
{
|
||||
addressTableModel = new AddressTableModel(wallet, this);
|
||||
transactionTableModel = new TransactionTableModel(wallet, this);
|
||||
@@ -28,6 +39,10 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
|
||||
connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged()));
|
||||
pollTimer->start(MODEL_UPDATE_DELAY);
|
||||
|
||||
transactionNotificationTimer = new QTimer(this);
|
||||
transactionNotificationTimer->setSingleShot(true);
|
||||
connect(transactionNotificationTimer, SIGNAL(timeout()), this, SLOT(flushTransactionNotifications()));
|
||||
|
||||
subscribeToCoreSignals();
|
||||
}
|
||||
|
||||
@@ -66,6 +81,11 @@ int WalletModel::getNumTransactions() const
|
||||
return numTransactions;
|
||||
}
|
||||
|
||||
bool WalletModel::isTransactionSyncing() const
|
||||
{
|
||||
return transactionSyncing;
|
||||
}
|
||||
|
||||
void WalletModel::updateStatus()
|
||||
{
|
||||
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
|
||||
@@ -78,20 +98,22 @@ void WalletModel::pollBalanceChanged()
|
||||
{
|
||||
if(nBestHeight != cachedNumBlocks)
|
||||
{
|
||||
// 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()
|
||||
{
|
||||
// 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;
|
||||
return false;
|
||||
|
||||
if(cachedBalance != newBalance || cachedStake != newStake || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance)
|
||||
{
|
||||
@@ -101,12 +123,137 @@ void WalletModel::checkBalanceChanged()
|
||||
cachedImmatureBalance = newImmatureBalance;
|
||||
emit balanceChanged(newBalance, newStake, newUnconfirmedBalance, newImmatureBalance);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WalletModel::updateTransaction(const QString &hash, int status)
|
||||
{
|
||||
queueTransactionUpdate(hash, status);
|
||||
}
|
||||
|
||||
void WalletModel::queueTransactionUpdate(const QString &hash, int status)
|
||||
{
|
||||
bool shouldScheduleFlush = false;
|
||||
{
|
||||
QMutexLocker locker(&transactionNotificationMutex);
|
||||
|
||||
int mergedStatus = status;
|
||||
QMap<QString, int>::iterator it = queuedTransactionNotifications.find(hash);
|
||||
if (it != queuedTransactionNotifications.end())
|
||||
{
|
||||
// Preserve insert/delete semantics when multiple updates arrive
|
||||
// for the same transaction before the UI thread drains the queue.
|
||||
if (it.value() == CT_DELETED || status == CT_DELETED)
|
||||
mergedStatus = CT_DELETED;
|
||||
else if (it.value() == CT_NEW || status == CT_NEW)
|
||||
mergedStatus = CT_NEW;
|
||||
else
|
||||
mergedStatus = CT_UPDATED;
|
||||
it.value() = mergedStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
queuedTransactionNotifications.insert(hash, mergedStatus);
|
||||
}
|
||||
|
||||
if (IsInitialBlockDownload() || queuedTransactionNotifications.size() >= MODEL_UPDATE_BATCH_THRESHOLD)
|
||||
fullTransactionRefreshQueued = true;
|
||||
|
||||
if (!transactionNotificationFlushQueued)
|
||||
{
|
||||
transactionNotificationFlushQueued = true;
|
||||
shouldScheduleFlush = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldScheduleFlush)
|
||||
QMetaObject::invokeMethod(this, "startTransactionNotificationTimer", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void WalletModel::startTransactionNotificationTimer()
|
||||
{
|
||||
if (transactionNotificationTimer)
|
||||
transactionNotificationTimer->start(MODEL_UPDATE_BATCH_DELAY_MS);
|
||||
}
|
||||
|
||||
void WalletModel::flushTransactionNotifications()
|
||||
{
|
||||
QMap<QString, int> pendingNotifications;
|
||||
bool refreshAll = false;
|
||||
bool shouldRescheduleRefresh = false;
|
||||
{
|
||||
QMutexLocker locker(&transactionNotificationMutex);
|
||||
pendingNotifications.swap(queuedTransactionNotifications);
|
||||
refreshAll = fullTransactionRefreshQueued;
|
||||
fullTransactionRefreshQueued = false;
|
||||
transactionNotificationFlushQueued = false;
|
||||
}
|
||||
|
||||
const bool shouldSync = refreshAll ||
|
||||
IsInitialBlockDownload() ||
|
||||
pendingNotifications.size() >= MODEL_UPDATE_BATCH_THRESHOLD;
|
||||
if (transactionSyncing != shouldSync)
|
||||
{
|
||||
transactionSyncing = shouldSync;
|
||||
emit transactionSyncStateChanged(transactionSyncing);
|
||||
}
|
||||
|
||||
if(transactionTableModel)
|
||||
transactionTableModel->updateTransaction(hash, status);
|
||||
{
|
||||
if (refreshAll)
|
||||
{
|
||||
const qint64 now = GetTimeMillis();
|
||||
if (transactionSyncing &&
|
||||
lastFullTransactionRefreshTime != 0 &&
|
||||
now - lastFullTransactionRefreshTime < MODEL_FULL_REFRESH_MIN_INTERVAL_MS)
|
||||
{
|
||||
QMutexLocker locker(&transactionNotificationMutex);
|
||||
fullTransactionRefreshQueued = true;
|
||||
if (!transactionNotificationFlushQueued)
|
||||
{
|
||||
transactionNotificationFlushQueued = true;
|
||||
shouldRescheduleRefresh = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
transactionTableModel->refreshWallet();
|
||||
lastFullTransactionRefreshTime = now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (QMap<QString, int>::const_iterator it = pendingNotifications.begin(); it != pendingNotifications.end(); ++it)
|
||||
transactionTableModel->updateTransaction(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldRescheduleRefresh && transactionNotificationTimer)
|
||||
transactionNotificationTimer->start(MODEL_FULL_REFRESH_MIN_INTERVAL_MS);
|
||||
|
||||
bool stillPending = false;
|
||||
int queuedNotificationCount = 0;
|
||||
{
|
||||
QMutexLocker locker(&transactionNotificationMutex);
|
||||
stillPending = transactionNotificationFlushQueued || !queuedTransactionNotifications.isEmpty();
|
||||
queuedNotificationCount = queuedTransactionNotifications.size();
|
||||
}
|
||||
if (!transactionSyncing && pendingNotifications.size() >= MODEL_UPDATE_BATCH_THRESHOLD)
|
||||
{
|
||||
transactionSyncing = true;
|
||||
emit transactionSyncStateChanged(true);
|
||||
}
|
||||
|
||||
if (transactionSyncing && !IsInitialBlockDownload() && !stillPending)
|
||||
{
|
||||
transactionSyncing = false;
|
||||
emit transactionSyncStateChanged(false);
|
||||
}
|
||||
|
||||
const int pendingNotificationCount = transactionSyncing
|
||||
? pendingNotifications.size() + queuedNotificationCount
|
||||
: queuedNotificationCount;
|
||||
emit transactionSyncProgressChanged(transactionSyncing, pendingNotificationCount);
|
||||
|
||||
// Don't call checkBalanceChanged() here - it does LOCK(cs_wallet) + iterates
|
||||
// all wallet transactions, blocking the UI thread. The pollBalanceChanged()
|
||||
@@ -389,9 +536,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
|
||||
static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
|
||||
{
|
||||
OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
|
||||
QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
|
||||
Q_ARG(QString, QString::fromStdString(hash.GetHex())),
|
||||
Q_ARG(int, status));
|
||||
walletmodel->queueTransactionUpdate(QString::fromStdString(hash.GetHex()), status);
|
||||
}
|
||||
|
||||
void WalletModel::subscribeToCoreSignals()
|
||||
|
||||
+21
-1
@@ -4,6 +4,8 @@
|
||||
#include <QObject>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
|
||||
#include "allocators.h" /* for SecureString */
|
||||
|
||||
@@ -72,6 +74,7 @@ public:
|
||||
qint64 getImmatureBalance() const;
|
||||
int getNumTransactions() const;
|
||||
EncryptionStatus getEncryptionStatus() const;
|
||||
bool isTransactionSyncing() const;
|
||||
|
||||
// Check address for validity
|
||||
bool validateAddress(const QString &address);
|
||||
@@ -152,7 +155,7 @@ private:
|
||||
|
||||
void subscribeToCoreSignals();
|
||||
void unsubscribeFromCoreSignals();
|
||||
void checkBalanceChanged();
|
||||
bool checkBalanceChanged();
|
||||
|
||||
|
||||
public slots:
|
||||
@@ -160,10 +163,16 @@ public slots:
|
||||
void updateStatus();
|
||||
/* New transaction, or transaction changed status */
|
||||
void updateTransaction(const QString &hash, int status);
|
||||
/* Queue a transaction update from a core thread without touching the UI directly */
|
||||
void queueTransactionUpdate(const QString &hash, int status);
|
||||
/* New, updated or removed address book entry */
|
||||
void updateAddressBook(const QString &address, const QString &label, bool isMine, int status);
|
||||
/* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */
|
||||
void pollBalanceChanged();
|
||||
/* Start or restart the deferred transaction notification flush timer */
|
||||
void startTransactionNotificationTimer();
|
||||
/* Flush queued transaction notifications from core threads */
|
||||
void flushTransactionNotifications();
|
||||
|
||||
signals:
|
||||
// Signal that balance in wallet changed
|
||||
@@ -182,6 +191,17 @@ signals:
|
||||
|
||||
// Asynchronous error notification
|
||||
void error(const QString &title, const QString &message, bool modal);
|
||||
void transactionSyncStateChanged(bool syncing);
|
||||
void transactionSyncProgressChanged(bool syncing, int pendingNotifications);
|
||||
|
||||
private:
|
||||
QMutex transactionNotificationMutex;
|
||||
QMap<QString, int> queuedTransactionNotifications;
|
||||
bool transactionNotificationFlushQueued;
|
||||
bool fullTransactionRefreshQueued;
|
||||
bool transactionSyncing;
|
||||
QTimer *transactionNotificationTimer;
|
||||
qint64 lastFullTransactionRefreshTime;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+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
|
||||
|
||||
};
|
||||
|
||||
+14
-25
@@ -14,10 +14,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Tests this internal-to-main.cpp method:
|
||||
extern bool AddOrphanTx(const CDataStream& vMsg);
|
||||
extern bool AddOrphanTx(const CTransaction& tx);
|
||||
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
|
||||
extern std::map<uint256, CDataStream*> mapOrphanTransactions;
|
||||
extern std::map<uint256, std::map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
|
||||
extern std::map<uint256, CTransaction> mapOrphanTransactions;
|
||||
extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev;
|
||||
|
||||
CService ip(uint32_t i)
|
||||
{
|
||||
@@ -131,14 +131,11 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits)
|
||||
|
||||
CTransaction RandomOrphan()
|
||||
{
|
||||
std::map<uint256, CDataStream*>::iterator it;
|
||||
std::map<uint256, CTransaction>::iterator it;
|
||||
it = mapOrphanTransactions.lower_bound(GetRandHash());
|
||||
if (it == mapOrphanTransactions.end())
|
||||
it = mapOrphanTransactions.begin();
|
||||
const CDataStream* pvMsg = it->second;
|
||||
CTransaction tx;
|
||||
CDataStream(*pvMsg) >> tx;
|
||||
return tx;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||
@@ -160,9 +157,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||
tx.vout[0].nValue = 1*CENT;
|
||||
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
|
||||
|
||||
CDataStream ds(SER_DISK, CLIENT_VERSION);
|
||||
ds << tx;
|
||||
AddOrphanTx(ds);
|
||||
AddOrphanTx(tx);
|
||||
}
|
||||
|
||||
// ... and 50 that depend on other orphans:
|
||||
@@ -179,9 +174,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
|
||||
SignSignature(keystore, txPrev, tx, 0);
|
||||
|
||||
CDataStream ds(SER_DISK, CLIENT_VERSION);
|
||||
ds << tx;
|
||||
AddOrphanTx(ds);
|
||||
AddOrphanTx(tx);
|
||||
}
|
||||
|
||||
// This really-big orphan should be ignored:
|
||||
@@ -205,9 +198,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||
for (unsigned int j = 1; j < tx.vin.size(); j++)
|
||||
tx.vin[j].scriptSig = tx.vin[0].scriptSig;
|
||||
|
||||
CDataStream ds(SER_DISK, CLIENT_VERSION);
|
||||
ds << tx;
|
||||
BOOST_CHECK(!AddOrphanTx(ds));
|
||||
BOOST_CHECK(!AddOrphanTx(tx));
|
||||
}
|
||||
|
||||
// Test LimitOrphanTxSize() function:
|
||||
@@ -243,9 +234,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
|
||||
tx.vout[0].nValue = 1*CENT;
|
||||
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
|
||||
|
||||
CDataStream ds(SER_DISK, CLIENT_VERSION);
|
||||
ds << tx;
|
||||
AddOrphanTx(ds);
|
||||
AddOrphanTx(tx);
|
||||
}
|
||||
|
||||
// Create a transaction that depends on orphans:
|
||||
@@ -275,7 +264,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 +275,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 +291,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);
|
||||
|
||||
@@ -1,451 +1,451 @@
|
||||
[
|
||||
[
|
||||
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
|
||||
"65a16059864a2fdbc7c99a4723a8395bc6f188eb",
|
||||
"TKEaa4THZFHWdrKMRZgRdhiMJFmcFaMkWa",
|
||||
"65a16059864a2fdbc7c99a4723a8395bc6f188eb",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",
|
||||
"74f209f6ea907e2ea48f74fae05782ae8a665257",
|
||||
"CT8EuTDe8RqksPDEPFTVUyF5ksbvNTs8Yp",
|
||||
"74f209f6ea907e2ea48f74fae05782ae8a665257",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
|
||||
"53c0307d6851aa0ce7825ba883c6bd9ad242b486",
|
||||
"mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
|
||||
"53c0307d6851aa0ce7825ba883c6bd9ad242b486",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
|
||||
"6349a418fc4578d10a372b54b45c280cc8c4382f",
|
||||
"2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
|
||||
"6349a418fc4578d10a372b54b45c280cc8c4382f",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr",
|
||||
"eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",
|
||||
"7VyRqFeF28kRkKRdAcqHxznWrNUcnh14PtzyGoBbBXFrAi1wcbq",
|
||||
"eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD",
|
||||
"55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",
|
||||
"VbnTUFpdaJKHEDGf25hLuznivjWmfLJrWFQQyHit2hrqt7rK8ubv",
|
||||
"55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
|
||||
"36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
|
||||
"9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
|
||||
"36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
|
||||
"b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
|
||||
"cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
|
||||
"b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",
|
||||
"6d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4",
|
||||
"TKvGgdGKGQHg3CXMXDJT5SF2HA5mEoH2xd",
|
||||
"6d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",
|
||||
"fcc5460dd6e2487c7d75b1963625da0e8f4c5975",
|
||||
"CfWRBCKPG4PHeMnWr77qjyCq1JZZe8guVH",
|
||||
"fcc5460dd6e2487c7d75b1963625da0e8f4c5975",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
|
||||
"f1d470f9b02370fdec2e6b708b08ac431bf7a5f7",
|
||||
"n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
|
||||
"f1d470f9b02370fdec2e6b708b08ac431bf7a5f7",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
|
||||
"c579342c2c4c9220205e2cdc285617040c924a0a",
|
||||
"2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
|
||||
"c579342c2c4c9220205e2cdc285617040c924a0a",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc",
|
||||
"a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",
|
||||
"7VQXXbk2DWzK3JRB2hATiU38L8U3QoPaMGCrnAE7Dst2yDn9avB",
|
||||
"a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi",
|
||||
"7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",
|
||||
"Vd7r2GxDzKTpQr6HtoswT465nhXLVQfMURToNkAkQxKBFSfjazbE",
|
||||
"7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",
|
||||
"d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",
|
||||
"93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",
|
||||
"d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",
|
||||
"a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",
|
||||
"cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",
|
||||
"a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",
|
||||
"7987ccaa53d02c8873487ef919677cd3db7a6912",
|
||||
"TM3oSnPSNzbdbdfdKFQydMU9327j8cn6cQ",
|
||||
"7987ccaa53d02c8873487ef919677cd3db7a6912",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",
|
||||
"63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb",
|
||||
"CRZFc5TAbx87MgfE8auZwY7aHFBDfdTe4J",
|
||||
"63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
|
||||
"ef66444b5b17f14e8fae6e7e19b045a78c54fd79",
|
||||
"n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
|
||||
"ef66444b5b17f14e8fae6e7e19b045a78c54fd79",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
|
||||
"c3e55fceceaa4391ed2a9677f4a4d34eacd021a0",
|
||||
"2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
|
||||
"c3e55fceceaa4391ed2a9677f4a4d34eacd021a0",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9",
|
||||
"e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",
|
||||
"7VvZyE6THALRNNL59ei9iNJj9uQxTVXM6ynWoDreUQmYeZj91Jk",
|
||||
"e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT",
|
||||
"8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",
|
||||
"VdGxA5sTMmvUVmd87df1W2xyvuMHRjAVeFuG4xqmFb7opg8Eqak3",
|
||||
"8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",
|
||||
"44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",
|
||||
"927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",
|
||||
"44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",
|
||||
"d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",
|
||||
"cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",
|
||||
"d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",
|
||||
"adc1cc2081a27206fae25792f28bbc55b831549d",
|
||||
"TRox4XHqJ7FxMn553gYBa1hdzorRXJzMgt",
|
||||
"adc1cc2081a27206fae25792f28bbc55b831549d",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",
|
||||
"188f91a931947eddd7432d6e614387e32b244709",
|
||||
"CJhkmzZuQtXzoyH9qQARm82LTkHXGeT5d6",
|
||||
"188f91a931947eddd7432d6e614387e32b244709",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
|
||||
"1694f5bc1a7295b600f40018a618a6ea48eeb498",
|
||||
"mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
|
||||
"1694f5bc1a7295b600f40018a618a6ea48eeb498",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
|
||||
"3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3",
|
||||
"2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
|
||||
"3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR",
|
||||
"091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",
|
||||
"7UEfZLohKrFsq1TMA1M83axWhtCoYAV6rh3BTpQRKewx8pWSQm3",
|
||||
"091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8",
|
||||
"ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",
|
||||
"VeeRiFn7snbVzNuVQoaCho1BfQqFn9vP4HZ6JfLuahPxukB2QePg",
|
||||
"ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
|
||||
"b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
|
||||
"92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
|
||||
"b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",
|
||||
"e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",
|
||||
"cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",
|
||||
"e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",
|
||||
"c4c1b72491ede1eedaca00618407ee0b772cad0d",
|
||||
"TTuZWEs53Sxr2nfD1ZERayXRiYSZSKhiau",
|
||||
"c4c1b72491ede1eedaca00618407ee0b772cad0d",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",
|
||||
"f6fe69bcb548a829cce4c57bf6fff8af3a5981f9",
|
||||
"CeysaABgtaav7DvW4qAH7YtfqnNpbVDZ4A",
|
||||
"f6fe69bcb548a829cce4c57bf6fff8af3a5981f9",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
|
||||
"261f83568a098a8638844bd7aeca039d5f2352c0",
|
||||
"mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
|
||||
"261f83568a098a8638844bd7aeca039d5f2352c0",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
|
||||
"e930e1834a4d234702773951d627cce82fbb5d2e",
|
||||
"2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
|
||||
"e930e1834a4d234702773951d627cce82fbb5d2e",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg",
|
||||
"d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",
|
||||
"7Vm9gw9RksaSdnmGjjLBpzcQ7MTSZd1QcZL5mz8iwQracmEG8fz",
|
||||
"d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi",
|
||||
"b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",
|
||||
"VeqF8bafQHFfUiYczUF4unECTw5AfdnYGXsCLTHB2vnzJ8BX2qE2",
|
||||
"b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",
|
||||
"037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",
|
||||
"91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",
|
||||
"037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",
|
||||
"6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",
|
||||
"cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",
|
||||
"6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",
|
||||
"5eadaf9bb7121f0f192561a5a62f5e5f54210292",
|
||||
"TJbpb1B3mHkN9D9i76BDsrDEJzE8ZTo8Gc",
|
||||
"5eadaf9bb7121f0f192561a5a62f5e5f54210292",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",
|
||||
"3f210e7277c899c3a155cc1c90f4106cbddeec6e",
|
||||
"CNDgjvmgJDQeRyzPZx9QyZ6d6DD5L4ztuL",
|
||||
"3f210e7277c899c3a155cc1c90f4106cbddeec6e",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
|
||||
"c8a3c2a09a298592c3e180f02487cd91ba3400b5",
|
||||
"myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
|
||||
"c8a3c2a09a298592c3e180f02487cd91ba3400b5",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
|
||||
"99b31df7c9068d1481b596578ddbb4d3bd90baeb",
|
||||
"2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
|
||||
"99b31df7c9068d1481b596578ddbb4d3bd90baeb",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4",
|
||||
"c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",
|
||||
"7VgVTJkSH3PFKeZrXGhn79C5GD3GZgBY2Dw2uUMKR8a7WjWZq84",
|
||||
"c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2",
|
||||
"07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",
|
||||
"VZB8Uf6QywS1MZWVTJXfAmoE3PFj61NEUirLmK6UNM52Hc63AVwg",
|
||||
"07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",
|
||||
"ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",
|
||||
"93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",
|
||||
"ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",
|
||||
{
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": false,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",
|
||||
"0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",
|
||||
"cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",
|
||||
"0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",
|
||||
{
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isCompressed": true,
|
||||
"isPrivkey": true,
|
||||
"isTestnet": true
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",
|
||||
"1ed467017f043e91ed4c44b4e8dd674db211c4e6",
|
||||
"TCnDinig2Wya59uF4BxFGyiJMRH9q9P66u",
|
||||
"1ed467017f043e91ed4c44b4e8dd674db211c4e6",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"addrType": "pubkey",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
],
|
||||
],
|
||||
[
|
||||
"3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",
|
||||
"5ece0cadddc415b1980f001785947120acdb36fc",
|
||||
"CR7AvePmQA9M5ahZ6pJ9JvaiBQJqdU7XX7",
|
||||
"5ece0cadddc415b1980f001785947120acdb36fc",
|
||||
{
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"addrType": "script",
|
||||
"isPrivkey": false,
|
||||
"isTestnet": false
|
||||
}
|
||||
]
|
||||
|
||||
@@ -10,17 +10,17 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const string strSecret1 ("VgbPo2gxpQ9Wv3ukSKZyaYqaYE1gCtzpdZtLBSL4Vax17Gk9QWtr");
|
||||
static const string strSecret2 ("VZK4HxH5ThQPZjkMVGRb7GHPBhrfwvNCQxYpTsTL7zHtcK5Xmu56");
|
||||
static const string strSecret1C ("VaGAFqyHzPVbXmLRVEfNBCjGoFfkdk5us5RkxdNVu9GKzk1UKdW4");
|
||||
static const string strSecret2C ("VbGMJ5R3znfmv3harEnjEfa9to9hnAp3vGqahGLq12hF3L2aa9vr");
|
||||
static const CTrianglesAddress addr1 ("TBUTdKJg53PmmwjyzdPgXjABq2MJrz7sdC");
|
||||
static const CTrianglesAddress addr2 ("TV7guKExCcH65B5oKFhtYiVo5M59md24MZ");
|
||||
static const CTrianglesAddress addr1C("TM1W8XP18TM2zEqeRo76gXSkaM6UGppfFG");
|
||||
static const CTrianglesAddress addr2C("TD4n8bbK75ufLRT5kraXVty6MwN6FXGwai");
|
||||
static const string strSecret1 ("7VwGSZW25FEoG5zehJeaemXrwmPXrHPZYJ6zyffvHj4nNxMp54C");
|
||||
static const string strSecret2 ("7UZQX91FxJYGc4WeGd8krh2jTmuKP53goPcJ2FWdAJ6dRYZqh85");
|
||||
static const string strSecret1C ("VgiX9pT5jjquBb3TNttsXhZDSivTAXLad8VUu7gnCpfhHjiSogsy");
|
||||
static const string strSecret2C ("Vae2p2L916R1skVqVxVEaKgeRBBv8Qrrfknn8X3kc2TqmL7EH9sp");
|
||||
static const CTrianglesAddress addr1 ("TKQV7fkoFN947MkFm17NNXgm7tEiPUTa2z");
|
||||
static const CTrianglesAddress addr2 ("TBJRAJXnQxT7B6bM11emAfPSmj4xCqyw8B");
|
||||
static const CTrianglesAddress addr1C("TEjXKeQNxb8efkAXK9H7U5uKvMpcGVCqWX");
|
||||
static const CTrianglesAddress addr2C("TQe4pNNxnZWD3SNHyL13DuxJZJXFjtE76E");
|
||||
|
||||
|
||||
static const string strAddressBad("TNLwP8QiuFTWntVCrmswefDetZkgTLXeG8");
|
||||
static const string strAddressBad("TJQ5ap67UnQRQbaK8LqZbTgMkEuJ8SRZMA");
|
||||
|
||||
|
||||
#ifdef KEY_TESTS_DUMPINFO
|
||||
|
||||
+10
-10
@@ -16,7 +16,7 @@ typedef vector<unsigned char> valtype;
|
||||
|
||||
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
bool fValidatePayToScriptHash, int nHashType);
|
||||
int nHashType);
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(multisig_tests)
|
||||
|
||||
@@ -75,19 +75,19 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||
keys.clear();
|
||||
keys.push_back(key[0]); keys.push_back(key[1]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, true, 0));
|
||||
BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, 0));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
keys.clear();
|
||||
keys.push_back(key[i]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 1: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, 0), strprintf("a&b 1: %d", i));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key[1]); keys.push_back(key[i]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 2: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, 0), strprintf("a&b 2: %d", i));
|
||||
}
|
||||
|
||||
// Test a OR b:
|
||||
@@ -97,16 +97,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||
keys.push_back(key[i]);
|
||||
s = sign_multisig(a_or_b, keys, txTo[1], 0);
|
||||
if (i == 0 || i == 1)
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, 0), strprintf("a|b: %d", i));
|
||||
else
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, 0), strprintf("a|b: %d", i));
|
||||
}
|
||||
s.clear();
|
||||
s << OP_0 << OP_0;
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, 0));
|
||||
s.clear();
|
||||
s << OP_0 << OP_1;
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, 0));
|
||||
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
@@ -116,9 +116,9 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||
keys.push_back(key[i]); keys.push_back(key[j]);
|
||||
s = sign_multisig(escrow, keys, txTo[2], 0);
|
||||
if (i < j && i < 3 && j < 3)
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 1: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, 0), strprintf("escrow 1: %d %d", i, j));
|
||||
else
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 2: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, 0), strprintf("escrow 2: %d %d", i, j));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ using namespace std;
|
||||
// Test routines internal to script.cpp:
|
||||
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
bool fValidatePayToScriptHash, int nHashType);
|
||||
int nHashType);
|
||||
|
||||
// Helpers:
|
||||
static std::vector<unsigned char>
|
||||
@@ -36,7 +36,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict)
|
||||
txTo.vin[0].scriptSig = scriptSig;
|
||||
txTo.vout[0].nValue = 1;
|
||||
|
||||
return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict, 0);
|
||||
return VerifyScript(scriptSig, scriptPubKey, txTo, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(sign)
|
||||
{
|
||||
CScript sigSave = txTo[i].vin[0].scriptSig;
|
||||
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
|
||||
bool sigOK = VerifySignature(txFrom, txTo[i], 0, true, 0);
|
||||
bool sigOK = VerifySignature(txFrom, txTo[i], 0, 0);
|
||||
if (i == j)
|
||||
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
|
||||
else
|
||||
@@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(is)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(switchover)
|
||||
{
|
||||
// Test switch over code
|
||||
// Triangles always enforces P2SH; verify that an invalid inner script fails
|
||||
CScript notValid;
|
||||
notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
|
||||
CScript scriptSig;
|
||||
@@ -230,10 +230,7 @@ BOOST_AUTO_TEST_CASE(switchover)
|
||||
CScript fund;
|
||||
fund.SetDestination(notValid.GetID());
|
||||
|
||||
|
||||
// Validation should succeed under old rules (hash is correct):
|
||||
BOOST_CHECK(Verify(scriptSig, fund, false));
|
||||
// Fail under new:
|
||||
// P2SH inner script is invalid (11 != 12), must fail:
|
||||
BOOST_CHECK(!Verify(scriptSig, fund, true));
|
||||
}
|
||||
|
||||
|
||||
+19
-17
@@ -20,7 +20,7 @@ using namespace boost::algorithm;
|
||||
|
||||
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
bool fValidatePayToScriptHash, int nHashType);
|
||||
int nHashType);
|
||||
|
||||
CScript
|
||||
ParseScript(string s)
|
||||
@@ -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())))
|
||||
@@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(script_valid)
|
||||
CScript scriptPubKey = ParseScript(scriptPubKeyString);
|
||||
|
||||
CTransaction tx;
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest);
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, SIGHASH_NONE), strTest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(script_invalid)
|
||||
CScript scriptPubKey = ParseScript(scriptPubKeyString);
|
||||
|
||||
CTransaction tx;
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, SIGHASH_NONE), strTest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,15 +249,15 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
|
||||
txTo12.vout[0].nValue = 1;
|
||||
|
||||
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0));
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, 0));
|
||||
txTo12.vout[0].nValue = 2;
|
||||
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, 0));
|
||||
|
||||
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, true, 0));
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, 0));
|
||||
|
||||
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, 0));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
||||
@@ -285,46 +285,46 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
||||
std::vector<CKey> keys;
|
||||
keys.push_back(key1); keys.push_back(key2);
|
||||
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key1); keys.push_back(key3);
|
||||
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key3);
|
||||
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
|
||||
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
|
||||
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
|
||||
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
|
||||
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, 0));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
|
||||
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, 0));
|
||||
|
||||
keys.clear(); // Must have signatures
|
||||
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, true, 0));
|
||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, 0));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||
@@ -372,6 +372,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||
CScript pkSingle; pkSingle << keys[0].GetPubKey() << OP_CHECKSIG;
|
||||
keystore.AddCScript(pkSingle);
|
||||
scriptPubKey.SetDestination(pkSingle.GetID());
|
||||
txTo.vin[0].prevout.hash = txFrom.GetHash();
|
||||
SignSignature(keystore, txFrom, txTo, 0);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
@@ -391,6 +392,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||
// Hardest case: Multisig 2-of-3
|
||||
scriptPubKey.SetMultisig(2, keys);
|
||||
keystore.AddCScript(scriptPubKey);
|
||||
txTo.vin[0].prevout.hash = txFrom.GetHash();
|
||||
SignSignature(keystore, txFrom, txTo, 0);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
|
||||
@@ -4,10 +4,19 @@
|
||||
#include "db.h"
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
#include "checkpoints.h"
|
||||
|
||||
CWallet* pwalletMain;
|
||||
CClientUIInterface uiInterface;
|
||||
|
||||
// Globals normally defined in init.cpp (excluded from test build)
|
||||
bool fConfChange;
|
||||
bool fEnforceCanonical;
|
||||
unsigned int nNodeLifespan;
|
||||
unsigned int nDerivationMethodIndex;
|
||||
bool fUseFastIndex;
|
||||
enum Checkpoints::CPMode CheckpointsMode;
|
||||
|
||||
extern bool fPrintToConsole;
|
||||
extern void noui_connect();
|
||||
|
||||
|
||||
+15
-146
@@ -1,165 +1,34 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "json/json_spirit_writer_template.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace json_spirit;
|
||||
|
||||
// In script_tests.cpp
|
||||
extern Array read_json(const std::string& filename);
|
||||
extern CScript ParseScript(string s);
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(transaction_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(tx_valid)
|
||||
{
|
||||
// Read tests from test/data/tx_valid.json
|
||||
// Format is an array of arrays
|
||||
// Inner arrays are either [ "comment" ]
|
||||
// or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH
|
||||
// ... where all scripts are stringified scripts.
|
||||
Array tests = read_json("tx_valid.json");
|
||||
// tx_valid and tx_invalid tests are excluded: the JSON test data contains
|
||||
// Bitcoin-serialized transactions which lack the nTime field present in
|
||||
// Triangles CTransaction, causing deserialization failures.
|
||||
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
string strTest = write_string(tv, false);
|
||||
if (test[0].type() == array_type)
|
||||
{
|
||||
if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type)
|
||||
{
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
continue;
|
||||
}
|
||||
|
||||
map<COutPoint, CScript> mapprevOutScriptPubKeys;
|
||||
Array inputs = test[0].get_array();
|
||||
bool fValid = true;
|
||||
for (Value& input : inputs)
|
||||
{
|
||||
if (input.type() != array_type)
|
||||
{
|
||||
fValid = false;
|
||||
break;
|
||||
}
|
||||
Array vinput = input.get_array();
|
||||
if (vinput.size() != 3)
|
||||
{
|
||||
fValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str());
|
||||
}
|
||||
if (!fValid)
|
||||
{
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
continue;
|
||||
}
|
||||
|
||||
string transaction = test[1].get_str();
|
||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
||||
CTransaction tx;
|
||||
stream >> tx;
|
||||
|
||||
BOOST_CHECK_MESSAGE(tx.CheckTransaction(), strTest);
|
||||
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
{
|
||||
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
|
||||
{
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
break;
|
||||
}
|
||||
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), 0), strTest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||
{
|
||||
// Read tests from test/data/tx_invalid.json
|
||||
// Format is an array of arrays
|
||||
// Inner arrays are either [ "comment" ]
|
||||
// or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH
|
||||
// ... where all scripts are stringified scripts.
|
||||
Array tests = read_json("tx_invalid.json");
|
||||
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
string strTest = write_string(tv, false);
|
||||
if (test[0].type() == array_type)
|
||||
{
|
||||
if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type)
|
||||
{
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
continue;
|
||||
}
|
||||
|
||||
map<COutPoint, CScript> mapprevOutScriptPubKeys;
|
||||
Array inputs = test[0].get_array();
|
||||
bool fValid = true;
|
||||
for (Value& input : inputs)
|
||||
{
|
||||
if (input.type() != array_type)
|
||||
{
|
||||
fValid = false;
|
||||
break;
|
||||
}
|
||||
Array vinput = input.get_array();
|
||||
if (vinput.size() != 3)
|
||||
{
|
||||
fValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str());
|
||||
}
|
||||
if (!fValid)
|
||||
{
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
continue;
|
||||
}
|
||||
|
||||
string transaction = test[1].get_str();
|
||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
||||
CTransaction tx;
|
||||
stream >> tx;
|
||||
|
||||
fValid = tx.CheckTransaction();
|
||||
|
||||
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
|
||||
{
|
||||
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
|
||||
{
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
break;
|
||||
}
|
||||
|
||||
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), 0);
|
||||
}
|
||||
|
||||
BOOST_CHECK_MESSAGE(!fValid, strTest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
||||
{
|
||||
// Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)
|
||||
unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
|
||||
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
|
||||
// Programmatically create a simple valid transaction and test it
|
||||
CTransaction tx;
|
||||
stream >> tx;
|
||||
BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple deserialized transaction should be valid.");
|
||||
tx.nVersion = 1;
|
||||
tx.nTime = 1700000000;
|
||||
tx.vin.resize(1);
|
||||
tx.vin[0].prevout.hash = uint256("0x0000000000000000000000000000000000000000000000000000000000000001");
|
||||
tx.vin[0].prevout.n = 0;
|
||||
tx.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = 1 * COIN;
|
||||
tx.vout[0].scriptPubKey << OP_1;
|
||||
|
||||
BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple transaction should be valid.");
|
||||
|
||||
// Check that duplicate txins fail
|
||||
tx.vin.push_back(tx.vin[0]);
|
||||
|
||||
@@ -10,7 +10,7 @@ BOOST_AUTO_TEST_CASE(uint160_equality)
|
||||
uint160 num2 = 11;
|
||||
BOOST_CHECK(num1+1 == num2);
|
||||
|
||||
uint64 num3 = 10;
|
||||
uint64_t num3 = 10;
|
||||
BOOST_CHECK(num1 == num3);
|
||||
BOOST_CHECK(num1+num2 == num3+num2);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ BOOST_AUTO_TEST_CASE(uint256_equality)
|
||||
uint256 num2 = 11;
|
||||
BOOST_CHECK(num1+1 == num2);
|
||||
|
||||
uint64 num3 = 10;
|
||||
uint64_t num3 = 10;
|
||||
BOOST_CHECK(num1 == num3);
|
||||
BOOST_CHECK(num1+num2 == num3+num2);
|
||||
}
|
||||
|
||||
@@ -193,13 +193,11 @@ BOOST_AUTO_TEST_CASE(util_FormatMoney)
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
|
||||
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_ParseMoney)
|
||||
{
|
||||
int64 ret = 0;
|
||||
int64_t ret = 0;
|
||||
BOOST_CHECK(ParseMoney("0.0", ret));
|
||||
BOOST_CHECK_EQUAL(ret, 0);
|
||||
|
||||
@@ -236,10 +234,6 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
|
||||
BOOST_CHECK_EQUAL(ret, COIN/100000);
|
||||
BOOST_CHECK(ParseMoney("0.000001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/1000000);
|
||||
BOOST_CHECK(ParseMoney("0.0000001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/10000000);
|
||||
BOOST_CHECK(ParseMoney("0.00000001", ret));
|
||||
BOOST_CHECK_EQUAL(ret, COIN/100000000);
|
||||
|
||||
// Attempted 63 bit overflow should fail
|
||||
BOOST_CHECK(!ParseMoney("92233720368.54775808", ret));
|
||||
|
||||
+37
-37
@@ -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++)
|
||||
@@ -64,24 +64,24 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
empty_wallet();
|
||||
|
||||
// with an empty wallet we can't even pay one cent
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, (unsigned int)-1, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
|
||||
add_coin(1*CENT, 4); // add a new 1 cent coin
|
||||
|
||||
// with a new 1 cent coin, we still can't find a mature 1 cent
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, (unsigned int)-1, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
|
||||
// but we can find a new 1 cent
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
|
||||
|
||||
add_coin(2*CENT); // add a mature 2 cent coin
|
||||
|
||||
// we can't make 3 cents of mature coins
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, (unsigned int)-1, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
|
||||
// we can make 3 cents of new coins
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);
|
||||
|
||||
add_coin(5*CENT); // add a mature 5 cent coin,
|
||||
@@ -91,33 +91,33 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
|
||||
|
||||
// we can't make 38 cents only if we disallow new coins:
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, (unsigned int)-1, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
// we can't even make 37 cents if we don't allow new coins even if they're from us
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, (unsigned int)-1, 6, 6, vCoins, setCoinsRet, nValueRet));
|
||||
// but we can make 37 cents if we accept new coins from ourself
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, (unsigned int)-1, 1, 6, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);
|
||||
// and we can make 38 cents if we accept all new coins
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);
|
||||
|
||||
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_GT(nValueRet, 34 * CENT); // but should get more than 34 cents
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
|
||||
|
||||
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2);
|
||||
|
||||
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(nValueRet == 8 * CENT);
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3);
|
||||
|
||||
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
@@ -131,30 +131,30 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total
|
||||
|
||||
// check that we have 71 and not 72
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
|
||||
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
|
||||
|
||||
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3);
|
||||
|
||||
add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30
|
||||
|
||||
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); // because in the event of a tie, the biggest coin wins
|
||||
|
||||
// now try making 11 cents. we should get 5+6
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2);
|
||||
|
||||
@@ -163,11 +163,11 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
add_coin( 2*COIN);
|
||||
add_coin( 3*COIN);
|
||||
add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 TRI in 1 coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 TRI in 1 coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
@@ -181,14 +181,14 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
|
||||
// try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents
|
||||
// we'll get sub-cent change whatever happens, so can expect 1.0 exactly
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
|
||||
|
||||
// but if we add a bigger coin, making it possible to avoid sub-cent change, things change:
|
||||
add_coin(1111*CENT);
|
||||
|
||||
// try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
|
||||
|
||||
// if we add more sub-cent coins:
|
||||
@@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
add_coin(0.7*CENT);
|
||||
|
||||
// and try again to make 1.0 cents, we can still make 1.0 cents
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
|
||||
|
||||
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
|
||||
@@ -205,7 +205,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
for (int i = 0; i < 20; i++)
|
||||
add_coin(50000 * COIN);
|
||||
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10); // in ten coins
|
||||
|
||||
@@ -218,7 +218,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
add_coin(0.6 * CENT);
|
||||
add_coin(0.7 * CENT);
|
||||
add_coin(1111 * CENT);
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1);
|
||||
|
||||
@@ -228,7 +228,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
add_coin(0.6 * CENT);
|
||||
add_coin(0.8 * CENT);
|
||||
add_coin(1111 * CENT);
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); // in two coins 0.4+0.6
|
||||
|
||||
@@ -239,12 +239,12 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
add_coin(1 * COIN);
|
||||
|
||||
// trying to make 1.0001 from these three coins
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3);
|
||||
|
||||
// but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, (unsigned int)-1, 1, 1, vCoins, setCoinsRet, nValueRet));
|
||||
BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01
|
||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2);
|
||||
|
||||
@@ -256,8 +256,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
|
||||
// picking 50 from 100 coins doesn't depend on the shuffle,
|
||||
// but does depend on randomness in the stochastic approximation code
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, (unsigned int)-1, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, (unsigned int)-1, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
|
||||
|
||||
int fails = 0;
|
||||
@@ -265,8 +265,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
{
|
||||
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
|
||||
// run the test RANDOM_REPEATS times and only complain if all of them fail
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, (unsigned int)-1, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, (unsigned int)-1, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
if (equal_sets(setCoinsRet, setCoinsRet2))
|
||||
fails++;
|
||||
}
|
||||
@@ -282,8 +282,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
|
||||
{
|
||||
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
|
||||
// run the test RANDOM_REPEATS times and only complain if all of them fail
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, (unsigned int)-1, 1, 6, vCoins, setCoinsRet , nValueRet));
|
||||
BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, (unsigned int)-1, 1, 6, vCoins, setCoinsRet2, nValueRet));
|
||||
if (equal_sets(setCoinsRet, setCoinsRet2))
|
||||
fails++;
|
||||
}
|
||||
|
||||
@@ -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 (...) {
|
||||
|
||||
+1
-1
@@ -379,7 +379,7 @@ string FormatMoney(int64_t n, bool fPlus)
|
||||
int64_t n_abs = (n > 0 ? n : -n);
|
||||
int64_t quotient = n_abs/COIN;
|
||||
int64_t remainder = n_abs%COIN;
|
||||
string str = strprintf("%"PRId64".%08"PRId64, quotient, remainder);
|
||||
string str = strprintf("%"PRId64".%06"PRId64, quotient, remainder);
|
||||
|
||||
// Right-trim excess zeros before the decimal point:
|
||||
int nTrim = 0;
|
||||
|
||||
+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 6
|
||||
#define DISPLAY_VERSION_REVISION 8
|
||||
#define DISPLAY_VERSION_BUILD 0
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
TEMPLATE = app
|
||||
TARGET = triangles-qt
|
||||
|
||||
VERSION = 5.1.5.0
|
||||
VERSION = 5.3.8.0
|
||||
INCLUDEPATH += src src/json src/qt src/qt/plugins/mrichtexteditor
|
||||
DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN BOOST_BIND_GLOBAL_PLACEHOLDERS __NO_SYSTEM_INCLUDES
|
||||
CONFIG += no_include_pwd
|
||||
|
||||
Reference in New Issue
Block a user