mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 02:25:40 +01:00
Merge bitcoin/bitcoin#20923: signet miner followups
b3c712cb28
contrib/signet/miner: remove debug code (Anthony Towns)297e35159f
bitcoin-util: use AddCommand / GetCommand (Anthony Towns)b6d493fd4d
contrib/signet/README.md: Update miner description (Anthony Towns)e66543827c
contrib/signet/miner: Automatic timestamp for first block (Anthony Towns)a383ce5b4a
contrib/signet/miner: --grind-cmd is required for calibrate (Anthony Towns)1a45cd2e51
contrib/signet: Fix typos (Anthony Towns) Pull request description: Followups from #19937 ACKs for top commit: laanwj: Code review ACKb3c712cb28
Tree-SHA512: a1003f9ee3697438114b60872b50f4300c8b52f0d58551566eb61c421d787525807ae75be205dcab2c24358cd568f53260120880109a9d728773405ff987596f
This commit is contained in:
commit
0f47e01d7d
@ -21,27 +21,28 @@ accept one claim per day. See `--password` above.
|
||||
miner
|
||||
=====
|
||||
|
||||
To mine the first block in your custom chain, you can run:
|
||||
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:
|
||||
|
||||
cd src/
|
||||
CLI="./bitcoin-cli -conf=mysignet.conf"
|
||||
MINER="..contrib/signet/miner"
|
||||
MINER="../contrib/signet/miner"
|
||||
GRIND="./bitcoin-util grind"
|
||||
ADDR=$($CLI -signet getnewaddress)
|
||||
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --set-block-time=-1
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
$MINER calibrate --grind-cmd="$GRIND"
|
||||
nbits=1e00f403 for 25s average mining time
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
To mine the first block in your custom chain, you can run:
|
||||
|
||||
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=1e00f403 --ongoing
|
||||
CLI="./bitcoin-cli -conf=mysignet.conf"
|
||||
ADDR=$($CLI -signet getnewaddress)
|
||||
NBITS=1e00f403
|
||||
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=$NBITS
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=$NBITS --ongoing
|
||||
|
||||
Other options
|
||||
-------------
|
||||
@ -50,9 +51,11 @@ The --debug and --quiet options are available to control how noisy the signet mi
|
||||
|
||||
Instead of specifying --ongoing, you can specify --max-blocks=N to mine N blocks and stop.
|
||||
|
||||
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.
|
||||
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).
|
||||
|
||||
Instead of calculating a specific nbits value, --min-nbits can be specified instead, in which case the mininmum signet difficulty will be targeted.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
@ -76,5 +79,5 @@ These steps can instead be done explicitly:
|
||||
$MINER --cli="$CLI" solvepsbt --grind-cmd="$GRIND" |
|
||||
$CLI -signet -stdin submitblock
|
||||
|
||||
This is intended to allow you to replace part of the pipeline for further experimentation, if desired.
|
||||
This is intended to allow you to replace part of the pipeline for further experimentation (eg, to sign the block with a hardware wallet).
|
||||
|
||||
|
@ -428,10 +428,13 @@ def do_generate(args):
|
||||
action_time = now
|
||||
is_mine = True
|
||||
elif bestheader["height"] == 0:
|
||||
logging.error("When mining first block in a new signet, must specify --set-block-time")
|
||||
return 1
|
||||
time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
|
||||
time_delta *= 100 # 100 blocks
|
||||
logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60))
|
||||
mine_time = now - time_delta
|
||||
action_time = now
|
||||
is_mine = True
|
||||
else:
|
||||
|
||||
time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
|
||||
mine_time = bestheader["time"] + time_delta
|
||||
|
||||
@ -520,12 +523,11 @@ def do_calibrate(args):
|
||||
sys.stderr.write("Can only specify one of --nbits or --seconds\n")
|
||||
return 1
|
||||
if args.nbits is not None and len(args.nbits) != 8:
|
||||
sys.stderr.write("Must specify 8 hex digits for --nbits")
|
||||
sys.stderr.write("Must specify 8 hex digits for --nbits\n")
|
||||
return 1
|
||||
|
||||
TRIALS = 600 # gets variance down pretty low
|
||||
TRIAL_BITS = 0x1e3ea75f # takes about 5m to do 600 trials
|
||||
#TRIAL_BITS = 0x1e7ea75f # XXX
|
||||
|
||||
header = CBlockHeader()
|
||||
header.nBits = TRIAL_BITS
|
||||
@ -533,23 +535,14 @@ def do_calibrate(args):
|
||||
|
||||
start = time.time()
|
||||
count = 0
|
||||
#CHECKS=[]
|
||||
for i in range(TRIALS):
|
||||
header.nTime = i
|
||||
header.nNonce = 0
|
||||
headhex = header.serialize().hex()
|
||||
cmd = args.grind_cmd.split(" ") + [headhex]
|
||||
newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip()
|
||||
#newhead = FromHex(CBlockHeader(), newheadhex.decode('utf8'))
|
||||
#count += newhead.nNonce
|
||||
#if (i+1) % 100 == 0:
|
||||
# CHECKS.append((i+1, count, time.time()-start))
|
||||
|
||||
#print("checks =", [c*1.0 / (b*targ*2**-256) for _,b,c in CHECKS])
|
||||
|
||||
avg = (time.time() - start) * 1.0 / TRIALS
|
||||
#exp_count = 2**256 / targ * TRIALS
|
||||
#print("avg =", avg, "count =", count, "exp_count =", exp_count)
|
||||
|
||||
if args.nbits is not None:
|
||||
want_targ = nbits_to_target(int(args.nbits,16))
|
||||
@ -590,7 +583,6 @@ def main():
|
||||
generate.add_argument("--nbits", default=None, type=str, help="Target nBits (specify difficulty)")
|
||||
generate.add_argument("--min-nbits", action="store_true", help="Target minimum nBits (use min difficulty)")
|
||||
generate.add_argument("--poisson", action="store_true", help="Simulate randomised block times")
|
||||
#generate.add_argument("--signcmd", default=None, type=str, help="Alternative signing command")
|
||||
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)")
|
||||
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)")
|
||||
@ -605,7 +597,7 @@ def main():
|
||||
sp.add_argument("--descriptor", default=None, type=str, help="Descriptor for block reward payment")
|
||||
|
||||
for sp in [solvepsbt, generate, calibrate]:
|
||||
sp.add_argument("--grind-cmd", default=None, type=str, help="Command to grind a block header for proof-of-work")
|
||||
sp.add_argument("--grind-cmd", default=None, type=str, required=(sp==calibrate), help="Command to grind a block header for proof-of-work")
|
||||
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
|
||||
|
@ -43,6 +43,8 @@ static void SetupBitcoinUtilArgs(ArgsManager &argsman)
|
||||
|
||||
argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
|
||||
argsman.AddCommand("grind", "Perform proof of work on hex header string", OptionsCategory::COMMANDS);
|
||||
|
||||
SetupChainParamsBaseOptions(argsman);
|
||||
}
|
||||
|
||||
@ -57,15 +59,7 @@ static int AppInitUtil(int argc, char* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Check for chain settings (Params() calls are only valid after this clause)
|
||||
try {
|
||||
SelectParams(gArgs.GetChainName());
|
||||
} catch (const std::exception& e) {
|
||||
tfm::format(std::cerr, "Error: %s\n", e.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
|
||||
if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
|
||||
// First part of help message is specific to this utility
|
||||
std::string strUsage = PACKAGE_NAME " bitcoin-util utility version " + FormatFullVersion() + "\n";
|
||||
if (!gArgs.IsArgSet("-version")) {
|
||||
@ -82,6 +76,15 @@ static int AppInitUtil(int argc, char* argv[])
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// Check for chain settings (Params() calls are only valid after this clause)
|
||||
try {
|
||||
SelectParams(gArgs.GetChainName());
|
||||
} catch (const std::exception& e) {
|
||||
tfm::format(std::cerr, "Error: %s\n", e.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
@ -111,17 +114,17 @@ static void grind_task(uint32_t nBits, CBlockHeader& header_orig, uint32_t offse
|
||||
}
|
||||
}
|
||||
|
||||
static int Grind(int argc, char* argv[], std::string& strPrint)
|
||||
static int Grind(std::vector<std::string> args, std::string& strPrint)
|
||||
{
|
||||
if (argc != 1) {
|
||||
if (args.size() != 1) {
|
||||
strPrint = "Must specify block header to grind";
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CBlockHeader header;
|
||||
if (!DecodeHexBlockHeader(header, argv[0])) {
|
||||
if (!DecodeHexBlockHeader(header, args[0])) {
|
||||
strPrint = "Could not decode block header";
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t nBits = header.nBits;
|
||||
@ -137,49 +140,13 @@ static int Grind(int argc, char* argv[], std::string& strPrint)
|
||||
}
|
||||
if (!found) {
|
||||
strPrint = "Could not satisfy difficulty target";
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << header;
|
||||
strPrint = HexStr(ss);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CommandLineUtil(int argc, char* argv[])
|
||||
{
|
||||
if (argc <= 1) return 1;
|
||||
|
||||
std::string strPrint;
|
||||
int nRet = 0;
|
||||
|
||||
try {
|
||||
while (argc > 1 && IsSwitchChar(argv[1][0]) && (argv[1][1] != 0)) {
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
char* command = argv[1];
|
||||
if (strcmp(command, "grind") == 0) {
|
||||
nRet = Grind(argc-2, argv+2, strPrint);
|
||||
} else {
|
||||
strPrint = strprintf("Unknown command %s", command);
|
||||
nRet = 1;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
strPrint = std::string("error: ") + e.what();
|
||||
nRet = EXIT_FAILURE;
|
||||
}
|
||||
catch (...) {
|
||||
PrintExceptionContinue(nullptr, "CommandLineUtil()");
|
||||
throw;
|
||||
}
|
||||
|
||||
if (strPrint != "") {
|
||||
tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
|
||||
}
|
||||
return nRet;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
@ -199,8 +166,7 @@ int main(int argc, char* argv[])
|
||||
int ret = AppInitUtil(argc, argv);
|
||||
if (ret != CONTINUE_EXECUTION)
|
||||
return ret;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
} catch (const std::exception& e) {
|
||||
PrintExceptionContinue(&e, "AppInitUtil()");
|
||||
return EXIT_FAILURE;
|
||||
} catch (...) {
|
||||
@ -208,14 +174,29 @@ int main(int argc, char* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const auto cmd = gArgs.GetCommand();
|
||||
if (!cmd) {
|
||||
tfm::format(std::cerr, "Error: must specify a command\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int ret = EXIT_FAILURE;
|
||||
std::string strPrint;
|
||||
try {
|
||||
ret = CommandLineUtil(argc, argv);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
PrintExceptionContinue(&e, "CommandLineUtil()");
|
||||
if (cmd->command == "grind") {
|
||||
ret = Grind(cmd->args, strPrint);
|
||||
} else {
|
||||
assert(false); // unknown command should be caught earlier
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
strPrint = std::string("error: ") + e.what();
|
||||
} catch (...) {
|
||||
PrintExceptionContinue(nullptr, "CommandLineUtil()");
|
||||
strPrint = "unknown error";
|
||||
}
|
||||
|
||||
if (strPrint != "") {
|
||||
tfm::format(ret == 0 ? std::cout : std::cerr, "%s\n", strPrint);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user