diff --git a/contrib/signet/issuer/issuer.sh b/contrib/signet/issuer/issuer.sh new file mode 100755 index 000000000000..f21a9153d780 --- /dev/null +++ b/contrib/signet/issuer/issuer.sh @@ -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 []" ; 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 + 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 diff --git a/src/chain.h b/src/chain.h index 01011d54f19b..5ebac95290e9 100644 --- a/src/chain.h +++ b/src/chain.h @@ -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 diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 93bb3e764746..6f78e1b7c09c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -14,13 +14,15 @@ #include -static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) +#include + +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((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; @@ -35,6 +37,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((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 @@ -274,6 +282,91 @@ class CTestNetParams : public CChainParams { } }; +/** + * SigNet version 2018-07-20 + */ +class SigNetParams : public CChainParams { +public: + SigNetParams(const ChainParamArgs& args) { + for (const auto& a : args) { + for (const auto& b : a.second) { + printf("%s : %s\n", a.first.c_str(), b.c_str()); + } + } + if (!args.count("signet_blockscript") || !args.count("signet_siglen")) { + throw std::runtime_error(strprintf("%s: Signet requires -signet_blockscript and -signet_siglen provided.", __func__)); + } + if (args.at("signet_blockscript").size() != 1) { + throw std::runtime_error(strprintf("%s: -signet_blockscript cannot be multiple values.", __func__)); + } + if (args.at("signet_siglen").size() != 1) { + throw std::runtime_error(strprintf("%s: -signet_siglen cannot be multiple values.", __func__)); + } + + strNetworkID = "signet"; + consensus.blockscript = ParseHex(args.at("signet_blockscript")[0]); + g_solution_block_len = consensus.siglen = atoi64(args.at("signet_siglen")[0]); + consensus.signature_pow = true; + consensus.nSubsidyHalvingInterval = 210000; + consensus.BIP34Height = 1; + consensus.BIP65Height = 1; + consensus.BIP66Height = 1; + consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks + consensus.nPowTargetSpacing = 10 * 60; + consensus.fPowAllowMinDifficultyBlocks = false; + consensus.fPowNoRetargeting = false; + consensus.nRuleChangeActivationThreshold = 1916; + consensus.nMinerConfirmationWindow = 2016; + consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1539478800; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + + // Deployment of BIP68, BIP112, and BIP113. + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1539478800; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + + // Deployment of SegWit (BIP141, BIP143, and BIP147) + consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1; + consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1539478800; + consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + + pchMessageStart[0] = 0xf0; + pchMessageStart[1] = 0xc7; + pchMessageStart[2] = 0x70; + pchMessageStart[3] = 0x6a; + nDefaultPort = 38333; + nPruneAfterHeight = 1000; + + CHashWriter h(SER_DISK, 0); + h << strNetworkID; + h << consensus.blockscript << consensus.siglen; + uint256 hash = h.GetHash(); + CScript coinbase_sig = CScript() << std::vector(hash.begin(), hash.end()); + genesis = CreateGenesisBlock(coinbase_sig, CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN); + consensus.hashGenesisBlock = genesis.GetHash(); + + vFixedSeeds.clear(); + vSeeds.clear(); + if (args.count("signet_seednode")) { + vSeeds = args.at("signet_seednode"); + } + + base58Prefixes[PUBKEY_ADDRESS] = std::vector{125}; + base58Prefixes[SCRIPT_ADDRESS] = std::vector{87}; + base58Prefixes[SECRET_KEY] = std::vector{217}; + base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; + base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; + + bech32_hrp = "sb"; + + fDefaultConsistencyChecks = false; + fRequireStandard = false; + fMineBlocksOnDemand = false; + } +}; + /** * Regression test */ @@ -361,7 +454,7 @@ const CChainParams &Params() { return *globalChainParams; } -std::unique_ptr CreateChainParams(const std::string& chain) +std::unique_ptr CreateChainParams(const std::string& chain, const ChainParamArgs& args) { if (chain == CBaseChainParams::MAIN) return std::unique_ptr(new CMainParams()); @@ -369,13 +462,32 @@ std::unique_ptr CreateChainParams(const std::string& chain) return std::unique_ptr(new CTestNetParams()); else if (chain == CBaseChainParams::REGTEST) return std::unique_ptr(new CRegTestParams()); + else if (chain == CBaseChainParams::SIGNET) { + g_solution_blocks = true; + return std::unique_ptr(new SigNetParams(args)); + } throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); } void SelectParams(const std::string& network) { + ChainParamArgs chain_args; + if (gArgs.IsArgSet("-signet_blockscript") && gArgs.IsArgSet("-signet_siglen")) { + chain_args["signet_blockscript"] = gArgs.GetArgs("-signet_blockscript"); + chain_args["signet_siglen"] = gArgs.GetArgs("-signet_siglen"); + if (gArgs.IsArgSet("-signet_seednode")) { + chain_args["signet_seednode"] = gArgs.GetArgs("-signet_seednode"); + } + } else { + chain_args["signet_blockscript"].push_back("512103e464a9f3070da4d3e0b34ce971ff36f3e07c47a8f4beadf32e8ea7e2afa8a82451ae"); + chain_args["signet_siglen"].push_back("77"); + if (!gArgs.IsArgSet("-signet_seednode")) { + chain_args["signet_seednode"].push_back("178.128.221.177"); // DG seed node + } + } + SelectBaseParams(network); - globalChainParams = CreateChainParams(network); + globalChainParams = CreateChainParams(network, chain_args); } void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) diff --git a/src/chainparams.h b/src/chainparams.h index 722e52ff40f5..d295f74281aa 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -102,12 +102,14 @@ class CChainParams bool m_fallback_fee_enabled; }; +typedef std::map> ChainParamArgs; + /** * Creates and returns a std::unique_ptr of the chosen chain. * @returns a CChainParams* of the chosen chain. * @throws a std::runtime_error if the chain is not supported. */ -std::unique_ptr CreateChainParams(const std::string& chain); +std::unique_ptr CreateChainParams(const std::string& chain, const ChainParamArgs& args=ChainParamArgs()); /** * Return the currently selected parameters. This won't change after app diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index e9e8ce03b419..0529417b95d5 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -13,6 +13,7 @@ const std::string CBaseChainParams::MAIN = "main"; const std::string CBaseChainParams::TESTNET = "test"; +const std::string CBaseChainParams::SIGNET = "signet"; const std::string CBaseChainParams::REGTEST = "regtest"; void SetupChainParamsBaseOptions() @@ -20,6 +21,10 @@ 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("-signet", "Use the signet chain. Note that the network is defined by the signet_blockscript and signet_siglen parameters", false, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-signet_blockscript", "Blocks must satisfy the given script to be considered valid (only for -signet networks)", false, 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", false, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-signet_seednode", "Specify a seed node for the signet network (may be used multiple times to specify multiple seed nodes)", false, OptionsCategory::CHAINPARAMS); } static std::unique_ptr globalChainBaseParams; @@ -38,8 +43,9 @@ std::unique_ptr CreateBaseChainParams(const std::string& chain return MakeUnique("testnet3", 18332); else if (chain == CBaseChainParams::REGTEST) return MakeUnique("regtest", 18443); - else - throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); + else if (chain == CBaseChainParams::SIGNET) + return MakeUnique("signet", 38332); + throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); } void SelectBaseParams(const std::string& chain) diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index 355df043d39e..ed21323146d7 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -16,9 +16,10 @@ class CBaseChainParams { public: - /** BIP70 chain name strings (main, test or regtest) */ + /** BIP70 chain name strings (main, test (, sigtest) or regtest) */ static const std::string MAIN; static const std::string TESTNET; + static const std::string SIGNET; static const std::string REGTEST; const std::string& DataDir() const { return strDataDir; } diff --git a/src/consensus/params.h b/src/consensus/params.h index 6c3a201f4f5f..560317d4c349 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -75,7 +75,12 @@ struct Params { int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; } uint256 nMinimumChainWork; uint256 defaultAssumeValid; + + bool signature_pow{false}; + std::vector blockscript; + uint32_t siglen; }; + } // namespace Consensus #endif // BITCOIN_CONSENSUS_PARAMS_H diff --git a/src/miner.cpp b/src/miner.cpp index 6d35f9ac37d6..02faa2c466d3 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -55,6 +55,10 @@ 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) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index b8f7963a0cb4..623e6d0a5ccf 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -14,6 +14,7 @@ #include #include +unsigned int GetStandardScriptVerifyFlags() { return STANDARD_SCRIPT_VERIFY_FLAGS; } CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn) { diff --git a/src/policy/policy.h b/src/policy/policy.h index 3d47ac126762..28e9eb1877b2 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -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; diff --git a/src/pow.cpp b/src/pow.cpp index 1414d3756492..ef7dfba9e0cc 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -9,6 +9,9 @@ #include #include #include +#include