Skip to content

Commit 0f47e01

Browse files
committed
Merge bitcoin/bitcoin#20923: signet miner followups
b3c712c contrib/signet/miner: remove debug code (Anthony Towns) 297e351 bitcoin-util: use AddCommand / GetCommand (Anthony Towns) b6d493f contrib/signet/README.md: Update miner description (Anthony Towns) e665438 contrib/signet/miner: Automatic timestamp for first block (Anthony Towns) a383ce5 contrib/signet/miner: --grind-cmd is required for calibrate (Anthony Towns) 1a45cd2 contrib/signet: Fix typos (Anthony Towns) Pull request description: Followups from #19937 ACKs for top commit: laanwj: Code review ACK b3c712c Tree-SHA512: a1003f9ee3697438114b60872b50f4300c8b52f0d58551566eb61c421d787525807ae75be205dcab2c24358cd568f53260120880109a9d728773405ff987596f
2 parents da1e6d5 + b3c712c commit 0f47e01

File tree

3 files changed

+66
-90
lines changed

3 files changed

+66
-90
lines changed

contrib/signet/README.md

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,28 @@ accept one claim per day. See `--password` above.
2121
miner
2222
=====
2323

24-
To mine the first block in your custom chain, you can run:
24+
You will first need to pick a difficulty target. Since signet chains are primarily protected by a signature rather than proof of work, there is no need to spend as much energy as possible mining, however you may wish to choose to spend more time than the absolute minimum. The calibrate subcommand can be used to pick a target appropriate for your hardware, eg:
2525

2626
cd src/
27-
CLI="./bitcoin-cli -conf=mysignet.conf"
28-
MINER="..contrib/signet/miner"
27+
MINER="../contrib/signet/miner"
2928
GRIND="./bitcoin-util grind"
30-
ADDR=$($CLI -signet getnewaddress)
31-
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --set-block-time=-1
32-
33-
This will mine a block with the current timestamp. If you want to backdate the chain, you can give a different timestamp to --set-block-time.
34-
35-
You will then need to pick a difficulty target. Since signet chains are primarily protected by a signature rather than proof of work, there is no need to spend as much energy as possible mining, however you may wish to choose to spend more time than the absolute minimum. The calibrate subcommand can be used to pick a target, eg:
36-
3729
$MINER calibrate --grind-cmd="$GRIND"
3830
nbits=1e00f403 for 25s average mining time
3931

4032
It defaults to estimating an nbits value resulting in 25s average time to find a block, but the --seconds parameter can be used to pick a different target, or the --nbits parameter can be used to estimate how long it will take for a given difficulty.
4133

42-
Using the --ongoing parameter will then cause the signet miner to create blocks indefinitely. It will pick the time between blocks so that difficulty is adjusted to match the provided --nbits value.
34+
To mine the first block in your custom chain, you can run:
4335

44-
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=1e00f403 --ongoing
36+
CLI="./bitcoin-cli -conf=mysignet.conf"
37+
ADDR=$($CLI -signet getnewaddress)
38+
NBITS=1e00f403
39+
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=$NBITS
40+
41+
This will mine a single block with a backdated timestamp designed to allow 100 blocks to be mined as quickly as possible, so that it is possible to do transactions.
42+
43+
Adding the --ongoing parameter will then cause the signet miner to create blocks indefinitely. It will pick the time between blocks so that difficulty is adjusted to match the provided --nbits value.
44+
45+
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=$NBITS --ongoing
4546

4647
Other options
4748
-------------
@@ -50,9 +51,11 @@ The --debug and --quiet options are available to control how noisy the signet mi
5051

5152
Instead of specifying --ongoing, you can specify --max-blocks=N to mine N blocks and stop.
5253

53-
Instead of using a single address, a ranged descriptor may be provided instead (via the --descriptor parameter), with the reward for the block at height H being sent to the H'th address generated from the descriptor.
54+
The --set-block-time option is available to manually move timestamps forward or backward (subject to the rules that blocktime must be greater than mediantime, and dates can't be more than two hours in the future). It can only be used when mining a single block (ie, not when using --ongoing or --max-blocks greater than 1).
55+
56+
Instead of using a single address, a ranged descriptor may be provided via the --descriptor parameter, with the reward for the block at height H being sent to the H'th address generated from the descriptor.
5457

55-
Instead of calculating a specific nbits value, --min-nbits can be specified instead, in which case the mininmum signet difficulty will be targeted.
58+
Instead of calculating a specific nbits value, --min-nbits can be specified instead, in which case the minimum signet difficulty will be targeted. Signet's minimum difficulty corresponds to --nbits=1e0377ae.
5659

5760
By default, the signet miner mines blocks at fixed intervals with minimal variation. If you want blocks to appear more randomly, as they do in mainnet, specify the --poisson option.
5861

@@ -76,5 +79,5 @@ These steps can instead be done explicitly:
7679
$MINER --cli="$CLI" solvepsbt --grind-cmd="$GRIND" |
7780
$CLI -signet -stdin submitblock
7881

79-
This is intended to allow you to replace part of the pipeline for further experimentation, if desired.
82+
This is intended to allow you to replace part of the pipeline for further experimentation (eg, to sign the block with a hardware wallet).
8083

contrib/signet/miner

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -428,10 +428,13 @@ def do_generate(args):
428428
action_time = now
429429
is_mine = True
430430
elif bestheader["height"] == 0:
431-
logging.error("When mining first block in a new signet, must specify --set-block-time")
432-
return 1
431+
time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
432+
time_delta *= 100 # 100 blocks
433+
logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60))
434+
mine_time = now - time_delta
435+
action_time = now
436+
is_mine = True
433437
else:
434-
435438
time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
436439
mine_time = bestheader["time"] + time_delta
437440

@@ -520,36 +523,26 @@ def do_calibrate(args):
520523
sys.stderr.write("Can only specify one of --nbits or --seconds\n")
521524
return 1
522525
if args.nbits is not None and len(args.nbits) != 8:
523-
sys.stderr.write("Must specify 8 hex digits for --nbits")
526+
sys.stderr.write("Must specify 8 hex digits for --nbits\n")
524527
return 1
525528

526529
TRIALS = 600 # gets variance down pretty low
527530
TRIAL_BITS = 0x1e3ea75f # takes about 5m to do 600 trials
528-
#TRIAL_BITS = 0x1e7ea75f # XXX
529531

530532
header = CBlockHeader()
531533
header.nBits = TRIAL_BITS
532534
targ = nbits_to_target(header.nBits)
533535

534536
start = time.time()
535537
count = 0
536-
#CHECKS=[]
537538
for i in range(TRIALS):
538539
header.nTime = i
539540
header.nNonce = 0
540541
headhex = header.serialize().hex()
541542
cmd = args.grind_cmd.split(" ") + [headhex]
542543
newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip()
543-
#newhead = FromHex(CBlockHeader(), newheadhex.decode('utf8'))
544-
#count += newhead.nNonce
545-
#if (i+1) % 100 == 0:
546-
# CHECKS.append((i+1, count, time.time()-start))
547-
548-
#print("checks =", [c*1.0 / (b*targ*2**-256) for _,b,c in CHECKS])
549544

550545
avg = (time.time() - start) * 1.0 / TRIALS
551-
#exp_count = 2**256 / targ * TRIALS
552-
#print("avg =", avg, "count =", count, "exp_count =", exp_count)
553546

554547
if args.nbits is not None:
555548
want_targ = nbits_to_target(int(args.nbits,16))
@@ -590,7 +583,6 @@ def main():
590583
generate.add_argument("--nbits", default=None, type=str, help="Target nBits (specify difficulty)")
591584
generate.add_argument("--min-nbits", action="store_true", help="Target minimum nBits (use min difficulty)")
592585
generate.add_argument("--poisson", action="store_true", help="Simulate randomised block times")
593-
#generate.add_argument("--signcmd", default=None, type=str, help="Alternative signing command")
594586
generate.add_argument("--multiminer", default=None, type=str, help="Specify which set of blocks to mine (eg: 1-40/100 for the first 40%%, 2/3 for the second 3rd)")
595587
generate.add_argument("--backup-delay", default=300, type=int, help="Seconds to delay before mining blocks reserved for other miners (default=300)")
596588
generate.add_argument("--standby-delay", default=0, type=int, help="Seconds to delay before mining blocks (default=0)")
@@ -605,7 +597,7 @@ def main():
605597
sp.add_argument("--descriptor", default=None, type=str, help="Descriptor for block reward payment")
606598

607599
for sp in [solvepsbt, generate, calibrate]:
608-
sp.add_argument("--grind-cmd", default=None, type=str, help="Command to grind a block header for proof-of-work")
600+
sp.add_argument("--grind-cmd", default=None, type=str, required=(sp==calibrate), help="Command to grind a block header for proof-of-work")
609601

610602
args = parser.parse_args(sys.argv[1:])
611603

src/bitcoin-util.cpp

Lines changed: 40 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ static void SetupBitcoinUtilArgs(ArgsManager &argsman)
4343

4444
argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
4545

46+
argsman.AddCommand("grind", "Perform proof of work on hex header string", OptionsCategory::COMMANDS);
47+
4648
SetupChainParamsBaseOptions(argsman);
4749
}
4850

@@ -57,15 +59,7 @@ static int AppInitUtil(int argc, char* argv[])
5759
return EXIT_FAILURE;
5860
}
5961

60-
// Check for chain settings (Params() calls are only valid after this clause)
61-
try {
62-
SelectParams(gArgs.GetChainName());
63-
} catch (const std::exception& e) {
64-
tfm::format(std::cerr, "Error: %s\n", e.what());
65-
return EXIT_FAILURE;
66-
}
67-
68-
if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
62+
if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
6963
// First part of help message is specific to this utility
7064
std::string strUsage = PACKAGE_NAME " bitcoin-util utility version " + FormatFullVersion() + "\n";
7165
if (!gArgs.IsArgSet("-version")) {
@@ -82,6 +76,15 @@ static int AppInitUtil(int argc, char* argv[])
8276
}
8377
return EXIT_SUCCESS;
8478
}
79+
80+
// Check for chain settings (Params() calls are only valid after this clause)
81+
try {
82+
SelectParams(gArgs.GetChainName());
83+
} catch (const std::exception& e) {
84+
tfm::format(std::cerr, "Error: %s\n", e.what());
85+
return EXIT_FAILURE;
86+
}
87+
8588
return CONTINUE_EXECUTION;
8689
}
8790

@@ -111,17 +114,17 @@ static void grind_task(uint32_t nBits, CBlockHeader& header_orig, uint32_t offse
111114
}
112115
}
113116

114-
static int Grind(int argc, char* argv[], std::string& strPrint)
117+
static int Grind(std::vector<std::string> args, std::string& strPrint)
115118
{
116-
if (argc != 1) {
119+
if (args.size() != 1) {
117120
strPrint = "Must specify block header to grind";
118-
return 1;
121+
return EXIT_FAILURE;
119122
}
120123

121124
CBlockHeader header;
122-
if (!DecodeHexBlockHeader(header, argv[0])) {
125+
if (!DecodeHexBlockHeader(header, args[0])) {
123126
strPrint = "Could not decode block header";
124-
return 1;
127+
return EXIT_FAILURE;
125128
}
126129

127130
uint32_t nBits = header.nBits;
@@ -137,49 +140,13 @@ static int Grind(int argc, char* argv[], std::string& strPrint)
137140
}
138141
if (!found) {
139142
strPrint = "Could not satisfy difficulty target";
140-
return 1;
143+
return EXIT_FAILURE;
141144
}
142145

143146
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
144147
ss << header;
145148
strPrint = HexStr(ss);
146-
return 0;
147-
}
148-
149-
static int CommandLineUtil(int argc, char* argv[])
150-
{
151-
if (argc <= 1) return 1;
152-
153-
std::string strPrint;
154-
int nRet = 0;
155-
156-
try {
157-
while (argc > 1 && IsSwitchChar(argv[1][0]) && (argv[1][1] != 0)) {
158-
--argc;
159-
++argv;
160-
}
161-
162-
char* command = argv[1];
163-
if (strcmp(command, "grind") == 0) {
164-
nRet = Grind(argc-2, argv+2, strPrint);
165-
} else {
166-
strPrint = strprintf("Unknown command %s", command);
167-
nRet = 1;
168-
}
169-
}
170-
catch (const std::exception& e) {
171-
strPrint = std::string("error: ") + e.what();
172-
nRet = EXIT_FAILURE;
173-
}
174-
catch (...) {
175-
PrintExceptionContinue(nullptr, "CommandLineUtil()");
176-
throw;
177-
}
178-
179-
if (strPrint != "") {
180-
tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
181-
}
182-
return nRet;
149+
return EXIT_SUCCESS;
183150
}
184151

185152
#ifdef WIN32
@@ -199,23 +166,37 @@ int main(int argc, char* argv[])
199166
int ret = AppInitUtil(argc, argv);
200167
if (ret != CONTINUE_EXECUTION)
201168
return ret;
202-
}
203-
catch (const std::exception& e) {
169+
} catch (const std::exception& e) {
204170
PrintExceptionContinue(&e, "AppInitUtil()");
205171
return EXIT_FAILURE;
206172
} catch (...) {
207173
PrintExceptionContinue(nullptr, "AppInitUtil()");
208174
return EXIT_FAILURE;
209175
}
210176

177+
const auto cmd = gArgs.GetCommand();
178+
if (!cmd) {
179+
tfm::format(std::cerr, "Error: must specify a command\n");
180+
return EXIT_FAILURE;
181+
}
182+
211183
int ret = EXIT_FAILURE;
184+
std::string strPrint;
212185
try {
213-
ret = CommandLineUtil(argc, argv);
214-
}
215-
catch (const std::exception& e) {
216-
PrintExceptionContinue(&e, "CommandLineUtil()");
186+
if (cmd->command == "grind") {
187+
ret = Grind(cmd->args, strPrint);
188+
} else {
189+
assert(false); // unknown command should be caught earlier
190+
}
191+
} catch (const std::exception& e) {
192+
strPrint = std::string("error: ") + e.what();
217193
} catch (...) {
218-
PrintExceptionContinue(nullptr, "CommandLineUtil()");
194+
strPrint = "unknown error";
195+
}
196+
197+
if (strPrint != "") {
198+
tfm::format(ret == 0 ? std::cout : std::cerr, "%s\n", strPrint);
219199
}
200+
220201
return ret;
221202
}

0 commit comments

Comments
 (0)