Skip to content

Commit

Permalink
Signet implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
kallewoof committed Mar 8, 2019
1 parent 4952a95 commit fb844eb
Show file tree
Hide file tree
Showing 32 changed files with 750 additions and 50 deletions.
76 changes: 76 additions & 0 deletions contrib/signet/issuer/issuer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/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

(( 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
(( rv=$RANDOM%$randinterval ))
(( rv=rv+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 @@ -383,6 +383,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
98 changes: 96 additions & 2 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
#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)
#include <hash.h>

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 +40,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 @@ -268,6 +276,88 @@ class CTestNetParams : public CChainParams {
}
};

/**
* SigNet version 2018-07-20
*/
class SigNetParams : public CChainParams {
public:
SigNetParams(const ArgsManager& args) {
if (!args.IsArgSet("-signet_blockscript") || !args.IsArgSet("-signet_siglen")) {
throw std::runtime_error(strprintf("%s: -signet_blockscript and -signet_siglen are both mandatory for signet networks", __func__));
}
if (args.GetArgs("-signet_blockscript").size() != 1) {
throw std::runtime_error(strprintf("%s: -signet_blockscript cannot be multiple values.", __func__));
}
if (args.GetArgs("-signet_siglen").size() != 1) {
throw std::runtime_error(strprintf("%s: -signet_siglen cannot be multiple values.", __func__));
}

LogPrintf("SigNet with block script %s\n", gArgs.GetArgs("-signet_blockscript")[0]);

strNetworkID = "signet";
consensus.signature_pow = true;
consensus.blockscript = ParseHex(args.GetArgs("-signet_blockscript")[0]);
consensus.siglen = g_solution_block_len = atoi64(args.GetArgs("-signet_siglen")[0]);
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 << 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);
consensus.hashGenesisBlock = genesis.GetHash();

vFixedSeeds.clear();
vSeeds.clear();
if (args.IsArgSet("-signet_seednode")) {
vSeeds = gArgs.GetArgs("-signet_seednode");
}

base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>{125};
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>{87};
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>{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
*/
Expand Down Expand Up @@ -409,6 +499,10 @@ std::unique_ptr<const CChainParams> CreateChainParams(const std::string& chain)
return std::unique_ptr<CChainParams>(new CTestNetParams());
else if (chain == CBaseChainParams::REGTEST)
return std::unique_ptr<CChainParams>(new CRegTestParams(gArgs));
else if (chain == CBaseChainParams::SIGNET) {
g_solution_blocks = true;
return std::unique_ptr<CChainParams>(new SigNetParams(gArgs));
}
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}

Expand Down
10 changes: 8 additions & 2 deletions src/chainparamsbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -21,6 +22,10 @@ void SetupChainParamsBaseOptions()
"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("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", true, 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<CBaseChainParams> globalChainBaseParams;
Expand All @@ -39,8 +44,9 @@ std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain
return MakeUnique<CBaseChainParams>("testnet3", 18332);
else if (chain == CBaseChainParams::REGTEST)
return MakeUnique<CBaseChainParams>("regtest", 18443);
else
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
else if (chain == CBaseChainParams::SIGNET)
return MakeUnique<CBaseChainParams>("signet", 38332);
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}

void SelectBaseParams(const std::string& chain)
Expand Down
3 changes: 2 additions & 1 deletion src/chainparamsbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
5 changes: 5 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ struct Params {
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
uint256 nMinimumChainWork;
uint256 defaultAssumeValid;

bool signature_pow{false};
std::vector<uint8_t> blockscript;
uint32_t siglen;
};

} // namespace Consensus

#endif // BITCOIN_CONSENSUS_PARAMS_H
4 changes: 4 additions & 0 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,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)
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/system.h>
#include <util/strencodings.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
6 changes: 5 additions & 1 deletion src/primitives/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
#include <util/strencodings.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);
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
}

std::string CBlock::ToString() const
Expand Down
Loading

0 comments on commit fb844eb

Please sign in to comment.