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
|
# Secrets and environment files - NEVER commit
|
||||||
!*.secret
|
|
||||||
|
|
||||||
# Environment files - NEVER commit tokens or secrets
|
|
||||||
*.env
|
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.*
|
||||||
.env.production
|
!.env.example
|
||||||
.env.secret
|
|
||||||
|
|
||||||
|
|
||||||
# Private keys - NEVER commit to git
|
|
||||||
# Only public_key.pem should be tracked (if needed)
|
|
||||||
*.pem
|
*.pem
|
||||||
!public_key.pem
|
!public_key.pem
|
||||||
data/*.pem
|
|
||||||
!data/public_key.pem
|
|
||||||
*.key
|
*.key
|
||||||
!*.secret
|
|
||||||
private_key.pem
|
|
||||||
privkey.pem
|
|
||||||
ec.key
|
|
||||||
chiave_privata.key
|
|
||||||
|
|
||||||
# Other sensitive files
|
# Databases
|
||||||
bal.db
|
*.db
|
||||||
.bal.db
|
*.db-shm
|
||||||
download_bal_db.sh
|
*.db-wal
|
||||||
|
|
||||||
# IDE files
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
# Rust build artifacts
|
# Rust build artifacts
|
||||||
/target
|
/target
|
||||||
Cargo.lock
|
|
||||||
!lib/
|
# Release artifacts
|
||||||
!contrib/
|
/releases/
|
||||||
!src/
|
*.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
|
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