Skip to content

smite-scenarios: disable wallet fsync in regtest bitcoind - #191

Open
erickcestari wants to merge 1 commit into
lnfuzz:masterfrom
erickcestari:bitcoind-unsafe-sqlite-sync
Open

smite-scenarios: disable wallet fsync in regtest bitcoind#191
erickcestari wants to merge 1 commit into
lnfuzz:masterfrom
erickcestari:bitcoind-unsafe-sqlite-sync

Conversation

@erickcestari

@erickcestari erickcestari commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

The coinbase of every generated block pays a wallet address, so connecting it commits the sqlite wallet with synchronous=FULL, one fsync per block. -unsafesqlitesync=1 sets synchronous=OFF, which is what Bitcoin Core's own functional test framework does.

Only matters when the datadir sits on a real filesystem, as in a local docker run: there -generate 6 drops from ~103ms to ~4ms and startup's -generate 101 from ~1469ms to ~40ms. Under Nyx the guest rootfs is the initramfs, where fsync is a no-op, so this changes nothing.

This flag should make docker's execution speed closer to performance when running inside the NYX VM.

before inside docker container:

INFO  [smite::bitcoin::metrics] bitcoin-cli: 8 calls, 123.8ms total
INFO  [smite::bitcoin::metrics]   -generate: 1 calls, 96.5ms total, 96.5ms avg, 96.5ms max (78%)
INFO  [smite::bitcoin::metrics]   getnewaddress: 1 calls, 9.5ms total, 9.5ms avg, 9.5ms max (8%)
INFO  [smite::bitcoin::metrics]   sendrawtransaction: 1 calls, 7.7ms total, 7.7ms avg, 7.7ms max (6%)
INFO  [smite::bitcoin::metrics]   getrawtransaction: 2 calls, 5.6ms total, 2.8ms avg, 4.4ms max (5%)
INFO  [smite::bitcoin::metrics]   listunspent: 1 calls, 2.2ms total, 2.2ms avg, 2.2ms max (2%)
INFO  [smite::bitcoin::metrics]   signrawtransactionwithwallet: 1 calls, 1.3ms total, 1.3ms avg, 1.3ms max (1%)
INFO  [smite::bitcoin::metrics]   lockunspent: 1 calls, 1.1ms total, 1.1ms avg, 1.1ms max (1%)

after inside docker container:

INFO  [smite::bitcoin::metrics] bitcoin-cli: 8 calls, 25.1ms total
INFO  [smite::bitcoin::metrics]   -generate: 1 calls, 8.0ms total, 8.0ms avg, 8.0ms max (32%)
INFO  [smite::bitcoin::metrics]   sendrawtransaction: 1 calls, 3.5ms total, 3.5ms avg, 3.5ms max (14%)
INFO  [smite::bitcoin::metrics]   getrawtransaction: 2 calls, 3.2ms total, 1.6ms avg, 2.1ms max (13%)
INFO  [smite::bitcoin::metrics]   listunspent: 1 calls, 2.8ms total, 2.8ms avg, 2.8ms max (11%)
INFO  [smite::bitcoin::metrics]   lockunspent: 1 calls, 2.6ms total, 2.6ms avg, 2.6ms max (10%)
INFO  [smite::bitcoin::metrics]   getnewaddress: 1 calls, 2.6ms total, 2.6ms avg, 2.6ms max (10%)
INFO  [smite::bitcoin::metrics]   signrawtransactionwithwallet: 1 calls, 2.4ms total, 2.4ms avg, 2.4ms max (10%)

The coinbase of every generated block pays a wallet address, so connecting
it commits the sqlite wallet with synchronous=FULL, one fsync per block.
-unsafesqlitesync=1 sets synchronous=OFF, which is what Bitcoin Core's own
functional test framework does.

Only matters when the datadir sits on a real filesystem, as in a local
docker run: there `-generate 6` drops from ~103ms to ~4ms and startup's
`-generate 101` from ~1469ms to ~40ms. Under Nyx the guest rootfs is the
initramfs, where fsync is a no-op, so this changes nothing.
@erickcestari

Copy link
Copy Markdown
Contributor Author

Should we document this in the README instead of changing the bitcoind configuration?

Something like:

Measuring Performance

Local mode writes to the image's filesystem, while the Nyx guest unpacks the
container into its RAM-backed initramfs. Disk fsync costs therefore show up
locally but not under Nyx, so timings taken in the default local mode can be off
by ~100ms. Put the scenario's data directory in RAM to match Nyx:

docker run --rm --tmpfs /tmp:rw,exec,size=1g \
  -v $PWD/input.bin:/input.bin -e SMITE_INPUT=/input.bin -e RUST_LOG=debug \
  smite-$TARGET-$SCENARIO /$TARGET-scenario

size= is required: Docker's --tmpfs default of 64MB cannot hold the chain and
wallet. This also makes timing-dependent crashes easier to reproduce.

@ekzyis ekzyis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK 9572e82

LGTM, I think we also care more about speed than robustness, similar to the arguments in bitcoin/bitcoin#21634:

This syncing behavior is necessary for normal operation as it helps guarantee that data won't become lost or corrupted, but in tests, we don't care about that.

@erickcestari

Copy link
Copy Markdown
Contributor Author

utACK 9572e82

LGTM, I think we also care more about speed than robustness, similar to the arguments in bitcoin/bitcoin#21634:

This syncing behavior is necessary for normal operation as it helps guarantee that data won't become lost or corrupted, but in tests, we don't care about that.

Sadly (or perhaps happily), this doesn't make a noticeable difference in practice when running the fuzzer. The improvement is only observable when running inside a Docker container. Even there, using --tmpfs brings the execution speed close to that of the NYX VM, making the unsafesqlitesync flag have no measurable impact. Given that, maybe documenting this behavior instead of changing the default configuration probably makes more sense. WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants