Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NOMERGE: [0.17] Signet implementation #433

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions contrib/example.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

chain=signet

[signet]
con_genesis_style=signet_old
signet_blockscript=512103e464a9f3070da4d3e0b34ce971ff36f3e07c47a8f4beadf32e8ea7e2afa8a82451ae
signet_siglen=77
# DG seed node
seednode=178.128.221.177
bech32_hrp=sb
pchmessagestart=F0C7706A
pubkeyprefix=125
scriptprefix=87
secretprefix=217
extpubkeyprefix=043587CF
extprvkeyprefix=04358394
75 changes: 75 additions & 0 deletions contrib/signet/issuer/issuer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

export LC_ALL=C

#
# Issue blocks using a local node at a given interval.
#

if [ $# -lt 3 ]; then
echo "syntax: $0 <min_time> <max_time> <bitcoin-cli path> [<bitcoin-cli args>]" ; exit 1
fi

function log()
{
echo "- $(date +%H:%M:%S): $*"
}

min_time=$1
shift
max_time=$1
shift
bcli=$1
shift

# https://stackoverflow.com/questions/806906/how-do-i-test-if-a-variable-is-a-number-in-bash
re='^[0-9]+$'
if ! [[ $min_time =~ $re ]] ; then
echo "error: min_time $min_time is not a number" ; exit 1
fi
if ! [[ $max_time =~ $re ]] ; then
echo "error: max_time $max_time is not a number" ; exit 1
fi

let randinterval=max_time-min_time
if [ $randinterval -lt 1 ]; then
echo "error: interval min..max must be positive and greater than 0" ; exit 1
fi

if ! [ -e "$bcli" ]; then
which "$bcli" &> /dev/null
if [ $? -ne 0 ]; then
echo "error: unable to find bitcoin binary: $bcli" ; exit 1
fi
fi

echo "- checking node status"
conns=$($bcli "$@" getconnectioncount)

if [ $? -ne 0 ]; then
echo "node error" ; exit 1
fi

if [ $conns -lt 1 ]; then
echo "warning: node is not connected to any other node"
fi

log "node OK with $conns connection(s)"
log "mining in random intervals between $min_time .. $max_time seconds"
log "hit ^C to stop"

while true; do
let rv=$RANDOM%$randinterval
Copy link
Collaborator

Choose a reason for hiding this comment

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

this needs +$min_time

echo -n -e "- $(date +%H:%M:%S): next block in $rv seconds..."
sleep $rv
echo -n -e " [submit]"
blockhash=$($bcli "$@" getnewblockhex true)
if [ $? -ne 0 ]; then
echo "node error; aborting" ; exit 1
fi
echo ""
log "broadcasting block $($bcli "$@" getblockcount) $blockhash to $($bcli "$@" getconnectioncount) peer(s)"
done
10 changes: 10 additions & 0 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,16 @@ class CDiskBlockIndex : public CBlockIndex
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
if (g_solution_blocks && !(s.GetType() & SER_GETHASH)) {
uint256 hash = GetBlockHash();
READWRITE(g_blockheader_payload_map[hash]);
size_t len = GetSizeOfCompactSize(g_blockheader_payload_map[hash].size()) + g_blockheader_payload_map[hash].size();
while (len < g_solution_block_len) {
uint8_t padding = 0;
READWRITE(padding);
len++;
}
}
}

uint256 GetBlockHash() const
Expand Down
52 changes: 48 additions & 4 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <consensus/merkle.h>

#include <chainparamsseeds.h>
#include <consensus/merkle.h>
#include <hash.h>
#include <tinyformat.h>
#include <util.h>
#include <utilstrencodings.h>
Expand All @@ -17,13 +18,13 @@
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
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)
{
CMutableTransaction txNew;
txNew.nVersion = 1;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vin[0].scriptSig = coinbase_sig;
txNew.vout[0].nValue = genesisReward;
txNew.vout[0].scriptPubKey = genesisOutputScript;

Expand All @@ -38,6 +39,12 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
return genesis;
}

static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
CScript coinbase_sig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
return CreateGenesisBlock(coinbase_sig, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
}

/**
* Build the genesis block. Note that the output of its generation
* transaction cannot be spent since it did not originally exist in the
Expand Down Expand Up @@ -403,6 +410,7 @@ class CCustomParams : public CRegTestParams {
{
UpdateVersionBitsParametersFromArgs(args);

consensus.genesis_style = args.GetArg("-con_genesis_style", "default_style");
consensus.nSubsidyHalvingInterval = args.GetArg("-con_nsubsidyhalvinginterval", consensus.nSubsidyHalvingInterval);
consensus.BIP16Exception = uint256S(args.GetArg("-con_bip16exception", "0x0"));
consensus.BIP34Height = args.GetArg("-con_bip34height", consensus.BIP34Height);
Expand All @@ -420,6 +428,10 @@ class CCustomParams : public CRegTestParams {
consensus.nMinimumChainWork = uint256S(args.GetArg("-con_nminimumchainwork", "0x0"));
consensus.defaultAssumeValid = uint256S(args.GetArg("-con_defaultassumevalid", "0x00"));

consensus.blockscript = ParseHex(args.GetArg("-signet_blockscript", ""));
g_solution_blocks = !consensus.blockscript.empty();
g_solution_block_len = consensus.siglen = args.GetArg("-signet_siglen", 77);

nPruneAfterHeight = (uint64_t)args.GetArg("-npruneafterheight", nPruneAfterHeight);
fDefaultConsistencyChecks = args.GetBoolArg("-fdefaultconsistencychecks", fDefaultConsistencyChecks);
fMineBlocksOnDemand = args.GetBoolArg("-fmineblocksondemand", fMineBlocksOnDemand);
Expand Down Expand Up @@ -452,12 +464,44 @@ class CCustomParams : public CRegTestParams {
}
}

void SetGenesisBlock()
{
if (consensus.genesis_style == "regtest2_style") {
// Same style as in https://github.com/bitcoin/bitcoin/pull/8994
assert(consensus.blockscript.empty() && "consensus.blockscript is for signets");
genesis = CreateGenesisBlock(strNetworkID.c_str(), CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN);

} else if (consensus.genesis_style == "default_style") {
CHashWriter h(SER_DISK, 0);
h << strNetworkID;
if (!consensus.blockscript.empty()) {
h << consensus.blockscript << consensus.siglen;
}
uint256 hash = h.GetHash();
CScript coinbase_sig = CScript() << std::vector<uint8_t>(hash.begin(), hash.end());
genesis = CreateGenesisBlock(coinbase_sig, CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN);

} else if (consensus.genesis_style == "signet_old") {
// Same style as in https://github.com/kallewoof/bitcoin/pull/5
assert(!consensus.blockscript.empty() && "Signets require consensus.blockscript");
CHashWriter h(SER_DISK, 0);
h << consensus.blockscript << consensus.siglen;
uint256 hash = h.GetHash();
CScript coinbase_sig = CScript() << std::vector<uint8_t>(hash.begin(), hash.end());
CScript genesis_out = CScript() << OP_RETURN;
genesis = CreateGenesisBlock(coinbase_sig, genesis_out, 1534313275, 0, 0x1d00ffff, 1, 50 * COIN);

} else {
throw std::runtime_error(strprintf("%s: Unknown consensus.genesis_style %s.", __func__, consensus.genesis_style));
}
}

public:
CCustomParams(const std::string& chain, ArgsManager& args) : CRegTestParams(args)
{
strNetworkID = chain;
UpdateFromArgs(args);
genesis = CreateGenesisBlock(strNetworkID.c_str(), CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN);
SetGenesisBlock();
consensus.hashGenesisBlock = genesis.GetHash();
}
};
Expand Down
3 changes: 3 additions & 0 deletions src/chainparamsbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ void SetupChainParamsBaseOptions()
gArgs.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
"This is intended for regression testing tools and app development.", true, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-testnet", "Use the test chain", false, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-con_genesis_style=<style>", "Use genesis style <style> (default: default_style). Allowed values: default_style, regtest2_style, signet_old", true, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest or custom only)", true, OptionsCategory::CHAINPARAMS);
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);
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);
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);
}

static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
Expand Down
5 changes: 5 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct BIP9Deployment {
* Parameters that influence chain consensus.
*/
struct Params {
std::string genesis_style;
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
/* Block hash that is excepted from BIP16 enforcement */
Expand Down Expand Up @@ -75,7 +76,11 @@ struct Params {
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
uint256 nMinimumChainWork;
uint256 defaultAssumeValid;

std::vector<uint8_t> blockscript;
uint32_t siglen;
};

} // namespace Consensus

#endif // BITCOIN_CONSENSUS_PARAMS_H
3 changes: 3 additions & 0 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
BlockAssembler::Options::Options() {
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;

// Make room for the signature in the block header, if this is a signet block
if (g_solution_blocks) nBlockMaxWeight -= g_solution_block_len;
}

BlockAssembler::BlockAssembler(const CChainParams& params, const Options& options) : chainparams(params)
Expand Down
1 change: 1 addition & 0 deletions src/policy/policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <util.h>
#include <utilstrencodings.h>

unsigned int GetStandardScriptVerifyFlags() { return STANDARD_SCRIPT_VERIFY_FLAGS; }

CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
{
Expand Down
2 changes: 2 additions & 0 deletions src/policy/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
SCRIPT_VERIFY_CONST_SCRIPTCODE;

unsigned int GetStandardScriptVerifyFlags();

/** For convenience, standard but not mandatory verify flags. */
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;

Expand Down
14 changes: 13 additions & 1 deletion src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#include <chain.h>
#include <primitives/block.h>
#include <uint256.h>
#include <script/interpreter.h>

unsigned int GetStandardScriptVerifyFlags();

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

bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
bool CheckProofOfWork(const uint256& hash, unsigned int nBits, const Consensus::Params& params)
{
if (g_solution_blocks) {
if (hash == params.hashGenesisBlock) return true;
SimpleSignatureChecker bsc(hash);
const auto& payload = g_blockheader_payload_map.at(hash);
CScript solution = CScript(payload.begin(), payload.end());
CScript challenge = CScript(params.blockscript.begin(), params.blockscript.end());
return VerifyScript(solution, challenge, nullptr, GetStandardScriptVerifyFlags(), bsc);
}

bool fNegative;
bool fOverflow;
arith_uint256 bnTarget;
Expand Down
2 changes: 1 addition & 1 deletion src/pow.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&);

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

#endif // BITCOIN_POW_H
4 changes: 4 additions & 0 deletions src/primitives/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
#include <utilstrencodings.h>
#include <crypto/common.h>

bool g_solution_blocks = false;
size_t g_solution_block_len = 0;
std::map<uint256,std::vector<uint8_t>> g_blockheader_payload_map;

uint256 CBlockHeader::GetHash() const
{
return SerializeHash(*this);
Expand Down
26 changes: 26 additions & 0 deletions src/primitives/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,23 @@
#include <serialize.h>
#include <uint256.h>

/**
* If true, block headers contain a payload equal to a Bitcoin Script solution
* to a signet challenge as defined in the chain params.
*/
extern bool g_solution_blocks;
/**
* If non-zero, defines an enforced size requirement for block header payloads.
* It requires that all blocks are of size 80 + (this value) bytes.
*/
extern size_t g_solution_block_len;

/**
* Contains a mapping of hash to signature data for each block header
* in signet networks.
*/
extern std::map<uint256,std::vector<uint8_t>> g_blockheader_payload_map;

/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
Expand Down Expand Up @@ -43,6 +60,15 @@ class CBlockHeader
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
if (g_solution_blocks && !(s.GetType() & SER_GETHASH)) {
READWRITE(g_blockheader_payload_map[GetHash()]);
size_t len = GetSizeOfCompactSize(g_blockheader_payload_map[GetHash()].size()) + g_blockheader_payload_map[GetHash()].size();
while (len < g_solution_block_len) {
uint8_t padding = 0;
READWRITE(padding);
len++;
}
}
}

void SetNull()
Expand Down
Loading