chore: clean up .gitignore and remove tracked files that should not be in the repo
Removed from tracking: - Release binaries and tarballs (releases/, bal-server-0.2.2-*) - Environment files with secrets (bal-server.env) - Service files (bitcoind.service, tbitcoind.service) - Test data (invalid_txs, valid_txs, test) - Utility scripts (sendtx.sh, lib.sh, generate_random_ascii.sh, etc.) - Archive (contrib.tar.gz) - Scratch files (update, update_codebase.txt, src/xpub.rs2) NOTE: The .env file with Gitea token was never tracked (already in .gitignore). Private keys (chiave_privata.key, ec.key, private_key.pem, privkey.pem) were also never tracked. Rotate the Gitea token if it was ever shared.
This commit is contained in:
70
.gitignore
vendored
70
.gitignore
vendored
@@ -1,39 +1,49 @@
|
||||
.gitsecret/keys/random_seed
|
||||
!*.secret
|
||||
|
||||
# Environment files - NEVER commit tokens or secrets
|
||||
*.env
|
||||
# Secrets and environment files - NEVER commit
|
||||
.env
|
||||
.env.local
|
||||
.env.production
|
||||
.env.secret
|
||||
|
||||
|
||||
# Private keys - NEVER commit to git
|
||||
# Only public_key.pem should be tracked (if needed)
|
||||
.env.*
|
||||
!.env.example
|
||||
*.pem
|
||||
!public_key.pem
|
||||
data/*.pem
|
||||
!data/public_key.pem
|
||||
*.key
|
||||
!*.secret
|
||||
private_key.pem
|
||||
privkey.pem
|
||||
ec.key
|
||||
chiave_privata.key
|
||||
|
||||
# Other sensitive files
|
||||
bal.db
|
||||
.bal.db
|
||||
download_bal_db.sh
|
||||
# Databases
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
|
||||
# IDE files
|
||||
*.swp
|
||||
*.swo
|
||||
# Rust build artifacts
|
||||
/target
|
||||
Cargo.lock
|
||||
!lib/
|
||||
!contrib/
|
||||
!src/
|
||||
|
||||
# Release artifacts
|
||||
/releases/
|
||||
*.tar.gz
|
||||
*.tar.gz.asc
|
||||
*.tar.gz.sig
|
||||
*.tar.gz.sha256
|
||||
bal-server-*/
|
||||
|
||||
# Deployment configs (keep in deploy scripts, not in repo)
|
||||
bal-server.env
|
||||
bal-pusher.env
|
||||
bitcoind.service
|
||||
tbitcoind.service
|
||||
|
||||
# Test data and scratch files
|
||||
invalid_txs
|
||||
valid_txs
|
||||
test
|
||||
update
|
||||
update_codebase.txt
|
||||
|
||||
# Utility scripts (keep local, not in repo)
|
||||
sendtx.sh
|
||||
lib.sh
|
||||
generate_random_ascii.sh
|
||||
start_postgres_docker.sh
|
||||
make_release.sh
|
||||
download_bal_db.sh
|
||||
|
||||
# Misc
|
||||
*.swp
|
||||
*.swo
|
||||
src/xpub.rs2
|
||||
|
||||
Binary file not shown.
@@ -1,85 +0,0 @@
|
||||
# bal-server
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
$ git clone ....
|
||||
$ cd bal-server
|
||||
$ openssl genpkey -algorithm ED25519 -out private_key.pem
|
||||
$ openssl pkey -in private_key.pem -pubout -out public_key.pem
|
||||
$ cargo build --release
|
||||
$ sudo cp target/release/bal-server /usr/local/bin
|
||||
$ bal-server
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The `bal-server` application can be configured using environment variables. The following variables are available:
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_CONFIG_FILE` | Path to the configuration file. If the file does not exist, a new one will be created. | `$HOME/.config/bal-server/default-config.toml` |
|
||||
| `BAL_SERVER_DB_FILE` | Path to the SQLite3 database file. If the file does not exist, a new one will be created. | `bal.db` |
|
||||
| `BAL_SERVER_BIND_ADDRESS` | Public address for listening to requests. | `127.0.0.1` |
|
||||
| `BAL_SERVER_BIND_PORT` | Default port for listening to requests. | `9137` |
|
||||
| `BAL_SERVER_PUB_KEY_PATH` | WillExecutor Ed25519 public key | `public_key.pem` |
|
||||
| `BAL_SERVER_REGTEST_ADDRESS` | Bitcoin address for the regtest environment. | - |
|
||||
| `BAL_SERVER_REGTEST_FIXED_FEE` | Fixed fee for the regtest environment. | 50000 |
|
||||
| `BAL_SERVER_SIGNET_ADDRESS` | Bitcoin address for the signet environment. | - |
|
||||
| `BAL_SERVER_SIGNET_FIXED_FEE` | Fixed fee for the signet environment. | 50000 |
|
||||
| `BAL_SERVER_TESTNET_ADDRESS` | Bitcoin address for the testnet environment. | - |
|
||||
| `BAL_SERVER_TESTNET_FIXED_FEE` | Fixed fee for the testnet environment. | 50000 |
|
||||
| `BAL_SERVER_BITCOIN_ADDRESS` | Bitcoin address for the mainnet environment. | - |
|
||||
| `BAL_SERVER_BITCOIN_FIXED_FEE` | Fixed fee for the mainnet environment. | 50000 |
|
||||
|
||||
|
||||
# bal-pusher
|
||||
|
||||
`bal-pusher` is a tool that retrieves Bitcoin transactions from a database and pushes them to the Bitcoin network when their **locktime** exceeds the **median time past** (MTP). It listens for Bitcoin block updates via ZMQ.
|
||||
|
||||
## Installation
|
||||
|
||||
To use `bal-pusher`, you need to compile and install Bitcoin with ZMQ (ZeroMQ) support enabled. Then, configure your Bitcoin node and `bal-pusher` to push the transactions.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Bitcoin with ZMQ Support**:
|
||||
Ensure that Bitcoin is compiled with ZMQ support. Add the following line to your `bitcoin.conf` file:
|
||||
|
||||
```
|
||||
zmqpubhashblock=tcp://127.0.0.1:28332
|
||||
```
|
||||
|
||||
2. **Install Rust and Cargo**:
|
||||
If you haven't already installed Rust and Cargo, you can follow the official instructions to do so: [Rust Installation](https://www.rust-lang.org/tools/install).
|
||||
|
||||
## Configuration
|
||||
|
||||
`bal-pusher` can be configured using environment variables. If no configuration file is provided, a default configuration file will be created.
|
||||
|
||||
### Available Configuration Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|---------------------------------------|------------------------------------------|----------------------------------------------|
|
||||
| `BAL_PUSHER_CONFIG_FILE` | Path to the configuration file. If the file does not exist, it will be created. | `$HOME/.config/bal-pusher/default-config.toml` |
|
||||
| `BAL_PUSHER_DB_FILE` | Path to the SQLite3 database file. If the file does not exist, it will be created. | `bal.db` |
|
||||
| `BAL_PUSHER_ZMQ_LISTENER` | ZMQ listener for Bitcoin updates. | `tcp://127.0.0.1:28332` |
|
||||
| `BAL_PUSHER_BITCOIN_HOST` | Bitcoin server host for RPC connections. | `http://127.0.0.1` |
|
||||
| `BAL_PUSHER_BITCOIN_PORT` | Bitcoin RPC server port. | `8332` |
|
||||
| `BAL_PUSHER_BITCOIN_COOKIE_FILE` | Path to Bitcoin RPC cookie file. | `$HOME/.bitcoin/.cookie` |
|
||||
| `BAL_PUSHER_BITCOIN_RPC_USER` | Bitcoin RPC username. | - |
|
||||
| `BAL_PUSHER_BITCOIN_RPC_PASSWORD` | Bitcoin RPC password. | - |
|
||||
| `BAL_PUSHER_SEND_STATS` | Contact welist to provide times | false |
|
||||
| `WELIST_SERVER_URL` | welist server url to provide times | https://welist.bitcoin-afer.life |
|
||||
| `BAL_SERVER_URL` | WillExecutor server url | - |
|
||||
| `SSL_KEY_PATH` | Ed25519 private key pem file | `private_key.pem` |
|
||||
|
||||
|
||||
## Running `bal-pusher`
|
||||
|
||||
Once the application is installed and configured, you can start `bal-pusher` by running the following command:
|
||||
|
||||
```bash
|
||||
$ bal-pusher
|
||||
```
|
||||
|
||||
This will start the service, which will listen for Bitcoin blocks via ZMQ and push transactions from the database when their locktime exceeds the median time past.
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,25 +0,0 @@
|
||||
WORKING_DIR=$(pwd)
|
||||
if [ ! -f "$WORKING_DIR/public_key.pem" ]; then
|
||||
echo "creating keypairs"
|
||||
openssl genpkey -algorithm ED25519 -out private_key.pem
|
||||
openssl pkey -in private_key.pem -pubout -out public_key.pem
|
||||
fi
|
||||
|
||||
export RUST_LOG="trace"
|
||||
export BAL_SERVER_DB_FILE="$WORKING_DIR/bal.db"
|
||||
export BAL_SERVER_INFO="BAL devel willexecutor server"
|
||||
export BAL_SERVER_BIND_ADDRESS="127.0.0.1"
|
||||
export BAL_SERVER_BIND_PORT=9133
|
||||
export BAL_SERVER_PUB_KEY_PATH="$WORKING_DIR/public_key.pem"
|
||||
export BAL_SERVER_EXPOSE_STATS=true;
|
||||
|
||||
#export BAL_SERVER_BITCOIN_ADDRESS="your bitcoin address or xpub to recive payments here"
|
||||
#export BAL_SERVER_BITCOIN_FIXED_FEE=50000
|
||||
|
||||
export BAL_SERVER_REGTEST_ADDRESS="vpub5UhLrYG1qQjnJhvJgBdqgpznyH11mxW9hwBYxf3KhfdjiupCFPUVDvgwpeZ9Wj5YUJXjKjXjy7DSbJNBW1sXbKwARiaphm1UjHYy3mKvTG4"
|
||||
export BAL_SERVER_REGTEST_FIXED_FEE=1000
|
||||
#export BAL_SERVER_TESTNET_ADDRESS=
|
||||
#export BAL_SERVER_TESTNET_FEE=100000
|
||||
#export BAL_SERVER_SIGNET_ADDRESS=
|
||||
#export BAL_SERVER_SIGNET_FEE=100000
|
||||
./bal-server
|
||||
@@ -1,3 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAklkvdmBJSncODyKwkGuEqxqbd3y+gb3X73EPx+0QAZY=
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -1,30 +0,0 @@
|
||||
RUST_LOG=info
|
||||
BAL_SERVER_DB_FILE="/home/bal/bal.db"
|
||||
BAL_SERVER_INFO="BAL server test willexecutor"
|
||||
# !!! WARNING: Never bind to 0.0.0.0 in production. Use 127.0.0.1 and place Nginx with TLS in front.
|
||||
BAL_SERVER_BIND_ADDRESS=127.0.0.1
|
||||
BAL_SERVER_BIND_PORT=9133
|
||||
BAL_SERVER_BITCOIN_ADDRESS="your bitcoin or xpub to recive payments here"
|
||||
BAL_SERVER_BITCOIN_FIXED_FEE=50000
|
||||
BAL_SERVER_PUB_KEY_PATH="/home/bal/public_key.pem"
|
||||
|
||||
BAL_SERVER_REGTEST_ADDRESS="vpub5UhLrYG1qQjnJhvJgBdqgpznyH11mxW9hwBYxf3KhfdjiupCFPUVDvgwpeZ9Wj5YUJXjKjXjy7DSbJNBW1sXbKwARiaphm1UjHYy3mKvTG4"
|
||||
BAL_SERVER_REGTEST_FEE=5000
|
||||
#BAL_SERVER_TESTNET_ADDRESS=
|
||||
#BAL_SERVER_TESTNET_FEE=100000
|
||||
#BAL_SERVER_SIGNET_ADDRESS=
|
||||
#BAL_SERVER_SIGNET_FEE=100000
|
||||
|
||||
# Actix Web DoS Protection Settings (added with migration to Actix Web)
|
||||
BAL_SERVER_ACTIX_MAX_BODY_SIZE=1048576
|
||||
BAL_SERVER_ACTIX_TIMEOUT_SECS=5
|
||||
BAL_SERVER_ACTIX_PUSHTXS_PER_SEC=1
|
||||
BAL_SERVER_ACTIX_PUSHTXS_BURST=3
|
||||
BAL_SERVER_ACTIX_SEARCHTX_PER_SEC=5
|
||||
BAL_SERVER_ACTIX_SEARCHTX_BURST=10
|
||||
BAL_SERVER_ACTIX_INFO_PER_SEC=20
|
||||
BAL_SERVER_ACTIX_INFO_BURST=30
|
||||
BAL_SERVER_ACTIX_DEFAULT_PER_SEC=50
|
||||
BAL_SERVER_ACTIX_DEFAULT_BURST=100
|
||||
BAL_SERVER_ACTIX_WORKERS=4
|
||||
BAL_SERVER_ACTIX_MAX_CONNECTIONS=100
|
||||
@@ -1,55 +0,0 @@
|
||||
# /etc/systemd/system/bitcoind.service
|
||||
|
||||
[Unit]
|
||||
Description=Bitcoin daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
|
||||
# Service execution
|
||||
###################
|
||||
|
||||
ExecStart=/usr/local/bin/bitcoind -daemon \
|
||||
-pid=/run/bitcoind/bitcoind.pid \
|
||||
-conf=/home/bitcoin/.bitcoin/bitcoin.conf \
|
||||
-datadir=/home/bitcoin/.bitcoin \
|
||||
-startupnotify="chmod g+r /home/bitcoin/.bitcoin/.cookie"
|
||||
|
||||
# Process management
|
||||
####################
|
||||
Type=forking
|
||||
PIDFile=/run/bitcoind/bitcoind.pid
|
||||
Restart=on-failure
|
||||
TimeoutSec=300
|
||||
RestartSec=30
|
||||
|
||||
# Directory creation and permissions
|
||||
####################################
|
||||
User=bitcoin
|
||||
UMask=0027
|
||||
|
||||
# /run/bitcoind
|
||||
RuntimeDirectory=bitcoind
|
||||
RuntimeDirectoryMode=0710
|
||||
|
||||
# Hardening measures
|
||||
####################
|
||||
# Provide a private /tmp and /var/tmp.
|
||||
PrivateTmp=true
|
||||
|
||||
# Mount /usr, /boot/ and /etc read-only for the process.
|
||||
ProtectSystem=full
|
||||
|
||||
# Disallow the process and all of its children to gain
|
||||
# new privileges through execve().
|
||||
NoNewPrivileges=true
|
||||
|
||||
# Use a new /dev namespace only populated with API pseudo devices
|
||||
# such as /dev/null, /dev/zero and /dev/random.
|
||||
PrivateDevices=true
|
||||
|
||||
# Deny the creation of writable and executable memory mappings.
|
||||
MemoryDenyWriteExecute=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
BIN
contrib.tar.gz
BIN
contrib.tar.gz
Binary file not shown.
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
len=$1
|
||||
if [ -z $len ]; then
|
||||
len=32;
|
||||
fi
|
||||
# Genera 256 caratteri ASCII stampabili (32-126)
|
||||
random_ascii_256=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c $len)
|
||||
|
||||
echo "Stringa ASCII random (256 caratteri):"
|
||||
echo "$random_ascii_256"
|
||||
echo
|
||||
echo "Lunghezza: ${#random_ascii_256} caratteri"
|
||||
@@ -1,2 +0,0 @@
|
||||
3508f2970e7d6a597db58e3cc1e72d7f0f81f782fa95b3ea0f9388693b6587b2: JSON-RPC error: RPC error response: RpcError { code: -25, message: "bad-txns-inputs-missingorspent", data: None } : 1752489317 : 1751860800
|
||||
4df113c0d6c4f31cb01841edb1ce4434ec45bff78eef0b9fcf96129b0b21bb30: JSON-RPC error: RPC error response: RpcError { code: -27, message: "Transaction outputs already in utxo set", data: None } : 1752650972 : 1710573876
|
||||
19
lib.sh
19
lib.sh
@@ -1,19 +0,0 @@
|
||||
echo_i() {
|
||||
echo -e "\033[1m==> $1\033[0m"
|
||||
}
|
||||
|
||||
echo_e() {
|
||||
echo -e "\033[31;1m$1\033[0m"
|
||||
}
|
||||
|
||||
echo_s() {
|
||||
echo -e "\033[32;1m$1\033[0m"
|
||||
}
|
||||
echo_w() {
|
||||
echo -e "\033[33;1m$1\033[0m"
|
||||
}
|
||||
|
||||
alias echo_i=echo_i
|
||||
alias echo_e=echo_e
|
||||
alias echo_s=echo_s
|
||||
alias echo_w=echo_w
|
||||
@@ -1,159 +0,0 @@
|
||||
# bal-server
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
git clone https://bitcoin-after.life/gitea/bitcoinafterlife/bal-server.git
|
||||
cd bal-server
|
||||
openssl genpkey -algorithm ED25519 -out private_key.pem
|
||||
openssl pkey -in private_key.pem -pubout -out public_key.pem
|
||||
cargo build --release
|
||||
sudo cp target/release/bal-server target/release/bal-pusher /usr/local/bin
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
docker build -t bal-server .
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name bal-server \
|
||||
--network host \
|
||||
--tmpfs /tmp:rw,noexec,nosuid \
|
||||
-v /path/to/data:/var/bal:rw \
|
||||
-v /path/to/.bitcoin/regtest/.cookie:/var/bal/.bitcoin/regtest/.cookie:ro \
|
||||
-e BAL_SERVER_REGTEST_ADDRESS="your_xpub_or_address" \
|
||||
-e BAL_SERVER_REGTEST_FIXED_FEE=50000 \
|
||||
-e BAL_SERVER_INFO="BAL server" \
|
||||
-e BAL_PUSHER_NETWORK=regtest \
|
||||
-e BAL_PUSHER_REGTEST_ZMQ_HASHBLOCK=tcp://127.0.0.1:28332 \
|
||||
-e BAL_PUSHER_REGTEST_COOKIE_FILE=/var/bal/.bitcoin/regtest/.cookie \
|
||||
bal-server
|
||||
```
|
||||
|
||||
### Docker environment variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_NETWORK` | Network to run pusher on (`bitcoin`, `testnet`, `testnet4`, `signet`, `regtest`). | `bitcoin` |
|
||||
| `BAL_PUSHER_REGTEST_ZMQ_HASHBLOCK` | ZMQ endpoint for regtest blocks. | `tcp://127.0.0.1:21332` |
|
||||
| `BAL_PUSHER_REGTEST_COOKIE_FILE` | Absolute path to Bitcoin Core cookie file inside the container. | - |
|
||||
|
||||
> **Note:** The container runs as a non-root `bal` user (uid 1000) with `tini` as PID 1.
|
||||
> The `/var/bal` volume stores the database. Mount Bitcoin Core's cookie file as read-only.
|
||||
> When using `--network host`, ensure only `127.0.0.1` is used for internal services.
|
||||
|
||||
## Configuration (bal-server)
|
||||
|
||||
The `bal-server` application can be configured using environment variables.
|
||||
|
||||
### General
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_DB_FILE` | Path to the SQLite3 database file. | `bal.db` |
|
||||
| `BAL_SERVER_BIND_ADDRESS` | Address to listen on. **Never bind to `0.0.0.0` in production without a reverse proxy.** | `127.0.0.1` |
|
||||
| `BAL_SERVER_BIND_PORT` | Port to listen on. | `9137` |
|
||||
| `BAL_SERVER_INFO` | Server info string returned by the `/` endpoint. | - |
|
||||
| `BAL_SERVER_PUB_KEY_PATH` | Ed25519 public key for signature verification. | `public_key.pem` |
|
||||
| `BAL_SERVER_URL` | Public URL of this server (used for stats reporting). | - |
|
||||
| `SSL_KEY_PATH` | Ed25519 private key for signing stats reports. | `private_key.pem` |
|
||||
| `RUST_LOG` | Log level (`error`, `warn`, `info`, `debug`, `trace`). | `info` |
|
||||
|
||||
### Per-network addresses and fees
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_BITCOIN_ADDRESS` | xpub or address for mainnet. | - |
|
||||
| `BAL_SERVER_BITCOIN_FIXED_FEE` | Fixed fee (satoshis) for mainnet. | `50000` |
|
||||
| `BAL_SERVER_REGTEST_ADDRESS` | xpub or address for regtest. | - |
|
||||
| `BAL_SERVER_REGTEST_FIXED_FEE` | Fixed fee (satoshis) for regtest. | `50000` |
|
||||
| `BAL_SERVER_SIGNET_ADDRESS` | xpub or address for signet. | - |
|
||||
| `BAL_SERVER_SIGNET_FIXED_FEE` | Fixed fee (satoshis) for signet. | `50000` |
|
||||
| `BAL_SERVER_TESTNET_ADDRESS` | xpub or address for testnet. | - |
|
||||
| `BAL_SERVER_TESTNET_FIXED_FEE` | Fixed fee (satoshis) for testnet. | `50000` |
|
||||
| `BAL_SERVER_TESTNET4_ADDRESS` | xpub or address for testnet4. | - |
|
||||
| `BAL_SERVER_TESTNET4_FIXED_FEE` | Fixed fee (satoshis) for testnet4. | `50000` |
|
||||
|
||||
### DoS protection (Actix Web)
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_ACTIX_MAX_BODY_SIZE` | Maximum request body size in bytes. | `1048576` (1 MB) |
|
||||
| `BAL_SERVER_ACTIX_TIMEOUT_SECS` | Request timeout in seconds. | `5` |
|
||||
| `BAL_SERVER_ACTIX_PUSHTXS_PER_SEC` | Rate limit: push txs requests per second. | `1` |
|
||||
| `BAL_SERVER_ACTIX_PUSHTXS_BURST` | Rate limit: push txs burst size. | `3` |
|
||||
| `BAL_SERVER_ACTIX_SEARCHTX_PER_SEC` | Rate limit: search tx requests per second. | `5` |
|
||||
| `BAL_SERVER_ACTIX_SEARCHTX_BURST` | Rate limit: search tx burst size. | `10` |
|
||||
| `BAL_SERVER_ACTIX_INFO_PER_SEC` | Rate limit: info requests per second. | `20` |
|
||||
| `BAL_SERVER_ACTIX_INFO_BURST` | Rate limit: info burst size. | `30` |
|
||||
| `BAL_SERVER_ACTIX_DEFAULT_PER_SEC` | Rate limit: default requests per second. | `50` |
|
||||
| `BAL_SERVER_ACTIX_DEFAULT_BURST` | Rate limit: default burst size. | `100` |
|
||||
| `BAL_SERVER_ACTIX_WORKERS` | Number of Actix worker threads. | `4` |
|
||||
| `BAL_SERVER_ACTIX_MAX_CONNECTIONS` | Maximum concurrent connections. | `100` |
|
||||
|
||||
---
|
||||
|
||||
# bal-pusher
|
||||
|
||||
`bal-pusher` monitors Bitcoin blocks via ZMQ and pushes time-locked transactions from the database to the Bitcoin network when their **locktime** exceeds the **median time past** (MTP).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Bitcoin Core** with ZMQ support enabled. Add to `bitcoin.conf`:
|
||||
```
|
||||
zmqpubhashblock=tcp://127.0.0.1:28332
|
||||
```
|
||||
- **Rust and Cargo**: [Rust Installation](https://www.rust-lang.org/tools/install)
|
||||
- **Libraries**: `libssl-dev`, `libsodium-dev`, `libzmq5-dev`, `libsqlite3-dev`
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
bal-pusher [bitcoin|testnet|testnet4|signet|regtest]
|
||||
```
|
||||
|
||||
If no network is specified, defaults to `bitcoin`.
|
||||
|
||||
## Configuration (bal-pusher)
|
||||
|
||||
### General
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_DB_FILE` | Path to the SQLite3 database file. | `bal.db` |
|
||||
| `BAL_PUSHER_SEND_STATS` | Send stats to welist server. | `false` |
|
||||
| `BAL_SERVER_URL` | URL of bal-server (for stats reporting). | - |
|
||||
| `SSL_KEY_PATH` | Ed25519 private key for signing stats reports. | `private_key.pem` |
|
||||
| `WELIST_SERVER_URL` | Welist server URL. | `https://welist.bitcoin-after.life` |
|
||||
|
||||
### Per-network configuration
|
||||
|
||||
Each network (`bitcoin`, `regtest`, `testnet`, `testnet4`, `signet`) supports the following variables.
|
||||
Replace `{NETWORK}` with the uppercase network name (e.g., `REGTEST`, `BITCOIN`).
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_{NETWORK}_ZMQ_HASHBLOCK` | ZMQ endpoint for block notifications. | `tcp://127.0.0.1:28332` (mainnet) |
|
||||
| `BAL_PUSHER_{NETWORK}_COOKIE_FILE` | Absolute path to Bitcoin Core cookie file. | `$HOME/.bitcoin/{dir}/.cookie` |
|
||||
| `BAL_PUSHER_{NETWORK}_RPC_USER` | Bitcoin Core RPC username (alternative to cookie auth). | - |
|
||||
| `BAL_PUSHER_{NETWORK}_RPC_PASSWORD` | Bitcoin Core RPC password. | - |
|
||||
| `BAL_PUSHER_{NETWORK}_HOST` | Bitcoin Core RPC host. | `http://127.0.0.1` |
|
||||
| `BAL_PUSHER_{NETWORK}_PORT` | Bitcoin Core RPC port. | `8332` (mainnet) |
|
||||
| `BAL_PUSHER_{NETWORK}_DIR_PATH` | Bitcoin Core data directory subfolder. | `` (mainnet) |
|
||||
|
||||
Default ZMQ ports per network:
|
||||
|
||||
| Network | ZMQ Port | RPC Port |
|
||||
| --- | --- | --- |
|
||||
| `bitcoin` | 28332 | 8332 |
|
||||
| `regtest` | 21332 | 18443 |
|
||||
| `testnet` | 23332 | 18332 |
|
||||
| `testnet4` | 22332 | 48332 |
|
||||
| `signet` | 24332 | 38332 |
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,12 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQFSBAABCgA8FiEEqEfQBNuRYQcRymoN/nVnBugz4NEFAmpdecseHHN2YXRhbnRy
|
||||
eWFAYml0Y29pbi1hZnRlci5saWZlAAoJEP51ZwboM+DRhBwH/jlj/9Uug1mEbPqe
|
||||
cKPKC2cgRXfoHsVK2YUOZH1XB4wW4qmjJSDV6TyCMmy5F+z4I5rEhaa/QyLL2YIE
|
||||
bPaT7xJ5xKp3gzmRpHrwPEyvQEDj6ZxeZuAg/Rzk6FL1O0R8PQhxOqzOrW3uMfN+
|
||||
5VSrw8yaqNDoI5rpNF2R8D/Gfr2Ya4Xo9I0ScIaXUeH4oq5aHu3dFUI9jldfagbM
|
||||
6u7U7xPeT4gwNF01r47GrMdIfXpOmC0q8ba0wLPfvkDLz4N907Pp0CpCq0Hg5IlH
|
||||
F0MEh3ReKQXimhHWZ/gDex5M6gt5nFSZLxA68VvPoi5f3j7rTxrNveRyJFa6EPTH
|
||||
mzp58Ac=
|
||||
=tx0k
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -1 +0,0 @@
|
||||
e8055bf320b527266a071cf515759b4dec5d6a166f5bca6f23fa3d804eb52ffa bal-server-0.3.0_x86_64_linux-gnu.tar.gz
|
||||
Binary file not shown.
@@ -1,159 +0,0 @@
|
||||
# bal-server
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
git clone https://bitcoin-after.life/gitea/bitcoinafterlife/bal-server.git
|
||||
cd bal-server
|
||||
openssl genpkey -algorithm ED25519 -out private_key.pem
|
||||
openssl pkey -in private_key.pem -pubout -out public_key.pem
|
||||
cargo build --release
|
||||
sudo cp target/release/bal-server target/release/bal-pusher /usr/local/bin
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
docker build -t bal-server .
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name bal-server \
|
||||
--network host \
|
||||
--tmpfs /tmp:rw,noexec,nosuid \
|
||||
-v /path/to/data:/var/bal:rw \
|
||||
-v /path/to/.bitcoin/regtest/.cookie:/var/bal/.bitcoin/regtest/.cookie:ro \
|
||||
-e BAL_SERVER_REGTEST_ADDRESS="your_xpub_or_address" \
|
||||
-e BAL_SERVER_REGTEST_FIXED_FEE=50000 \
|
||||
-e BAL_SERVER_INFO="BAL server" \
|
||||
-e BAL_PUSHER_NETWORK=regtest \
|
||||
-e BAL_PUSHER_REGTEST_ZMQ_HASHBLOCK=tcp://127.0.0.1:28332 \
|
||||
-e BAL_PUSHER_REGTEST_COOKIE_FILE=/var/bal/.bitcoin/regtest/.cookie \
|
||||
bal-server
|
||||
```
|
||||
|
||||
### Docker environment variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_NETWORK` | Network to run pusher on (`bitcoin`, `testnet`, `testnet4`, `signet`, `regtest`). | `bitcoin` |
|
||||
| `BAL_PUSHER_REGTEST_ZMQ_HASHBLOCK` | ZMQ endpoint for regtest blocks. | `tcp://127.0.0.1:21332` |
|
||||
| `BAL_PUSHER_REGTEST_COOKIE_FILE` | Absolute path to Bitcoin Core cookie file inside the container. | - |
|
||||
|
||||
> **Note:** The container runs as a non-root `bal` user (uid 1000) with `tini` as PID 1.
|
||||
> The `/var/bal` volume stores the database. Mount Bitcoin Core's cookie file as read-only.
|
||||
> When using `--network host`, ensure only `127.0.0.1` is used for internal services.
|
||||
|
||||
## Configuration (bal-server)
|
||||
|
||||
The `bal-server` application can be configured using environment variables.
|
||||
|
||||
### General
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_DB_FILE` | Path to the SQLite3 database file. | `bal.db` |
|
||||
| `BAL_SERVER_BIND_ADDRESS` | Address to listen on. **Never bind to `0.0.0.0` in production without a reverse proxy.** | `127.0.0.1` |
|
||||
| `BAL_SERVER_BIND_PORT` | Port to listen on. | `9137` |
|
||||
| `BAL_SERVER_INFO` | Server info string returned by the `/` endpoint. | - |
|
||||
| `BAL_SERVER_PUB_KEY_PATH` | Ed25519 public key for signature verification. | `public_key.pem` |
|
||||
| `BAL_SERVER_URL` | Public URL of this server (used for stats reporting). | - |
|
||||
| `SSL_KEY_PATH` | Ed25519 private key for signing stats reports. | `private_key.pem` |
|
||||
| `RUST_LOG` | Log level (`error`, `warn`, `info`, `debug`, `trace`). | `info` |
|
||||
|
||||
### Per-network addresses and fees
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_BITCOIN_ADDRESS` | xpub or address for mainnet. | - |
|
||||
| `BAL_SERVER_BITCOIN_FIXED_FEE` | Fixed fee (satoshis) for mainnet. | `50000` |
|
||||
| `BAL_SERVER_REGTEST_ADDRESS` | xpub or address for regtest. | - |
|
||||
| `BAL_SERVER_REGTEST_FIXED_FEE` | Fixed fee (satoshis) for regtest. | `50000` |
|
||||
| `BAL_SERVER_SIGNET_ADDRESS` | xpub or address for signet. | - |
|
||||
| `BAL_SERVER_SIGNET_FIXED_FEE` | Fixed fee (satoshis) for signet. | `50000` |
|
||||
| `BAL_SERVER_TESTNET_ADDRESS` | xpub or address for testnet. | - |
|
||||
| `BAL_SERVER_TESTNET_FIXED_FEE` | Fixed fee (satoshis) for testnet. | `50000` |
|
||||
| `BAL_SERVER_TESTNET4_ADDRESS` | xpub or address for testnet4. | - |
|
||||
| `BAL_SERVER_TESTNET4_FIXED_FEE` | Fixed fee (satoshis) for testnet4. | `50000` |
|
||||
|
||||
### DoS protection (Actix Web)
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_ACTIX_MAX_BODY_SIZE` | Maximum request body size in bytes. | `1048576` (1 MB) |
|
||||
| `BAL_SERVER_ACTIX_TIMEOUT_SECS` | Request timeout in seconds. | `5` |
|
||||
| `BAL_SERVER_ACTIX_PUSHTXS_PER_SEC` | Rate limit: push txs requests per second. | `1` |
|
||||
| `BAL_SERVER_ACTIX_PUSHTXS_BURST` | Rate limit: push txs burst size. | `3` |
|
||||
| `BAL_SERVER_ACTIX_SEARCHTX_PER_SEC` | Rate limit: search tx requests per second. | `5` |
|
||||
| `BAL_SERVER_ACTIX_SEARCHTX_BURST` | Rate limit: search tx burst size. | `10` |
|
||||
| `BAL_SERVER_ACTIX_INFO_PER_SEC` | Rate limit: info requests per second. | `20` |
|
||||
| `BAL_SERVER_ACTIX_INFO_BURST` | Rate limit: info burst size. | `30` |
|
||||
| `BAL_SERVER_ACTIX_DEFAULT_PER_SEC` | Rate limit: default requests per second. | `50` |
|
||||
| `BAL_SERVER_ACTIX_DEFAULT_BURST` | Rate limit: default burst size. | `100` |
|
||||
| `BAL_SERVER_ACTIX_WORKERS` | Number of Actix worker threads. | `4` |
|
||||
| `BAL_SERVER_ACTIX_MAX_CONNECTIONS` | Maximum concurrent connections. | `100` |
|
||||
|
||||
---
|
||||
|
||||
# bal-pusher
|
||||
|
||||
`bal-pusher` monitors Bitcoin blocks via ZMQ and pushes time-locked transactions from the database to the Bitcoin network when their **locktime** exceeds the **median time past** (MTP).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Bitcoin Core** with ZMQ support enabled. Add to `bitcoin.conf`:
|
||||
```
|
||||
zmqpubhashblock=tcp://127.0.0.1:28332
|
||||
```
|
||||
- **Rust and Cargo**: [Rust Installation](https://www.rust-lang.org/tools/install)
|
||||
- **Libraries**: `libssl-dev`, `libsodium-dev`, `libzmq5-dev`, `libsqlite3-dev`
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
bal-pusher [bitcoin|testnet|testnet4|signet|regtest]
|
||||
```
|
||||
|
||||
If no network is specified, defaults to `bitcoin`.
|
||||
|
||||
## Configuration (bal-pusher)
|
||||
|
||||
### General
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_DB_FILE` | Path to the SQLite3 database file. | `bal.db` |
|
||||
| `BAL_PUSHER_SEND_STATS` | Send stats to welist server. | `false` |
|
||||
| `BAL_SERVER_URL` | URL of bal-server (for stats reporting). | - |
|
||||
| `SSL_KEY_PATH` | Ed25519 private key for signing stats reports. | `private_key.pem` |
|
||||
| `WELIST_SERVER_URL` | Welist server URL. | `https://welist.bitcoin-after.life` |
|
||||
|
||||
### Per-network configuration
|
||||
|
||||
Each network (`bitcoin`, `regtest`, `testnet`, `testnet4`, `signet`) supports the following variables.
|
||||
Replace `{NETWORK}` with the uppercase network name (e.g., `REGTEST`, `BITCOIN`).
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_{NETWORK}_ZMQ_HASHBLOCK` | ZMQ endpoint for block notifications. | `tcp://127.0.0.1:28332` (mainnet) |
|
||||
| `BAL_PUSHER_{NETWORK}_COOKIE_FILE` | Absolute path to Bitcoin Core cookie file. | `$HOME/.bitcoin/{dir}/.cookie` |
|
||||
| `BAL_PUSHER_{NETWORK}_RPC_USER` | Bitcoin Core RPC username (alternative to cookie auth). | - |
|
||||
| `BAL_PUSHER_{NETWORK}_RPC_PASSWORD` | Bitcoin Core RPC password. | - |
|
||||
| `BAL_PUSHER_{NETWORK}_HOST` | Bitcoin Core RPC host. | `http://127.0.0.1` |
|
||||
| `BAL_PUSHER_{NETWORK}_PORT` | Bitcoin Core RPC port. | `8332` (mainnet) |
|
||||
| `BAL_PUSHER_{NETWORK}_DIR_PATH` | Bitcoin Core data directory subfolder. | `` (mainnet) |
|
||||
|
||||
Default ZMQ ports per network:
|
||||
|
||||
| Network | ZMQ Port | RPC Port |
|
||||
| --- | --- | --- |
|
||||
| `bitcoin` | 28332 | 8332 |
|
||||
| `regtest` | 21332 | 18443 |
|
||||
| `testnet` | 23332 | 18332 |
|
||||
| `testnet4` | 22332 | 48332 |
|
||||
| `signet` | 24332 | 38332 |
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,12 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQFSBAABCgA8FiEEqEfQBNuRYQcRymoN/nVnBugz4NEFAmpeGfseHHN2YXRhbnRy
|
||||
eWFAYml0Y29pbi1hZnRlci5saWZlAAoJEP51ZwboM+DRoJUH/A+pp7RizJd0g60u
|
||||
FULkipJxDZhXQ5TJoWkjnVVRvkNfnoAms86Bik0sLxt+e8wy3w+NziUU+/ZwheCX
|
||||
hsOn1PANXjvyK8xWVKFjCpGNJY5R4iYe5cdpsY142J96UAHyrz1WJowl6HZ4wNwy
|
||||
XsNkOX1m5z/twrHosUULKLUVxs6Us4jit1SGT+4CP7us4WDBN8IAYgnMrTv3QjmI
|
||||
aAGOcOnB5FEfs0Egeh6a63l216boO/M4/eI7fkA1AnoxvVfUVnM7kL5MLwDvO6Gl
|
||||
ytGJxfq32H2mpWVYBzFaS6aue0xPQKur1G7hopRteq340tC6u44CEcomlj3O9f0p
|
||||
CR5QErI=
|
||||
=0KWl
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -1 +0,0 @@
|
||||
b6cdb29904e51cfbe354c25b346d3573e1c85bfcdc5aa589ebb391a55d8e2aa2 bal-server-0.3.1_x86_64_linux-gnu.tar.gz
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,12 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQFSBAABCgA8FiEEqEfQBNuRYQcRymoN/nVnBugz4NEFAmpeXM8eHHN2YXRhbnRy
|
||||
eWFAYml0Y29pbi1hZnRlci5saWZlAAoJEP51ZwboM+DR/08H/jY15bL48QVnPy0J
|
||||
XsgiYXP06jSZNnOoLb9hxyE41T5fZjWp/Cdu9ZyOu/xatPhNXXItYe80CKxHk/py
|
||||
JV9jdBUACVdjzWgC4xMZASUD0rwiv6UFBbMngchwy+WOubzsZY4Jp3Q/PBJm64rU
|
||||
OrWlqJ7DzKpeUtBnoS/YL4PHBCV/HXkPsXjc4wvLBOKNP/5enRY/OIVr1ySR4qQs
|
||||
HGODM3ozQeXipWebBtjs9K+p98baMXxxow7fCIT2W0jblhukRbckPPk5Bg8AklVg
|
||||
+BrhcS0Gt3bpFylbmB/J1x8gP2/lWQxSBrLxdyQYMcXT+OwbZSLL2MEYinwcwnzC
|
||||
yXH7OI8=
|
||||
=QCat
|
||||
-----END PGP SIGNATURE-----
|
||||
@@ -1 +0,0 @@
|
||||
481727931fd73a1959c17095fa900f5871b75cebc0d176576845a4dda51808f3 bal-server-0.3.2_x86_64_linux-gnu.tar.gz
|
||||
Binary file not shown.
@@ -1,159 +0,0 @@
|
||||
# bal-server
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
git clone https://bitcoin-after.life/gitea/bitcoinafterlife/bal-server.git
|
||||
cd bal-server
|
||||
openssl genpkey -algorithm ED25519 -out private_key.pem
|
||||
openssl pkey -in private_key.pem -pubout -out public_key.pem
|
||||
cargo build --release
|
||||
sudo cp target/release/bal-server target/release/bal-pusher /usr/local/bin
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
docker build -t bal-server .
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name bal-server \
|
||||
--network host \
|
||||
--tmpfs /tmp:rw,noexec,nosuid \
|
||||
-v /path/to/data:/var/bal:rw \
|
||||
-v /path/to/.bitcoin/regtest/.cookie:/var/bal/.bitcoin/regtest/.cookie:ro \
|
||||
-e BAL_SERVER_REGTEST_ADDRESS="your_xpub_or_address" \
|
||||
-e BAL_SERVER_REGTEST_FIXED_FEE=50000 \
|
||||
-e BAL_SERVER_INFO="BAL server" \
|
||||
-e BAL_PUSHER_NETWORK=regtest \
|
||||
-e BAL_PUSHER_REGTEST_ZMQ_HASHBLOCK=tcp://127.0.0.1:28332 \
|
||||
-e BAL_PUSHER_REGTEST_COOKIE_FILE=/var/bal/.bitcoin/regtest/.cookie \
|
||||
bal-server
|
||||
```
|
||||
|
||||
### Docker environment variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_NETWORK` | Network to run pusher on (`bitcoin`, `testnet`, `testnet4`, `signet`, `regtest`). | `bitcoin` |
|
||||
| `BAL_PUSHER_REGTEST_ZMQ_HASHBLOCK` | ZMQ endpoint for regtest blocks. | `tcp://127.0.0.1:21332` |
|
||||
| `BAL_PUSHER_REGTEST_COOKIE_FILE` | Absolute path to Bitcoin Core cookie file inside the container. | - |
|
||||
|
||||
> **Note:** The container runs as a non-root `bal` user (uid 1000) with `tini` as PID 1.
|
||||
> The `/var/bal` volume stores the database. Mount Bitcoin Core's cookie file as read-only.
|
||||
> When using `--network host`, ensure only `127.0.0.1` is used for internal services.
|
||||
|
||||
## Configuration (bal-server)
|
||||
|
||||
The `bal-server` application can be configured using environment variables.
|
||||
|
||||
### General
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_DB_FILE` | Path to the SQLite3 database file. | `bal.db` |
|
||||
| `BAL_SERVER_BIND_ADDRESS` | Address to listen on. **Never bind to `0.0.0.0` in production without a reverse proxy.** | `127.0.0.1` |
|
||||
| `BAL_SERVER_BIND_PORT` | Port to listen on. | `9137` |
|
||||
| `BAL_SERVER_INFO` | Server info string returned by the `/` endpoint. | - |
|
||||
| `BAL_SERVER_PUB_KEY_PATH` | Ed25519 public key for signature verification. | `public_key.pem` |
|
||||
| `BAL_SERVER_URL` | Public URL of this server (used for stats reporting). | - |
|
||||
| `SSL_KEY_PATH` | Ed25519 private key for signing stats reports. | `private_key.pem` |
|
||||
| `RUST_LOG` | Log level (`error`, `warn`, `info`, `debug`, `trace`). | `info` |
|
||||
|
||||
### Per-network addresses and fees
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_BITCOIN_ADDRESS` | xpub or address for mainnet. | - |
|
||||
| `BAL_SERVER_BITCOIN_FIXED_FEE` | Fixed fee (satoshis) for mainnet. | `50000` |
|
||||
| `BAL_SERVER_REGTEST_ADDRESS` | xpub or address for regtest. | - |
|
||||
| `BAL_SERVER_REGTEST_FIXED_FEE` | Fixed fee (satoshis) for regtest. | `50000` |
|
||||
| `BAL_SERVER_SIGNET_ADDRESS` | xpub or address for signet. | - |
|
||||
| `BAL_SERVER_SIGNET_FIXED_FEE` | Fixed fee (satoshis) for signet. | `50000` |
|
||||
| `BAL_SERVER_TESTNET_ADDRESS` | xpub or address for testnet. | - |
|
||||
| `BAL_SERVER_TESTNET_FIXED_FEE` | Fixed fee (satoshis) for testnet. | `50000` |
|
||||
| `BAL_SERVER_TESTNET4_ADDRESS` | xpub or address for testnet4. | - |
|
||||
| `BAL_SERVER_TESTNET4_FIXED_FEE` | Fixed fee (satoshis) for testnet4. | `50000` |
|
||||
|
||||
### DoS protection (Actix Web)
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_SERVER_ACTIX_MAX_BODY_SIZE` | Maximum request body size in bytes. | `1048576` (1 MB) |
|
||||
| `BAL_SERVER_ACTIX_TIMEOUT_SECS` | Request timeout in seconds. | `5` |
|
||||
| `BAL_SERVER_ACTIX_PUSHTXS_PER_SEC` | Rate limit: push txs requests per second. | `1` |
|
||||
| `BAL_SERVER_ACTIX_PUSHTXS_BURST` | Rate limit: push txs burst size. | `3` |
|
||||
| `BAL_SERVER_ACTIX_SEARCHTX_PER_SEC` | Rate limit: search tx requests per second. | `5` |
|
||||
| `BAL_SERVER_ACTIX_SEARCHTX_BURST` | Rate limit: search tx burst size. | `10` |
|
||||
| `BAL_SERVER_ACTIX_INFO_PER_SEC` | Rate limit: info requests per second. | `20` |
|
||||
| `BAL_SERVER_ACTIX_INFO_BURST` | Rate limit: info burst size. | `30` |
|
||||
| `BAL_SERVER_ACTIX_DEFAULT_PER_SEC` | Rate limit: default requests per second. | `50` |
|
||||
| `BAL_SERVER_ACTIX_DEFAULT_BURST` | Rate limit: default burst size. | `100` |
|
||||
| `BAL_SERVER_ACTIX_WORKERS` | Number of Actix worker threads. | `4` |
|
||||
| `BAL_SERVER_ACTIX_MAX_CONNECTIONS` | Maximum concurrent connections. | `100` |
|
||||
|
||||
---
|
||||
|
||||
# bal-pusher
|
||||
|
||||
`bal-pusher` monitors Bitcoin blocks via ZMQ and pushes time-locked transactions from the database to the Bitcoin network when their **locktime** exceeds the **median time past** (MTP).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Bitcoin Core** with ZMQ support enabled. Add to `bitcoin.conf`:
|
||||
```
|
||||
zmqpubhashblock=tcp://127.0.0.1:28332
|
||||
```
|
||||
- **Rust and Cargo**: [Rust Installation](https://www.rust-lang.org/tools/install)
|
||||
- **Libraries**: `libssl-dev`, `libsodium-dev`, `libzmq5-dev`, `libsqlite3-dev`
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
bal-pusher [bitcoin|testnet|testnet4|signet|regtest]
|
||||
```
|
||||
|
||||
If no network is specified, defaults to `bitcoin`.
|
||||
|
||||
## Configuration (bal-pusher)
|
||||
|
||||
### General
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_DB_FILE` | Path to the SQLite3 database file. | `bal.db` |
|
||||
| `BAL_PUSHER_SEND_STATS` | Send stats to welist server. | `false` |
|
||||
| `BAL_SERVER_URL` | URL of bal-server (for stats reporting). | - |
|
||||
| `SSL_KEY_PATH` | Ed25519 private key for signing stats reports. | `private_key.pem` |
|
||||
| `WELIST_SERVER_URL` | Welist server URL. | `https://welist.bitcoin-after.life` |
|
||||
|
||||
### Per-network configuration
|
||||
|
||||
Each network (`bitcoin`, `regtest`, `testnet`, `testnet4`, `signet`) supports the following variables.
|
||||
Replace `{NETWORK}` with the uppercase network name (e.g., `REGTEST`, `BITCOIN`).
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `BAL_PUSHER_{NETWORK}_ZMQ_HASHBLOCK` | ZMQ endpoint for block notifications. | `tcp://127.0.0.1:28332` (mainnet) |
|
||||
| `BAL_PUSHER_{NETWORK}_COOKIE_FILE` | Absolute path to Bitcoin Core cookie file. | `$HOME/.bitcoin/{dir}/.cookie` |
|
||||
| `BAL_PUSHER_{NETWORK}_RPC_USER` | Bitcoin Core RPC username (alternative to cookie auth). | - |
|
||||
| `BAL_PUSHER_{NETWORK}_RPC_PASSWORD` | Bitcoin Core RPC password. | - |
|
||||
| `BAL_PUSHER_{NETWORK}_HOST` | Bitcoin Core RPC host. | `http://127.0.0.1` |
|
||||
| `BAL_PUSHER_{NETWORK}_PORT` | Bitcoin Core RPC port. | `8332` (mainnet) |
|
||||
| `BAL_PUSHER_{NETWORK}_DIR_PATH` | Bitcoin Core data directory subfolder. | `` (mainnet) |
|
||||
|
||||
Default ZMQ ports per network:
|
||||
|
||||
| Network | ZMQ Port | RPC Port |
|
||||
| --- | --- | --- |
|
||||
| `bitcoin` | 28332 | 8332 |
|
||||
| `regtest` | 21332 | 18443 |
|
||||
| `testnet` | 23332 | 18332 |
|
||||
| `testnet4` | 22332 | 48332 |
|
||||
| `signet` | 24332 | 38332 |
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
rbitcoin-cli -rpcwallet=default sendrawtransaction $(rbitcoin-cli -rpcwallet=default gettransaction $(rbitcoin-cli -rpcwallet=default -named sendtoaddress address="$1" amount=0.0005 fee_rate=1)|jq -r .hex)
|
||||
242
src/xpub.rs2
242
src/xpub.rs2
@@ -1,242 +0,0 @@
|
||||
//use bs58;
|
||||
use bitcoin::Address;
|
||||
use bitcoin::Network;
|
||||
use bitcoin::ScriptBuf;
|
||||
use bitcoin::WPubkeyHash;
|
||||
use bitcoin::bip32::DerivationPath;
|
||||
use bitcoin::bip32::Xpub;
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::key::Secp256k1;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::str::FromStr;
|
||||
|
||||
// Mainnet (BIP44/BIP49/BIP84)
|
||||
enum BS58Prefix {
|
||||
Xpub,
|
||||
Ypub,
|
||||
Zpub,
|
||||
Tpub,
|
||||
Vpub,
|
||||
Upub,
|
||||
}
|
||||
const XPUB_PREFIX: [u8; 4] = [0x04, 0x88, 0xB2, 0x1E]; // xpub (Legacy P2PKH)
|
||||
const YPUB_PREFIX: [u8; 4] = [0x04, 0x9D, 0x7C, 0xB2]; // ypub (Nested SegWit P2SH-P2WPKH)
|
||||
const ZPUB_PREFIX: [u8; 4] = [0x04, 0xB2, 0x47, 0x46]; // zpub (Native SegWit P2WPKH)
|
||||
const TPUB_PREFIX: [u8; 4] = [0x04, 0x35, 0x87, 0xCF]; // tpub (Testnet Legacy P2PKH)
|
||||
const VPUB_PREFIX: [u8; 4] = [0x04, 0x5F, 0x1C, 0xF6]; // vpub (Testnet Nested SegWit)
|
||||
const UPUB_PREFIX: [u8; 4] = [0x04, 0x4A, 0x52, 0x62]; // upub (RegTest Nested SegWit)
|
||||
// Constants from Bitcoin Core's checksum algorithm
|
||||
const INPUT_CHARSET: &[u8] = b"0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
|
||||
const CHECKSUM_CHARSET: &[u8] = b"qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||
|
||||
// Polynomial modulo function used in checksum calculation (same as in Bitcoin Core)
|
||||
fn poly_mod(mut c: u64, val: u64) -> u64 {
|
||||
let c0 = c >> 35;
|
||||
c = ((c & 0x7ffffffff) << 5) ^ val;
|
||||
if c0 & 1 > 0 {
|
||||
c ^= 0xf5dee51989
|
||||
};
|
||||
if c0 & 2 > 0 {
|
||||
c ^= 0xa9fdca3312
|
||||
};
|
||||
if c0 & 4 > 0 {
|
||||
c ^= 0x1bab10e32d
|
||||
};
|
||||
if c0 & 8 > 0 {
|
||||
c ^= 0x3706b1677a
|
||||
};
|
||||
if c0 & 16 > 0 {
|
||||
c ^= 0x644d626ffd
|
||||
};
|
||||
|
||||
c
|
||||
}
|
||||
|
||||
// Calculate checksum for a descriptor string
|
||||
fn calc_checksum(desc: &str) -> Result<String, String> {
|
||||
// Separate descriptor from any existing checksum
|
||||
let desc = match desc.split_once('#') {
|
||||
Some((d, _)) => d,
|
||||
None => desc,
|
||||
};
|
||||
|
||||
let mut c: u64 = 1;
|
||||
let mut cls: u64 = 0;
|
||||
let mut clscount: u64 = 0;
|
||||
|
||||
// Process each character in the descriptor
|
||||
for ch in desc.as_bytes() {
|
||||
let pos = match INPUT_CHARSET.iter().position(|b| b == ch) {
|
||||
Some(p) => p as u64,
|
||||
None => return Err(format!("Invalid character in descriptor: {}", *ch as char)),
|
||||
};
|
||||
|
||||
c = poly_mod(c, pos & 31);
|
||||
cls = cls * 3 + (pos >> 5);
|
||||
clscount += 1;
|
||||
|
||||
if clscount == 3 {
|
||||
c = poly_mod(c, cls);
|
||||
cls = 0;
|
||||
clscount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if clscount > 0 {
|
||||
c = poly_mod(c, cls);
|
||||
}
|
||||
|
||||
// Final steps in checksum calculation
|
||||
for _ in 0..8 {
|
||||
c = poly_mod(c, 0);
|
||||
}
|
||||
c ^= 1;
|
||||
|
||||
// Convert checksum to characters
|
||||
let mut checksum = String::with_capacity(8);
|
||||
for j in 0..8 {
|
||||
let idx = ((c >> (5 * (7 - j))) & 31) as usize;
|
||||
checksum.push(CHECKSUM_CHARSET[idx] as char);
|
||||
}
|
||||
|
||||
Ok(checksum)
|
||||
}
|
||||
|
||||
pub fn get_bitcoincore_descriptor(xpub: &String) -> String {
|
||||
let fingerprint = calculate_fingerprint(xpub);
|
||||
let mut bip = 84;
|
||||
let cpub = xpub.to_string();
|
||||
match &xpub[0..4] {
|
||||
"vpub" => {
|
||||
bip = 84;
|
||||
}
|
||||
"zpub" => {
|
||||
bip = 84;
|
||||
}
|
||||
&_ => {
|
||||
bip = 84;
|
||||
}
|
||||
};
|
||||
let descriptor = format!(
|
||||
"wpkh([{}/84h/0h/0h]{}/0/*)",
|
||||
fingerprint,
|
||||
convert_xpub(xpub)
|
||||
);
|
||||
let descriptor = match calc_checksum(&descriptor) {
|
||||
Ok(checksum) => {
|
||||
let clean_descriptor = descriptor.split('#').next().unwrap_or(&descriptor);
|
||||
format!("{}#{}", clean_descriptor, checksum)
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Error: {}", err);
|
||||
"".to_string()
|
||||
}
|
||||
};
|
||||
descriptor
|
||||
//format!("{}#{}",descriptor,checksum)
|
||||
}
|
||||
fn convert_xpub(xpub: &String) -> String {
|
||||
if xpub[0..4] == *"xpub" || xpub[0..4] == *"ypub" || xpub[0..4] == *"zpub" {
|
||||
return convert_to(xpub, BS58Prefix::Xpub).unwrap();
|
||||
} else {
|
||||
return convert_to(xpub, BS58Prefix::Tpub).unwrap();
|
||||
}
|
||||
}
|
||||
pub fn calculate_fingerprint(tpub: &str) -> String {
|
||||
let xpub = Xpub::from_str(&convert_to(tpub, BS58Prefix::Xpub).unwrap()).unwrap();
|
||||
let fp = xpub.fingerprint();
|
||||
let pp = xpub.parent_fingerprint;
|
||||
format!("{}", fp)
|
||||
}
|
||||
|
||||
fn base58check_decode(s: &str) -> Result<Vec<u8>, String> {
|
||||
let data = bs58::decode(s).into_vec().map_err(|e| e.to_string())?;
|
||||
if data.len() < 4 {
|
||||
return Err("Data troppo corta".to_string());
|
||||
}
|
||||
let (payload, checksum) = data.split_at(data.len() - 4);
|
||||
let hash = Sha256::digest(&Sha256::digest(payload));
|
||||
if hash[0..4] != checksum[..] {
|
||||
return Err("Checksum invalido".to_string());
|
||||
}
|
||||
Ok(payload.to_vec())
|
||||
}
|
||||
|
||||
fn base58check_encode(data: &[u8]) -> String {
|
||||
let checksum = &Sha256::digest(&Sha256::digest(data))[0..4];
|
||||
let full = [data, checksum].concat();
|
||||
bs58::encode(full).into_string()
|
||||
}
|
||||
|
||||
fn convert_to(zpub: &str, prefix: BS58Prefix) -> Result<String, String> {
|
||||
let mut data = base58check_decode(zpub)?;
|
||||
|
||||
if data.len() < 4 {
|
||||
return Err("Non è una zpub valida.".to_string());
|
||||
}
|
||||
data.splice(
|
||||
0..4,
|
||||
match prefix {
|
||||
BS58Prefix::Xpub => XPUB_PREFIX,
|
||||
BS58Prefix::Ypub => YPUB_PREFIX,
|
||||
BS58Prefix::Zpub => ZPUB_PREFIX,
|
||||
BS58Prefix::Vpub => VPUB_PREFIX,
|
||||
BS58Prefix::Tpub => TPUB_PREFIX,
|
||||
BS58Prefix::Upub => UPUB_PREFIX,
|
||||
},
|
||||
);
|
||||
|
||||
Ok(base58check_encode(&data))
|
||||
}
|
||||
pub fn new_address_from_xpub(
|
||||
zpub: &str,
|
||||
index: i64,
|
||||
network: Network,
|
||||
) -> Result<(String, String), Box<dyn std::error::Error>> {
|
||||
let xpub = Xpub::from_str(&convert_to(zpub, BS58Prefix::Xpub)?)?;
|
||||
let path = format!("m/0/{}", index);
|
||||
let derivation_path = DerivationPath::from_str(&path.as_str())?;
|
||||
let secp = Secp256k1::new();
|
||||
let derived_xpub = xpub.derive_pub(&secp, &derivation_path)?;
|
||||
let public_key = derived_xpub.public_key;
|
||||
let pubkey_bytes = public_key.serialize();
|
||||
let witness_program = WPubkeyHash::hash(&pubkey_bytes);
|
||||
let redeem_script = ScriptBuf::new_p2wpkh(&witness_program);
|
||||
//let script_pubkey = ScriptBuf::new_p2sh(&redeem_script.script_hash());
|
||||
let address = Address::from_script(&redeem_script, network)?;
|
||||
//let address = Address::from_script(&script_pubkey, network)?;
|
||||
Ok((address.to_string(), path.to_string()))
|
||||
}
|
||||
/*
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>>{
|
||||
//let zpub = "xpub6C29v8gxCXREHUzoGNfqqFqZWxTVEmYtmZshuzfSwBKNmfYQxoizRziCkkUUA4WwJZkJs2i7nttRiC6MQG7mxZpouXeYkTZe3U52RyPAeo2";
|
||||
//let zpub = "vpub5Ut36m34VebUUjdhYaxJCjSPqk3ZR8bA2MXLmbHRQCycAxy5Q1GFPJspLkJywJjBgQnvU3rmwPKTPp1ELLWeXrve3zBufpZR4MRCCTNHzsn";
|
||||
let zpub = "zpub6qdfveGrxBQN3z8paZ88EHpCn5MGXpUoHwQmHhPbj4rPQtUjbWyCHrJFYZGVY7MsmVbDaeu4JYqRqcdLzMx78wZFEWbLrF9FG3gr2MPQC5H";
|
||||
match convert_to(zpub,BS58Prefix::Tpub) {
|
||||
Ok(tpub) => println!("XPUB: {}", tpub),
|
||||
Err(e) => eprintln!("Errore: {}", e),
|
||||
}
|
||||
let fingerprint = base58check_encode(&calculate_fingerprint(zpub));
|
||||
println!("ZPUB: {}, FINGERPRINT: {}",zpub,fingerprint);
|
||||
|
||||
let xpub = Xpub::from_str(&convert_to(zpub,BS58Prefix::Xpub)?)?;
|
||||
let tpub = convert_to(zpub,BS58Prefix::Tpub)?;
|
||||
let fingerprint = base58check_encode(&calculate_fingerprint(&tpub));
|
||||
println!("TPUB: {}, FINGERPRINT: {}",tpub,fingerprint);
|
||||
let derivation_path = DerivationPath::from_str("m/0/0")?;
|
||||
let secp = Secp256k1::new();
|
||||
let derived_xpub = xpub.derive_pub(&secp, &derivation_path)?;
|
||||
|
||||
let public_key = derived_xpub.public_key;
|
||||
let pubkey_bytes = public_key.serialize();
|
||||
let witness_program = WPubkeyHash::hash(&pubkey_bytes);
|
||||
let redeem_script = ScriptBuf::new_p2wpkh(&witness_program);
|
||||
let script_pubkey = ScriptBuf::new_p2sh(&redeem_script.script_hash());
|
||||
|
||||
// Generate the Bitcoin SegWit (BIP49) address
|
||||
let network = Network::Bitcoin;
|
||||
let address = Address::from_script(&redeem_script, network)?;
|
||||
let address = Address::from_script(&script_pubkey, network)?;
|
||||
|
||||
Ok(())
|
||||
}*/
|
||||
@@ -1 +0,0 @@
|
||||
docker run -d --name test-pg -e POSTGRES_PASSWORD=testpass -e POSTGRES_USER=testuser -e POSTGRES_DB=testdb -p 5432:5432 postgres:16-alpine
|
||||
@@ -1,55 +0,0 @@
|
||||
# /etc/systemd/system/tbitcoind.service
|
||||
|
||||
[Unit]
|
||||
Description=Bitcoin Testnet daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
|
||||
# Service execution
|
||||
###################
|
||||
|
||||
ExecStart=/usr/local/bin/bitcoind -daemon -testnet \
|
||||
-pid=/run/tbitcoind/tbitcoind.pid \
|
||||
-conf=/home/bitcoin/.bitcoin/bitcoin.conf \
|
||||
-datadir=/home/bitcoin/.bitcoin \
|
||||
-startupnotify="chmod g+r /home/bitcoin/.bitcoin/testnet3/.cookie"
|
||||
|
||||
# Process management
|
||||
####################
|
||||
Type=forking
|
||||
PIDFile=/run/tbitcoind/tbitcoind.pid
|
||||
Restart=on-failure
|
||||
TimeoutSec=300
|
||||
RestartSec=30
|
||||
|
||||
# Directory creation and permissions
|
||||
####################################
|
||||
User=bitcoin
|
||||
UMask=0027
|
||||
|
||||
# /run/tbitcoind
|
||||
RuntimeDirectory=tbitcoind
|
||||
RuntimeDirectoryMode=0710
|
||||
|
||||
# Hardening measures
|
||||
####################
|
||||
# Provide a private /tmp and /var/tmp.
|
||||
PrivateTmp=true
|
||||
|
||||
# Mount /usr, /boot/ and /etc read-only for the process.
|
||||
ProtectSystem=full
|
||||
|
||||
# Disallow the process and all of its children to gain
|
||||
# new privileges through execve().
|
||||
NoNewPrivileges=true
|
||||
|
||||
# Use a new /dev namespace only populated with API pseudo devices
|
||||
# such as /dev/null, /dev/zero and /dev/random.
|
||||
PrivateDevices=true
|
||||
|
||||
# Deny the creation of writable and executable memory mappings.
|
||||
MemoryDenyWriteExecute=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
30
test
30
test
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"amount": -0.00050000,
|
||||
"fee": -0.00000141,
|
||||
"confirmations": 0,
|
||||
"trusted": false,
|
||||
"txid": "931dd22dca06fee28c0bdeb404ce055bbd4250c5a2ea0f9dee1d43def1838e0e",
|
||||
"wtxid": "87c53a3f39a8874c4a70b65108f81c9899f199d79e378ce254198aaf25b185e6",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"mempoolconflicts": [
|
||||
],
|
||||
"time": 1747802029,
|
||||
"timereceived": 1747802029,
|
||||
"bip125-replaceable": "yes",
|
||||
"details": [
|
||||
{
|
||||
"address": "bcrt1qh2c83yulvs7kgw0g6q3lkxqws4cnf0uxpcgcpt",
|
||||
"category": "send",
|
||||
"amount": -0.00050000,
|
||||
"vout": 1,
|
||||
"fee": -0.00000141,
|
||||
"abandoned": false
|
||||
}
|
||||
],
|
||||
"hex": "02000000000101f54628aceb97a6140c5266ae6367c22db0e451c5683ef67455f99c2a92f6fece0000000000fdffffff02a3b8804a00000000160014fc2a81aebc081721099e0f394b82736f6651535650c3000000000000160014bab078939f643d6439e8d023fb180e857134bf8602473044022055da1e26c408892a5c8e1ac04fd7e1ce7a2fbd92ee10d977228a845423073d6402200f05d658ebf3a64e2f33e59a1378aa4f3966381917437b3a7627698f332b3c97012102614ec7c018916f137ea4137a05c328c1c0b6cc9ffb6b7a7aca249bff15124ceaa7010000",
|
||||
"lastprocessedblock": {
|
||||
"hash": "469ae576ee05edae3fe7dfc800f24d61165759f4ac57415adc5b14afcdf4a9ff",
|
||||
"height": 423
|
||||
}
|
||||
}
|
||||
271
update
271
update
@@ -1,271 +0,0 @@
|
||||
Per creare un Webservice in Rust che utilizza Axis (un framework per la definizione di servizi web basato su XML Schema) e Diesel (un ORM per database SQLite), dobbiamo seguire alcuni passaggi. Tuttavia, è
|
||||
importante notare che l'uso diretto di Axis con Diesel non è il modo più comune o consigliato per creare servizi web in Rust. Più spesso si usa Axum o Rocket come framework principale.
|
||||
|
||||
Tuttavia, posso mostrarti un esempio molto simplificato di come potresti iniziare a strutturare il tuo progetto utilizzando Diesel con SQLite3 e una libreria esterna per la definizione dei servizi web. Per
|
||||
brevità, utilizzeremo `axum`, che è uno dei framework più popolari per creare servizi web in Rust.
|
||||
|
||||
### Prerequisiti
|
||||
|
||||
1. Installa Rust: https://www.rust-lang.org/tools/install
|
||||
2. Crea un nuovo progetto con Cargo:
|
||||
```sh
|
||||
cargo new rust_sqlite_webserver
|
||||
cd rust_sqlite_webserver
|
||||
```
|
||||
|
||||
3. Aggiungi le dipendenze al file `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
axum = "0.6"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
diesel = { version = "2.0", features = ["sqlite"] }
|
||||
dotenv = "0.15"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
diesel_cli = { version = "2.0", features = ["sqlite"] }
|
||||
|
||||
[[bin]]
|
||||
name = "main"
|
||||
path = "src/main.rs"
|
||||
```
|
||||
|
||||
### Schema di Database
|
||||
|
||||
Creiamo un semplice schema per un database SQLite3 con Diesel.
|
||||
|
||||
1. Crea il file `schema.rs` in una nuova directory `src/schema/`.
|
||||
|
||||
```rust
|
||||
// src/schema/users.sql
|
||||
CREATE TABLE users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
email TEXT NOT NULL UNIQUE
|
||||
);
|
||||
```
|
||||
|
||||
2. Genera i modelli Diesel:
|
||||
|
||||
```sh
|
||||
cargo run --bin diesel_cli setup
|
||||
cargo run --bin diesel_cli migrate
|
||||
```
|
||||
|
||||
### Creazione del Servizio Web con Axum
|
||||
|
||||
1. Crea un file `main.rs` nella directory `src/`.
|
||||
|
||||
```rust
|
||||
use axum::{
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
|
||||
mod schema;
|
||||
mod models;
|
||||
|
||||
// Importiamo i modelli generati da Diesel
|
||||
use self::schema::users::dsl::*;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct User {
|
||||
id: i32,
|
||||
name: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
impl From<models::User> for User {
|
||||
fn from(user: models::User) -> Self {
|
||||
User {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Insertable)]
|
||||
#[diesel(table_name = users)]
|
||||
struct NewUser {
|
||||
name: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
async fn get_users() -> impl axum::response::IntoResponse {
|
||||
let conn = establish_connection();
|
||||
let results = users.load::<models::User>(&conn).expect("Error loading users");
|
||||
|
||||
(axum::http::StatusCode::OK, axum::Json(results.into_iter().map(User::from).collect()))
|
||||
}
|
||||
|
||||
async fn create_user(user: axum::Json<NewUser>) -> impl axum::response::IntoResponse {
|
||||
let conn = establish_connection();
|
||||
let new_user = user.0;
|
||||
diesel::insert_into(users)
|
||||
.values(&new_user)
|
||||
.get_result::<models::User>(&conn)
|
||||
.expect("Error creating new user");
|
||||
|
||||
(axum::http::StatusCode::CREATED, axum::Json(User::from(new_user)))
|
||||
}
|
||||
|
||||
fn establish_connection() -> SqliteConnection {
|
||||
dotenv().ok();
|
||||
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
SqliteConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Set the `RUST_LOG` environment variable if you want to see logs
|
||||
env_logger::init();
|
||||
|
||||
let app = Router::new()
|
||||
.route("/users", get(get_users).post(create_user));
|
||||
|
||||
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
||||
.serve(app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
### Esecuzione del Progetto
|
||||
|
||||
1. Crea un file `.env` nella directory root con la seguente riga:
|
||||
|
||||
```sh
|
||||
DATABASE_URL=sqlite://db.sqlite3
|
||||
```
|
||||
|
||||
2. Esegui il progetto:
|
||||
|
||||
```sh
|
||||
cargo run
|
||||
```
|
||||
|
||||
Ora, puoi accedere al tuo servizio web:
|
||||
|
||||
- Per ottenere tutti gli utenti: `GET http://localhost:3000/users`
|
||||
- Per creare un nuovo utente: `POST http://localhost:3000/users` con il corpo JSON:
|
||||
```json
|
||||
{
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
Questo esempio mostra come iniziare a strutturare un servizio web in Rust utilizzando Axum, Diesel con SQLite3. Ricorda che questo è solo un punto di partenza e potrebbe essere esteso o modificato per
|
||||
soddisfare le tue specifiche esigenze.
|
||||
|
||||
>>> il mio progetto prevede vari file binari, oltre al webservice come posso gestire piu' binari?
|
||||
Se il tuo progetto in Rust contiene diversi file binari (ad esempio, un client e un server separati), puoi organizzarli in moduli all'interno del tuo progetto. Ogni modulo può essere compilato come un file
|
||||
binario separato.
|
||||
|
||||
Ecco come farlo:
|
||||
|
||||
1. **Struttura del Progetto**:
|
||||
Organizza il tuo progetto in una directory `src` con sottodirectory per i vari binari e moduli. Ad esempio:
|
||||
|
||||
```
|
||||
rust_project/
|
||||
├── src/
|
||||
│ ├── main.rs
|
||||
│ ├── client/
|
||||
│ │ └── main.rs
|
||||
│ ├── server/
|
||||
│ │ └── main.rs
|
||||
│ └── common/
|
||||
│ └── lib.rs
|
||||
├── Cargo.toml
|
||||
└── .env
|
||||
```
|
||||
|
||||
2. **Creazione dei Binari**:
|
||||
Ogni sottodirectory con un file `main.rs` può essere considerata un binario separato.
|
||||
|
||||
3. **Cargo.toml**:
|
||||
Configura il tuo `Cargo.toml` per gestire i vari binari.
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "rust_project"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
axum = "0.6"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
diesel = { version = "2.0", features = ["sqlite"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
diesel_cli = { version = "2.0", features = ["sqlite"] }
|
||||
|
||||
[[bin]]
|
||||
name = "server"
|
||||
path = "src/server/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "client"
|
||||
path = "src/client/main.rs"
|
||||
```
|
||||
|
||||
4. **Esecuzione dei Binari**:
|
||||
Puoi ora compilare e eseguire i binari separati.
|
||||
|
||||
```sh
|
||||
cargo build --release
|
||||
./target/release/server
|
||||
./target/release/client
|
||||
```
|
||||
|
||||
5. **Moduli Comuni**:
|
||||
Se hai moduli comuni che vengono utilizzati da più binari, puoi organizzarli in una directory `common` e importarli nei vari binari.
|
||||
|
||||
```rust
|
||||
// src/common/lib.rs
|
||||
pub mod common_module {
|
||||
pub fn common_function() {
|
||||
println!("This is a common function");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Allora, puoi importare questo modulo in altri binari:
|
||||
|
||||
```rust
|
||||
// src/server/main.rs
|
||||
extern crate rust_project;
|
||||
|
||||
use rust_project::common::lib as common;
|
||||
|
||||
fn main() {
|
||||
common::common_function();
|
||||
}
|
||||
```
|
||||
|
||||
6. **File `.env`**:
|
||||
Puoi avere un file `.env` nella directory root del progetto per gestire le variabili d'ambiente comuni, e poi specificare variabili d'ambiente separate per ogni binario in sottodirectory.
|
||||
|
||||
```sh
|
||||
# .env
|
||||
DATABASE_URL=sqlite://db.sqlite3
|
||||
|
||||
# src/server/.env
|
||||
SERVER_PORT=3000
|
||||
|
||||
# src/client/.env
|
||||
CLIENT_IP=localhost
|
||||
```
|
||||
|
||||
Questo approccio ti permette di mantenere una struttura organizzata per i tuoi progetti multi-binari in Rust, facilitando la gestione e il sviluppo di diverse parti del tuo progetto.
|
||||
|
||||
@@ -1,271 +0,0 @@
|
||||
Per creare un Webservice in Rust che utilizza Axis (un framework per la definizione di servizi web basato su XML Schema) e Diesel (un ORM per database SQLite), dobbiamo seguire alcuni passaggi. Tuttavia, è
|
||||
importante notare che l'uso diretto di Axis con Diesel non è il modo più comune o consigliato per creare servizi web in Rust. Più spesso si usa Axum o Rocket come framework principale.
|
||||
|
||||
Tuttavia, posso mostrarti un esempio molto simplificato di come potresti iniziare a strutturare il tuo progetto utilizzando Diesel con SQLite3 e una libreria esterna per la definizione dei servizi web. Per
|
||||
brevità, utilizzeremo `axum`, che è uno dei framework più popolari per creare servizi web in Rust.
|
||||
|
||||
### Prerequisiti
|
||||
|
||||
1. Installa Rust: https://www.rust-lang.org/tools/install
|
||||
2. Crea un nuovo progetto con Cargo:
|
||||
```sh
|
||||
cargo new rust_sqlite_webserver
|
||||
cd rust_sqlite_webserver
|
||||
```
|
||||
|
||||
3. Aggiungi le dipendenze al file `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
axum = "0.6"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
diesel = { version = "2.0", features = ["sqlite"] }
|
||||
dotenv = "0.15"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
diesel_cli = { version = "2.0", features = ["sqlite"] }
|
||||
|
||||
[[bin]]
|
||||
name = "main"
|
||||
path = "src/main.rs"
|
||||
```
|
||||
|
||||
### Schema di Database
|
||||
|
||||
Creiamo un semplice schema per un database SQLite3 con Diesel.
|
||||
|
||||
1. Crea il file `schema.rs` in una nuova directory `src/schema/`.
|
||||
|
||||
```rust
|
||||
// src/schema/users.sql
|
||||
CREATE TABLE users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
email TEXT NOT NULL UNIQUE
|
||||
);
|
||||
```
|
||||
|
||||
2. Genera i modelli Diesel:
|
||||
|
||||
```sh
|
||||
cargo run --bin diesel_cli setup
|
||||
cargo run --bin diesel_cli migrate
|
||||
```
|
||||
|
||||
### Creazione del Servizio Web con Axum
|
||||
|
||||
1. Crea un file `main.rs` nella directory `src/`.
|
||||
|
||||
```rust
|
||||
use axum::{
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
|
||||
mod schema;
|
||||
mod models;
|
||||
|
||||
// Importiamo i modelli generati da Diesel
|
||||
use self::schema::users::dsl::*;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct User {
|
||||
id: i32,
|
||||
name: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
impl From<models::User> for User {
|
||||
fn from(user: models::User) -> Self {
|
||||
User {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Insertable)]
|
||||
#[diesel(table_name = users)]
|
||||
struct NewUser {
|
||||
name: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
async fn get_users() -> impl axum::response::IntoResponse {
|
||||
let conn = establish_connection();
|
||||
let results = users.load::<models::User>(&conn).expect("Error loading users");
|
||||
|
||||
(axum::http::StatusCode::OK, axum::Json(results.into_iter().map(User::from).collect()))
|
||||
}
|
||||
|
||||
async fn create_user(user: axum::Json<NewUser>) -> impl axum::response::IntoResponse {
|
||||
let conn = establish_connection();
|
||||
let new_user = user.0;
|
||||
diesel::insert_into(users)
|
||||
.values(&new_user)
|
||||
.get_result::<models::User>(&conn)
|
||||
.expect("Error creating new user");
|
||||
|
||||
(axum::http::StatusCode::CREATED, axum::Json(User::from(new_user)))
|
||||
}
|
||||
|
||||
fn establish_connection() -> SqliteConnection {
|
||||
dotenv().ok();
|
||||
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
SqliteConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Set the `RUST_LOG` environment variable if you want to see logs
|
||||
env_logger::init();
|
||||
|
||||
let app = Router::new()
|
||||
.route("/users", get(get_users).post(create_user));
|
||||
|
||||
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
||||
.serve(app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
### Esecuzione del Progetto
|
||||
|
||||
1. Crea un file `.env` nella directory root con la seguente riga:
|
||||
|
||||
```sh
|
||||
DATABASE_URL=sqlite://db.sqlite3
|
||||
```
|
||||
|
||||
2. Esegui il progetto:
|
||||
|
||||
```sh
|
||||
cargo run
|
||||
```
|
||||
|
||||
Ora, puoi accedere al tuo servizio web:
|
||||
|
||||
- Per ottenere tutti gli utenti: `GET http://localhost:3000/users`
|
||||
- Per creare un nuovo utente: `POST http://localhost:3000/users` con il corpo JSON:
|
||||
```json
|
||||
{
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
Questo esempio mostra come iniziare a strutturare un servizio web in Rust utilizzando Axum, Diesel con SQLite3. Ricorda che questo è solo un punto di partenza e potrebbe essere esteso o modificato per
|
||||
soddisfare le tue specifiche esigenze.
|
||||
|
||||
>>> il mio progetto prevede vari file binari, oltre al webservice come posso gestire piu' binari?
|
||||
Se il tuo progetto in Rust contiene diversi file binari (ad esempio, un client e un server separati), puoi organizzarli in moduli all'interno del tuo progetto. Ogni modulo può essere compilato come un file
|
||||
binario separato.
|
||||
|
||||
Ecco come farlo:
|
||||
|
||||
1. **Struttura del Progetto**:
|
||||
Organizza il tuo progetto in una directory `src` con sottodirectory per i vari binari e moduli. Ad esempio:
|
||||
|
||||
```
|
||||
rust_project/
|
||||
├── src/
|
||||
│ ├── main.rs
|
||||
│ ├── client/
|
||||
│ │ └── main.rs
|
||||
│ ├── server/
|
||||
│ │ └── main.rs
|
||||
│ └── common/
|
||||
│ └── lib.rs
|
||||
├── Cargo.toml
|
||||
└── .env
|
||||
```
|
||||
|
||||
2. **Creazione dei Binari**:
|
||||
Ogni sottodirectory con un file `main.rs` può essere considerata un binario separato.
|
||||
|
||||
3. **Cargo.toml**:
|
||||
Configura il tuo `Cargo.toml` per gestire i vari binari.
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "rust_project"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
axum = "0.6"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
diesel = { version = "2.0", features = ["sqlite"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
diesel_cli = { version = "2.0", features = ["sqlite"] }
|
||||
|
||||
[[bin]]
|
||||
name = "server"
|
||||
path = "src/server/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "client"
|
||||
path = "src/client/main.rs"
|
||||
```
|
||||
|
||||
4. **Esecuzione dei Binari**:
|
||||
Puoi ora compilare e eseguire i binari separati.
|
||||
|
||||
```sh
|
||||
cargo build --release
|
||||
./target/release/server
|
||||
./target/release/client
|
||||
```
|
||||
|
||||
5. **Moduli Comuni**:
|
||||
Se hai moduli comuni che vengono utilizzati da più binari, puoi organizzarli in una directory `common` e importarli nei vari binari.
|
||||
|
||||
```rust
|
||||
// src/common/lib.rs
|
||||
pub mod common_module {
|
||||
pub fn common_function() {
|
||||
println!("This is a common function");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Allora, puoi importare questo modulo in altri binari:
|
||||
|
||||
```rust
|
||||
// src/server/main.rs
|
||||
extern crate rust_project;
|
||||
|
||||
use rust_project::common::lib as common;
|
||||
|
||||
fn main() {
|
||||
common::common_function();
|
||||
}
|
||||
```
|
||||
|
||||
6. **File `.env`**:
|
||||
Puoi avere un file `.env` nella directory root del progetto per gestire le variabili d'ambiente comuni, e poi specificare variabili d'ambiente separate per ogni binario in sottodirectory.
|
||||
|
||||
```sh
|
||||
# .env
|
||||
DATABASE_URL=sqlite://db.sqlite3
|
||||
|
||||
# src/server/.env
|
||||
SERVER_PORT=3000
|
||||
|
||||
# src/client/.env
|
||||
CLIENT_IP=localhost
|
||||
```
|
||||
|
||||
Questo approccio ti permette di mantenere una struttura organizzata per i tuoi progetti multi-binari in Rust, facilitando la gestione e il sviluppo di diverse parti del tuo progetto.
|
||||
|
||||
Reference in New Issue
Block a user