Skip to content

Commit

Permalink
Add configurable signet (#4)
Browse files Browse the repository at this point in the history
* Allow configuring target block time for a signet

* add Dockerfile

* contrib: make block interval configurable in signet miner

* doc: add note on creating signet

---------

Co-authored-by: benthecarman <[email protected]>
Co-authored-by: Torkel Rogstad <[email protected]>
  • Loading branch information
3 people authored Oct 7, 2024
1 parent 8592f07 commit 505c535
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 6 deletions.
62 changes: 62 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
FROM debian:bookworm-slim AS builder

RUN apt-get update -y \
&& apt-get install -y ca-certificates curl git gnupg gosu python3 wget build-essential cmake pkg-config libevent-dev libboost-dev libsqlite3-dev libzmq3-dev libminiupnpc-dev libnatpmp-dev qtbase5-dev qttools5-dev qttools5-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

WORKDIR /src

# Copy source files
COPY . .

# Remove any existing build directory
RUN rm -rf build/

# Run CMake to configure the build
RUN cmake -S . -B build -DBUILD_TESTS=OFF -DBUILD_UTIL:BOOL=OFF -DBUILD_TX:BOOL=OFF -DBUILD_WALLET_TOOL=OFF

# Build the project
RUN cmake --build build -j

# Second stage
FROM debian:bookworm-slim

ARG UID=101
ARG GID=101

ARG TARGETPLATFORM

ENV DRIVECHAIN_DATA=/home/drivechain/.drivechain
ENV PATH=/opt/drivechain/bin:$PATH

RUN groupadd --gid ${GID} drivechain \
&& useradd --create-home --no-log-init -u ${UID} -g ${GID} drivechain \
&& apt-get update -y \
&& apt-get --no-install-recommends -y install jq curl gnupg gosu ca-certificates pkg-config libevent-dev libboost-dev libsqlite3-dev libzmq3-dev libminiupnpc-dev libnatpmp-dev qtbase5-dev qttools5-dev qttools5-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY --from=builder /src/build/src/bitcoind /opt/drivechain/bin/drivechaind
COPY --from=builder /src/build/src/bitcoin-cli /opt/drivechain/bin/drivechain-cli

COPY --chmod=755 entrypoint.sh /entrypoint.sh

VOLUME ["/home/drivechain/.drivechain"]

# P2P network (mainnet, testnet & regnet respectively)
EXPOSE 8333 18333 18444

# RPC interface (mainnet, testnet & regnet respectively)
EXPOSE 8332 18332 18443

# ZMQ ports (for transactions & blocks respectively)
EXPOSE 28332 28333

HEALTHCHECK --interval=300s --start-period=60s --start-interval=10s --timeout=20s CMD gosu bitcoin bitcoin-cli -rpcwait -getinfo || exit 1

ENTRYPOINT ["/entrypoint.sh"]

RUN drivechaind -version | grep "Bitcoin Core version"

CMD ["drivechaind"]
17 changes: 12 additions & 5 deletions contrib/signet/miner
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,12 @@ def seconds_to_hms(s):
return out

class Generate:
INTERVAL = 600.0*2016/2015 # 10 minutes, adjusted for the off-by-one bug


def __init__(self, multiminer=None, ultimate_target=None, poisson=False, max_interval=1800,
standby_delay=0, backup_delay=0, set_block_time=None,
standby_delay=0, backup_delay=0, set_block_time=None,
# 10 minutes, adjusted for the off-by-one bug
block_interval=600.0*2016/2015,
poolid=None):
if multiminer is None:
multiminer = (0, 1, 1)
Expand All @@ -239,6 +240,7 @@ class Generate:
self.backup_delay = backup_delay
self.set_block_time = set_block_time
self.poolid = poolid
self.block_interval = block_interval

def next_block_delta(self, last_nbits, last_hash):
# strategy:
Expand All @@ -252,7 +254,7 @@ class Generate:
retarget_factor = self.ultimate_target / current_target
retarget_factor = max(0.25, min(retarget_factor, 4.0))

avg_interval = self.INTERVAL * retarget_factor
avg_interval = self.block_interval * retarget_factor

if self.poisson:
det_rand = int(last_hash[-8:], 16) * 2**-32
Expand All @@ -276,7 +278,7 @@ class Generate:
self.action_time = now
self.is_mine = True
elif bestheader["height"] == 0:
time_delta = self.INTERVAL * 100 # plenty of time to mine 100 blocks
time_delta = self.block_interval * 100 # plenty of time to mine 100 blocks
logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60))
self.mine_time = now - time_delta
self.action_time = now
Expand Down Expand Up @@ -345,6 +347,9 @@ def do_generate(args):
else:
max_blocks = 1

if args.block_interval is not None:
logging.info("Using block interval %s", seconds_to_hms(args.block_interval))

if args.set_block_time is not None and args.set_block_time < 0:
args.set_block_time = time.time()
logging.info("Treating negative block time as current time (%d)" % (args.set_block_time))
Expand Down Expand Up @@ -386,7 +391,8 @@ def do_generate(args):
ultimate_target = nbits_to_target(int(args.nbits,16))

gen = Generate(multiminer=my_blocks, ultimate_target=ultimate_target, poisson=args.poisson, max_interval=args.max_interval,
standby_delay=args.standby_delay, backup_delay=args.backup_delay, set_block_time=args.set_block_time, poolid=poolid)
standby_delay=args.standby_delay, backup_delay=args.backup_delay, set_block_time=args.set_block_time, poolid=poolid,
block_interval=args.block_interval)

mined_blocks = 0
bestheader = {"hash": None}
Expand Down Expand Up @@ -529,6 +535,7 @@ def main():
generate.add_argument("--backup-delay", default=300, type=int, help="Seconds to delay before mining blocks reserved for other miners (default=300)")
generate.add_argument("--standby-delay", default=0, type=int, help="Seconds to delay before mining blocks (default=0)")
generate.add_argument("--max-interval", default=1800, type=int, help="Maximum interblock interval (seconds)")
generate.add_argument("--block-interval", default=60*10, type=int, help="Consensus blocktime interval (seconds)")

calibrate = cmds.add_parser("calibrate", help="Calibrate difficulty")
calibrate.set_defaults(fn=do_calibrate)
Expand Down
39 changes: 39 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash
set -e

if [ -n "${UID+x}" ] && [ "${UID}" != "0" ]; then
usermod -u "$UID" drivechain
fi

if [ -n "${GID+x}" ] && [ "${GID}" != "0" ]; then
groupmod -g "$GID" drivechain
fi

echo "$0: assuming uid:gid for drivechain:drivechain of $(id -u drivechain):$(id -g drivechain)"

if [ "$(echo "$1" | cut -c1)" = "-" ]; then
echo "$0: assuming arguments for drivechaind"

set -- drivechaind "$@"
fi

if [ "$(echo "$1" | cut -c1)" = "-" ] || [ "$1" = "drivechaind" ]; then
mkdir -p "$DRIVECHAIN_DATA"
chmod 700 "$DRIVECHAIN_DATA"
# Fix permissions for home dir.
chown -R drivechain:drivechain "$(getent passwd drivechain | cut -d: -f6)"
# Fix permissions for drivechain data dir.
chown -R drivechain:drivechain "$DRIVECHAIN_DATA"

echo "$0: setting data directory to $DRIVECHAIN_DATA"

set -- "$@" -datadir="$DRIVECHAIN_DATA"
fi

if [ "$1" = "drivechaind" ] || [ "$1" = "drivechain-cli" ]; then
echo
exec gosu drivechain "$@"
fi

echo
exec "$@"
69 changes: 69 additions & 0 deletions l2l-signet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
Instructions on setting up the signet. This is using Fish shell, but should be
easy enough to get the gist if using an inferior shell like Bash or Zsh.

1. Create the appropriate configuration file for our network:

```conf
signet=1
# 1 minute block times. Note that /everyone/ who connects to this signet
# must have this exact configuration value.
signetblocktime=60
```
1. Generate the private key used to sign blocks + corresponding
`signetchallenge` value.
```fish
$ mkdir l2l-signet
$ ./build/src/bitcoind -daemon -regtest -datadir=$PWD/l2l-signet
$ ./build/src/bitcoin-cli -regtest -datadir=$PWD/l2l-signet \
createwallet l2l-signet
$ set signet_challenge (./build/src/bitcoin-cli -regtest -datadir=$PWD/l2l-signet \
getaddressinfo $address | jq -r .scriptPubKey)
$ echo signetchallenge=$signet_challenge >> l2l-signet/bitcoin.conf
# Need the wallet descriptors to be able to import the wallet into
$ set descriptors (./build/src/bitcoin-cli -regtest -datadir=$PWD/l2l-signet \
listdescriptors true | jq -r .descriptors)
# We're finished with the regtest wallet!
$ ./build/src/bitcoin-cli -regtest -datadir=$PWD/l2l-signet stop
```
1. Create the signet wallet
```fish
$ ./build/src/bitcoind -daemon -signet -datadir=$PWD/l2l-signet
$ ./build/src/bitcoin-cli -signet -datadir=$PWD/l2l-signet \
createwallet l2l-signet
$ ./build/src/bitcoin-cli signet -datadir=$PWD/l2l-signet \
importdescriptors "$descriptors"
```
1. Start mining on our network:
```fish
$ set address (./build/src/bitcoin-cli -signet -datadir=$PWD/l2l-signet getnewaddress)
$ ./contrib/signet/miner \
--cli "bitcoin-cli -signet -datadir=$PWD/l2l-signet" \
generate --address $address \
--grind-cmd "$PWD/build/src/bitcoin-util grind" \
--min-nbits --ongoing --block-interval 60
```
```

```
```

```
9 changes: 9 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& option
}
options.challenge.emplace(*val);
}
if (const auto signetblocktime{args.GetIntArg("-signetblocktime")}) {
if (!args.IsArgSet("-signetchallenge")) {
throw std::runtime_error("-signetblocktime cannot be set without -signetchallenge");
}
if (*signetblocktime <= 0) {
throw std::runtime_error("-signetblocktime must be greater than 0");
}
options.pow_target_spacing = *signetblocktime;
}
}

void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& options)
Expand Down
1 change: 1 addition & 0 deletions src/chainparamsbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-signet", "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-signetblocktime", "Difficulty adjustment will target a block time of the given amount in seconds (only for custom signet networks, must have -signetchallenge set; defaults to 10 minutes)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS);
}

Expand Down
2 changes: 1 addition & 1 deletion src/kernel/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ class SigNetParams : public CChainParams {
consensus.CSVHeight = 1;
consensus.SegwitHeight = 1;
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.nPowTargetSpacing = options.pow_target_spacing;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.enforce_BIP94 = false;
consensus.fPowNoRetargeting = false;
Expand Down
1 change: 1 addition & 0 deletions src/kernel/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class CChainParams
struct SigNetOptions {
std::optional<std::vector<uint8_t>> challenge{};
std::optional<std::vector<std::string>> seeds{};
int64_t pow_target_spacing{10 * 60};
};

/**
Expand Down

0 comments on commit 505c535

Please sign in to comment.