-
Bitcoin Core, with ZMQ support. For information on running this on the global signet, see drivechain.info/dev.txt
The node must not be pruned. The enforcer checks this at startup and refuses to run against a node with pruning enabled.
-
Rustc & Cargo, version 1.88.0 or higher. Installing via Rustup is recommended.
The enforcer supports running against the 3 latest major versions of Bitcoin
Core. getnetworkinfo is queried at startup and refuses to run against an
unsupported Bitcoin Core version. The supported set lives in
lib/version.rs; see --help for the override flags.
Building/running:
# Compiles the project
$ cargo build
# See available options
$ cargo run -- --help
# Starts the Connect RPC server at localhost:50001
# Adjust these parameters to match your local Bitcoin
# Core instance
$ cargo run -- \
--node-rpc-addr=localhost:38332 \
--node-rpc-user=user \
--node-rpc-pass=password \
--node-zmq-addr-sequence=tcp://0.0.0.0:29000
# You should now be able to fetch data from the server!
$ curl -H 'application/json' \
http://localhost:50051/cusf.validator.v1.ValidatorService/GetChainInfo
{
"network": "NETWORK_SIGNET"
}The CUSF enforcer exposes multiple Connect (gRPC)
services. These can be interacted with using either plain curl or a
Connect/gRPC client of your choice, for example
buf curl or
grpcurl.
Some examples of interacting with the enforcer using curl, assuming you expose
the server at the default address localhost:50051:
# Define an alias for ease of use
$ alias enforcer_curl='curl -X POST -H "Content-Type: application/json"'
# List all the available RPCs
$ buf_curl --list-methods http://localhost:50051
cusf.mainchain.v1.ValidatorService/GetBlockHeaderInfo
cusf.mainchain.v1.ValidatorService/GetChainInfo
cusf.mainchain.v1.ValidatorService/GetChainTip
cusf.mainchain.v1.ValidatorService/GetSidechains
cusf.mainchain.v1.WalletService/CreateNewAddress
cusf.mainchain.v1.WalletService/CreateSidechainProposal
... list continues
# Fetching data with a RPC that takes no input data
$ enforcer_curl http://localhost:50051/cusf.mainchain.v1.ValidatorService/GetChainInfo
{
"network": "NETWORK_SIGNET"
}
# Fetching data with a RPC that takes input data
$ request='{"block_hash": {"hex": "000002a78fc54150bb2d4cdb0fb19bcf744f2877faf90a172972fca5daf5fe92"}}'
$ enforcer_curl -d "$request" http://localhost:50051/cusf.mainchain.v1.ValidatorService/GetBlockHeaderInfo
{
"headerInfo": {
"blockHash": {
"hex": "000002a78fc54150bb2d4cdb0fb19bcf744f2877faf90a172972fca5daf5fe92"
},
"prevBlockHash": {
"hex": "000002501d569e62a56ea175896d4348dd9cfef1d700e5b06250486df07c9225"
},
"height": 34998,
"work": {
"hex": "14d4490000000000000000000000000000000000000000000000000000000000"
}
}
}By default, the enforcer runs against our custom signet. If you instead want to
run against a local regtest, you need to also run a local regtest Electrum
server. There are multiple implementations of Electrum servers, an easy-to-use
one is mempool/electrs.
For complete instructions on how to do this, consult the official docs.
A quickstart (that might not work, in case you're missing some dependencies):
$ git clone https://github.com/mempool/electrs
$ cd electrs
$ cargo run --bin electrs --release -- \
--network regtest \
--cookie=user:password \
--jsonrpc-importThe application uses the tracing crate for logging. Logging is configured
through setting the --log-level argument. Some examples:
# Prints ALL debug logs
$ cargo run ... --log-level DEBUGLogs can also be configured via env vars, which take precedence over CLI args.
# Prints logs at the "info" level and above, plus our logs the "debug" level and above
$ RUST_LOG=info,bip300301_enforcer=debug cargo run ...The proto definitions are vendored under proto/, and the generated
Rust code is checked in under lib/proto/generated/.
Generation is performed by the remote
buf.build/anthropics/buffa (message
types) and buf.build/connectrpc/rust
(Connect RPC service stubs) plugins, pinned in buf.gen.yaml
to the versions matching the buffa and connectrpc crates in Cargo.toml.
To regenerate after editing protos:
$ just generateRust code is formatted with rustfmt. You need to ensure you have a nightly version of Rust installed on your system. To format the project files from the command line:
$ cargo +nightly fmt --allMarkdown and YAML files are formatted with Prettier. The easiest way to run it is to install the Prettier VSCode extension.
To run it from the command line, install the Prettier CLI and run it from the root of the repo:
$ prettier --write .Rust code is linted with Clippy. We use a specific Clippy lint that's only available on the nightly release channel. Running Clippy therefore looks like this:
$ cargo clippy --all-targets
$ cargo +nightly clippy -- -A clippy::all -D unqualified_local_imports -Zcrate-attr="feature(unqualified_local_imports)"Integration tests can be run using
$ cargo run --example integration_tests -- <TEST ARGS>or via the just recipe, which downloads the required binaries and writes the env
files on first run. --bitcoind selects the Bitcoin Core build to run against:
$ just test-it # against bitcoin-patched (default)
$ just test-it --bitcoind unpatched # against the newest stock Bitcoin Core
$ just test-it --bitcoind stock-30.2 # against a specific stock release
$ just test-it --bitcoind alphanet # against the rolling ecash-com/bitcoin alphanet build
$ just test-it --bitcoind betanet # against the rolling ecash-com/bitcoin betanet build
$ just test-it --bitcoind all # against every flavor in the CI matrixThe alphanet and betanet builds are fetched from
releases.ecash.com and their build provenance
verified with gh attestation verify, so the
GitHub CLI must be installed (no login needed).
# Generate a flamegraph for Rust code. This does NOT
# measure syscalls/IO wait
# https://github.com/flamegraph-rs/flamegraph
$ cargo install flamegraph
$ cargo flamegraph -- --data-dir ./datadir \
--node-rpc-addr=localhost:38332 \
--node-rpc-user=user \
--node-rpc-pass=password \
--enable-mempool --exit-after-sync 100000
# macOS only
$ ./scripts/trace_enforcer_macos.sh