Skip to content

Commit 03bbf01

Browse files
kallewoofjtimon
authored andcommitted
Signet implementation
test/functional/data/rpc_getblockstats.json needs to be touched because: Signet implementation changes the genesis block for custom chains
1 parent a1e0c56 commit 03bbf01

24 files changed

+556
-133
lines changed

contrib/example.conf

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
[signet]
3+
signet_blockscript=512103e464a9f3070da4d3e0b34ce971ff36f3e07c47a8f4beadf32e8ea7e2afa8a82451ae
4+
signet_siglen=77
5+
# DG seed node
6+
seednode=178.128.221.177
7+
bech32_hrp=sb
8+
pchmessagestart=F0C7706A
9+
pubkeyprefix=125
10+
scriptprefix=87
11+
secretprefix=217
12+
extpubkeyprefix=043587CF
13+
extprvkeyprefix=04358394

contrib/signet/issuer/issuer.sh

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env bash
2+
# Copyright (c) 2018 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
export LC_ALL=C
7+
8+
#
9+
# Issue blocks using a local node at a given interval.
10+
#
11+
12+
if [ $# -lt 3 ]; then
13+
echo "syntax: $0 <min_time> <max_time> <bitcoin-cli path> [<bitcoin-cli args>]" ; exit 1
14+
fi
15+
16+
function log()
17+
{
18+
echo "- $(date +%H:%M:%S): $*"
19+
}
20+
21+
min_time=$1
22+
shift
23+
max_time=$1
24+
shift
25+
bcli=$1
26+
shift
27+
28+
# https://stackoverflow.com/questions/806906/how-do-i-test-if-a-variable-is-a-number-in-bash
29+
re='^[0-9]+$'
30+
if ! [[ $min_time =~ $re ]] ; then
31+
echo "error: min_time $min_time is not a number" ; exit 1
32+
fi
33+
if ! [[ $max_time =~ $re ]] ; then
34+
echo "error: max_time $max_time is not a number" ; exit 1
35+
fi
36+
37+
let randinterval=max_time-min_time
38+
if [ $randinterval -lt 1 ]; then
39+
echo "error: interval min..max must be positive and greater than 0" ; exit 1
40+
fi
41+
42+
if ! [ -e "$bcli" ]; then
43+
which "$bcli" &> /dev/null
44+
if [ $? -ne 0 ]; then
45+
echo "error: unable to find bitcoin binary: $bcli" ; exit 1
46+
fi
47+
fi
48+
49+
echo "- checking node status"
50+
conns=$($bcli "$@" getconnectioncount)
51+
52+
if [ $? -ne 0 ]; then
53+
echo "node error" ; exit 1
54+
fi
55+
56+
if [ $conns -lt 1 ]; then
57+
echo "warning: node is not connected to any other node"
58+
fi
59+
60+
log "node OK with $conns connection(s)"
61+
log "mining in random intervals between $min_time .. $max_time seconds"
62+
log "hit ^C to stop"
63+
64+
while true; do
65+
let rv=$RANDOM%$randinterval
66+
echo -n -e "- $(date +%H:%M:%S): next block in $rv seconds..."
67+
sleep $rv
68+
echo -n -e " [submit]"
69+
blockhash=$($bcli "$@" getnewblockhex true)
70+
if [ $? -ne 0 ]; then
71+
echo "node error; aborting" ; exit 1
72+
fi
73+
echo ""
74+
log "broadcasting block $($bcli "$@" getblockcount) $blockhash to $($bcli "$@" getconnectioncount) peer(s)"
75+
done

src/chain.h

+10
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,16 @@ class CDiskBlockIndex : public CBlockIndex
405405
READWRITE(nTime);
406406
READWRITE(nBits);
407407
READWRITE(nNonce);
408+
if (g_solution_blocks && !(s.GetType() & SER_GETHASH)) {
409+
uint256 hash = GetBlockHash();
410+
READWRITE(g_blockheader_payload_map[hash]);
411+
size_t len = GetSizeOfCompactSize(g_blockheader_payload_map[hash].size()) + g_blockheader_payload_map[hash].size();
412+
while (len < g_solution_block_len) {
413+
uint8_t padding = 0;
414+
READWRITE(padding);
415+
len++;
416+
}
417+
}
408418
}
409419

410420
uint256 GetBlockHash() const

src/chainparams.cpp

+23-3
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
#include <boost/algorithm/string/classification.hpp>
1818
#include <boost/algorithm/string/split.hpp>
1919

20-
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
20+
#include <hash.h>
21+
22+
static CBlock CreateGenesisBlock(const CScript& coinbase_sig, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
2123
{
2224
CMutableTransaction txNew;
2325
txNew.nVersion = 1;
2426
txNew.vin.resize(1);
2527
txNew.vout.resize(1);
26-
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
28+
txNew.vin[0].scriptSig = coinbase_sig;
2729
txNew.vout[0].nValue = genesisReward;
2830
txNew.vout[0].scriptPubKey = genesisOutputScript;
2931

@@ -38,6 +40,12 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
3840
return genesis;
3941
}
4042

43+
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
44+
{
45+
CScript coinbase_sig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
46+
return CreateGenesisBlock(coinbase_sig, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
47+
}
48+
4149
/**
4250
* Build the genesis block. Note that the output of its generation
4351
* transaction cannot be spent since it did not originally exist in the
@@ -420,6 +428,10 @@ class CCustomParams : public CRegTestParams {
420428
consensus.nMinimumChainWork = uint256S(args.GetArg("-con_nminimumchainwork", "0x0"));
421429
consensus.defaultAssumeValid = uint256S(args.GetArg("-con_defaultassumevalid", "0x00"));
422430

431+
consensus.blockscript = ParseHex(args.GetArg("-signet_blockscript", ""));
432+
g_solution_blocks = !consensus.blockscript.empty();
433+
g_solution_block_len = consensus.siglen = args.GetArg("-signet_siglen", 77);
434+
423435
nPruneAfterHeight = (uint64_t)args.GetArg("-npruneafterheight", nPruneAfterHeight);
424436
fDefaultConsistencyChecks = args.GetBoolArg("-fdefaultconsistencychecks", fDefaultConsistencyChecks);
425437
fMineBlocksOnDemand = args.GetBoolArg("-fmineblocksondemand", fMineBlocksOnDemand);
@@ -457,7 +469,15 @@ class CCustomParams : public CRegTestParams {
457469
{
458470
strNetworkID = chain;
459471
UpdateFromArgs(args);
460-
genesis = CreateGenesisBlock(strNetworkID.c_str(), CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN);
472+
CHashWriter h(SER_DISK, 0);
473+
h << strNetworkID;
474+
if (g_solution_blocks) {
475+
h << consensus.blockscript << consensus.siglen;
476+
}
477+
const uint256 hash = h.GetHash();
478+
const CScript coinbase_sig = CScript() << std::vector<uint8_t>(hash.begin(), hash.end());
479+
const CScript genesis_out = CScript() << OP_RETURN;
480+
genesis = CreateGenesisBlock(coinbase_sig, genesis_out, 1296688602, 0, 0x207fffff, 1, 50 * COIN);
461481
consensus.hashGenesisBlock = genesis.GetHash();
462482
}
463483
};

src/chainparamsbase.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ void SetupChainParamsBaseOptions()
2323
gArgs.AddArg("-testnet", "Use the test chain", false, OptionsCategory::CHAINPARAMS);
2424
gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest or custom only)", true, OptionsCategory::CHAINPARAMS);
2525
gArgs.AddArg("-seednode=<ip>", "Use specified node as seed node. This option can be specified multiple times to connect to multiple nodes. (custom only)", true, OptionsCategory::CHAINPARAMS);
26+
gArgs.AddArg("-signet_blockscript", "Blocks must satisfy the given script to be considered valid instead of using pow. If empty, and by default, it is ignored. (custom only)", true, OptionsCategory::CHAINPARAMS);
27+
gArgs.AddArg("-signet_siglen", "The length of the signature must be exactly this long (padded to this length, if shorter). All block headers in this network are of length 80 + this value (custom only)", true, OptionsCategory::CHAINPARAMS);
2628
}
2729

2830
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;

src/consensus/params.h

+4
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ struct Params {
7575
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
7676
uint256 nMinimumChainWork;
7777
uint256 defaultAssumeValid;
78+
79+
std::vector<uint8_t> blockscript;
80+
uint32_t siglen;
7881
};
82+
7983
} // namespace Consensus
8084

8185
#endif // BITCOIN_CONSENSUS_PARAMS_H

src/miner.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
5555
BlockAssembler::Options::Options() {
5656
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
5757
nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
58+
59+
// Make room for the signature in the block header, if this is a signet block
60+
if (g_solution_blocks) nBlockMaxWeight -= g_solution_block_len;
5861
}
5962

6063
BlockAssembler::BlockAssembler(const CChainParams& params, const Options& options) : chainparams(params)

src/policy/policy.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <util.h>
1515
#include <utilstrencodings.h>
1616

17+
unsigned int GetStandardScriptVerifyFlags() { return STANDARD_SCRIPT_VERIFY_FLAGS; }
1718

1819
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
1920
{

src/policy/policy.h

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
6868
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
6969
SCRIPT_VERIFY_CONST_SCRIPTCODE;
7070

71+
unsigned int GetStandardScriptVerifyFlags();
72+
7173
/** For convenience, standard but not mandatory verify flags. */
7274
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
7375

src/pow.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <chain.h>
1010
#include <primitives/block.h>
1111
#include <uint256.h>
12+
#include <script/interpreter.h>
13+
14+
unsigned int GetStandardScriptVerifyFlags();
1215

1316
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
1417
{
@@ -71,8 +74,17 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
7174
return bnNew.GetCompact();
7275
}
7376

74-
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
77+
bool CheckProofOfWork(const uint256& hash, unsigned int nBits, const Consensus::Params& params)
7578
{
79+
if (g_solution_blocks) {
80+
if (hash == params.hashGenesisBlock) return true;
81+
SimpleSignatureChecker bsc(hash);
82+
const auto& payload = g_blockheader_payload_map.at(hash);
83+
CScript solution = CScript(payload.begin(), payload.end());
84+
CScript challenge = CScript(params.blockscript.begin(), params.blockscript.end());
85+
return VerifyScript(solution, challenge, nullptr, GetStandardScriptVerifyFlags(), bsc);
86+
}
87+
7688
bool fNegative;
7789
bool fOverflow;
7890
arith_uint256 bnTarget;

src/pow.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
1818
unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&);
1919

2020
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
21-
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
21+
bool CheckProofOfWork(const uint256& hash, unsigned int nBits, const Consensus::Params&);
2222

2323
#endif // BITCOIN_POW_H

src/primitives/block.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include <utilstrencodings.h>
1111
#include <crypto/common.h>
1212

13+
bool g_solution_blocks = false;
14+
size_t g_solution_block_len = 0;
15+
std::map<uint256,std::vector<uint8_t>> g_blockheader_payload_map;
16+
1317
uint256 CBlockHeader::GetHash() const
1418
{
1519
return SerializeHash(*this);

src/primitives/block.h

+26
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@
1010
#include <serialize.h>
1111
#include <uint256.h>
1212

13+
/**
14+
* If true, block headers contain a payload equal to a Bitcoin Script solution
15+
* to a signet challenge as defined in the chain params.
16+
*/
17+
extern bool g_solution_blocks;
18+
/**
19+
* If non-zero, defines an enforced size requirement for block header payloads.
20+
* It requires that all blocks are of size 80 + (this value) bytes.
21+
*/
22+
extern size_t g_solution_block_len;
23+
24+
/**
25+
* Contains a mapping of hash to signature data for each block header
26+
* in signet networks.
27+
*/
28+
extern std::map<uint256,std::vector<uint8_t>> g_blockheader_payload_map;
29+
1330
/** Nodes collect new transactions into a block, hash them into a hash tree,
1431
* and scan through nonce values to make the block's hash satisfy proof-of-work
1532
* requirements. When they solve the proof-of-work, they broadcast the block
@@ -43,6 +60,15 @@ class CBlockHeader
4360
READWRITE(nTime);
4461
READWRITE(nBits);
4562
READWRITE(nNonce);
63+
if (g_solution_blocks && !(s.GetType() & SER_GETHASH)) {
64+
READWRITE(g_blockheader_payload_map[GetHash()]);
65+
size_t len = GetSizeOfCompactSize(g_blockheader_payload_map[GetHash()].size()) + g_blockheader_payload_map[GetHash()].size();
66+
while (len < g_solution_block_len) {
67+
uint8_t padding = 0;
68+
READWRITE(padding);
69+
len++;
70+
}
71+
}
4672
}
4773

4874
void SetNull()

src/rpc/blockchain.cpp

+16-11
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,16 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
115115
{
116116
AssertLockHeld(cs_main);
117117
UniValue result(UniValue::VOBJ);
118-
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
118+
result.pushKV("hash", block.GetHash().GetHex());
119119
int confirmations = -1;
120120
// Only report confirmations if the block is on the main chain
121-
if (chainActive.Contains(blockindex))
121+
if (blockindex && chainActive.Contains(blockindex))
122122
confirmations = chainActive.Height() - blockindex->nHeight + 1;
123123
result.pushKV("confirmations", confirmations);
124124
result.pushKV("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS));
125125
result.pushKV("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION));
126126
result.pushKV("weight", (int)::GetBlockWeight(block));
127-
result.pushKV("height", blockindex->nHeight);
127+
if (blockindex) result.pushKV("height", blockindex->nHeight);
128128
result.pushKV("version", block.nVersion);
129129
result.pushKV("versionHex", strprintf("%08x", block.nVersion));
130130
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
@@ -142,18 +142,23 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
142142
}
143143
result.pushKV("tx", txs);
144144
result.pushKV("time", block.GetBlockTime());
145-
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
145+
if (blockindex) result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
146146
result.pushKV("nonce", (uint64_t)block.nNonce);
147147
result.pushKV("bits", strprintf("%08x", block.nBits));
148-
result.pushKV("difficulty", GetDifficulty(blockindex));
149-
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
150-
result.pushKV("nTx", (uint64_t)blockindex->nTx);
148+
if (blockindex) result.pushKV("difficulty", GetDifficulty(blockindex));
149+
if (blockindex) result.pushKV("chainwork", blockindex->nChainWork.GetHex());
150+
if (blockindex) result.pushKV("nTx", (uint64_t)blockindex->nTx);
151151

152-
if (blockindex->pprev)
152+
if (blockindex && blockindex->pprev)
153153
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
154-
CBlockIndex *pnext = chainActive.Next(blockindex);
155-
if (pnext)
156-
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
154+
if (blockindex) {
155+
CBlockIndex *pnext = chainActive.Next(blockindex);
156+
if (pnext)
157+
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
158+
}
159+
if (g_solution_blocks && g_blockheader_payload_map.count(block.GetHash())) {
160+
result.pushKV("signet-solution", HexStr(g_blockheader_payload_map.at(block.GetHash())));
161+
}
157162
return result;
158163
}
159164

src/rpc/client.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
5555
{ "getbalance", 1, "minconf" },
5656
{ "getbalance", 2, "include_watchonly" },
5757
{ "getblockhash", 0, "height" },
58+
{ "getnewblockhex", 0, "broadcast" },
5859
{ "waitforblockheight", 0, "height" },
5960
{ "waitforblockheight", 1, "timeout" },
6061
{ "waitforblock", 1, "timeout" },

src/rpc/mining.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ class submitblock_StateCatcher : public CValidationInterface
695695
}
696696
};
697697

698-
static UniValue submitblock(const JSONRPCRequest& request)
698+
UniValue submitblock(const JSONRPCRequest& request)
699699
{
700700
// We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
701701
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
@@ -725,6 +725,11 @@ static UniValue submitblock(const JSONRPCRequest& request)
725725
}
726726

727727
uint256 hash = block.GetHash();
728+
729+
if (!request.params[1].isNull()) {
730+
g_blockheader_payload_map[hash] = ParseHex(request.params[1].get_str());
731+
}
732+
728733
{
729734
LOCK(cs_main);
730735
const CBlockIndex* pindex = LookupBlockIndex(hash);
@@ -942,7 +947,6 @@ static const CRPCCommand commands[] =
942947
{ "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
943948
{ "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
944949

945-
946950
{ "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
947951

948952
{ "hidden", "estimatefee", &estimatefee, {} },

0 commit comments

Comments
 (0)