Signet implementation

This commit is contained in:
Karl-Johan Alm 2018-07-24 17:11:13 +09:00
parent 540bf8aacc
commit 5143d5ddc7
No known key found for this signature in database
GPG key ID: 57AF762DB3353322
20 changed files with 493 additions and 26 deletions

73
contrib/signet/issuer/issuer.sh Executable file
View file

@ -0,0 +1,73 @@
#!/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.
#
# 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 [ 1 ]; 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

View file

@ -13,14 +13,15 @@
#include <assert.h>
#include <chainparamsseeds.h>
#include <hash.h>
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;
@ -35,6 +36,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
@ -274,6 +281,89 @@ public:
}
};
/**
* 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") || !args.count("signet_seednode")) {
throw std::runtime_error(strprintf("%s: Signet requires -signet_blockscript, -signet_siglen, and -signet_seednode 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 = atoi(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 = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
// Deployment of BIP68, BIP112, and BIP113.
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1230767999; // December 31, 2008
// Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1230767999; // December 31, 2008
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();
vSeeds = args.at("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
*/
@ -361,7 +451,7 @@ const CChainParams &Params() {
return *globalChainParams;
}
std::unique_ptr<CChainParams> CreateChainParams(const std::string& chain)
std::unique_ptr<CChainParams> CreateChainParams(const std::string& chain, const ChainParamArgs& args)
{
if (chain == CBaseChainParams::MAIN)
return std::unique_ptr<CChainParams>(new CMainParams());
@ -369,13 +459,32 @@ std::unique_ptr<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());
else if (chain == CBaseChainParams::SIGNET) {
g_solution_blocks = true;
return std::unique_ptr<CChainParams>(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)

View file

@ -102,12 +102,14 @@ protected:
bool m_fallback_fee_enabled;
};
typedef std::map<std::string,std::vector<std::string>> ChainParamArgs;
/**
* Creates and returns a std::unique_ptr<CChainParams> 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<CChainParams> CreateChainParams(const std::string& chain);
std::unique_ptr<CChainParams> CreateChainParams(const std::string& chain, const ChainParamArgs& args=ChainParamArgs());
/**
* Return the currently selected parameters. This won't change after app

View file

@ -13,6 +13,7 @@
const std::string CBaseChainParams::MAIN = "main";
const std::string CBaseChainParams::TESTNET = "test";
const std::string CBaseChainParams::SIGNET = "sig";
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<CBaseChainParams> globalChainBaseParams;
@ -38,8 +43,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)

View file

@ -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; }

View file

@ -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

View file

@ -9,6 +9,8 @@
#include <chain.h>
#include <primitives/block.h>
#include <uint256.h>
#include <script/interpreter.h>
#include <policy/policy.h>
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
@ -71,8 +73,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;
BlockSignatureChecker 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, STANDARD_SCRIPT_VERIFY_FLAGS, bsc);
}
bool fNegative;
bool fOverflow;
arith_uint256 bnTarget;

View file

@ -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

View file

@ -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);

View file

@ -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
@ -30,6 +47,7 @@ public:
CBlockHeader()
{
nVersion = 0;
SetNull();
}
@ -43,6 +61,15 @@ public:
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()

View file

@ -114,16 +114,16 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
{
AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
result.pushKV("hash", block.GetHash().GetHex());
int confirmations = -1;
// Only report confirmations if the block is on the main chain
if (chainActive.Contains(blockindex))
if (blockindex && chainActive.Contains(blockindex))
confirmations = chainActive.Height() - blockindex->nHeight + 1;
result.pushKV("confirmations", confirmations);
result.pushKV("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS));
result.pushKV("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION));
result.pushKV("weight", (int)::GetBlockWeight(block));
result.pushKV("height", blockindex->nHeight);
if (blockindex) result.pushKV("height", blockindex->nHeight);
result.pushKV("version", block.nVersion);
result.pushKV("versionHex", strprintf("%08x", block.nVersion));
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
@ -141,18 +141,23 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
}
result.pushKV("tx", txs);
result.pushKV("time", block.GetBlockTime());
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
if (blockindex) result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
result.pushKV("nonce", (uint64_t)block.nNonce);
result.pushKV("bits", strprintf("%08x", block.nBits));
result.pushKV("difficulty", GetDifficulty(blockindex));
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
result.pushKV("nTx", (uint64_t)blockindex->nTx);
if (blockindex) result.pushKV("difficulty", GetDifficulty(blockindex));
if (blockindex) result.pushKV("chainwork", blockindex->nChainWork.GetHex());
if (blockindex) result.pushKV("nTx", (uint64_t)blockindex->nTx);
if (blockindex->pprev)
if (blockindex && blockindex->pprev)
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
CBlockIndex *pnext = chainActive.Next(blockindex);
if (pnext)
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
if (blockindex) {
CBlockIndex *pnext = chainActive.Next(blockindex);
if (pnext)
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
}
if (g_solution_blocks && g_blockheader_payload_map.count(block.GetHash())) {
result.pushKV("signet-solution", HexStr(g_blockheader_payload_map.at(block.GetHash())));
}
return result;
}

View file

@ -55,6 +55,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getbalance", 1, "minconf" },
{ "getbalance", 2, "include_watchonly" },
{ "getblockhash", 0, "height" },
{ "getnewblockhex", 0, "broadcast" },
{ "waitforblockheight", 0, "height" },
{ "waitforblockheight", 1, "timeout" },
{ "waitforblock", 1, "timeout" },

View file

@ -694,7 +694,7 @@ protected:
}
};
static UniValue submitblock(const JSONRPCRequest& request)
UniValue submitblock(const JSONRPCRequest& request)
{
// We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
@ -724,6 +724,11 @@ static UniValue submitblock(const JSONRPCRequest& request)
}
uint256 hash = block.GetHash();
if (!request.params[1].isNull()) {
g_blockheader_payload_map[hash] = ParseHex(request.params[1].get_str());
}
{
LOCK(cs_main);
const CBlockIndex* pindex = LookupBlockIndex(hash);
@ -978,7 +983,6 @@ static const CRPCCommand commands[] =
{ "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
{ "mining", "submitheader", &submitheader, {"hexdata"} },
{ "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
{ "hidden", "estimatefee", &estimatefee, {} },

View file

@ -1416,6 +1416,22 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
template class GenericTransactionSignatureChecker<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;
bool BlockSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
return false;
// Hash type is one byte tacked on to the end of the signature
std::vector<unsigned char> vchSig(vchSigIn);
if (vchSig.empty())
return false;
// int nHashType = vchSig.back();
vchSig.pop_back();
return pubkey.Verify(hash, vchSig);
}
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
std::vector<std::vector<unsigned char> > stack;

View file

@ -162,6 +162,17 @@ public:
virtual ~BaseSignatureChecker() {}
};
class BlockSignatureChecker : public BaseSignatureChecker
{
private:
uint256 hash;
public:
const uint256& GetHash() const { return hash; }
BlockSignatureChecker(const uint256& hash_in) : hash(hash_in) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
};
template <class T>
class GenericTransactionSignatureChecker : public BaseSignatureChecker
{

View file

@ -32,6 +32,15 @@ bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provid
return true;
}
bool BlockSignatureCreator::CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const
{
CKey key;
if (!provider.GetKey(keyid, key)) return false;
if (!key.Sign(checker.GetHash(), vchSig)) return false;
vchSig.push_back((unsigned char)SIGHASH_ALL);
return true;
}
static bool GetCScript(const SigningProvider& provider, const SignatureData& sigdata, const CScriptID& scriptid, CScript& script)
{
if (provider.GetCScript(scriptid, script)) {

View file

@ -66,6 +66,16 @@ public:
virtual bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;
};
class BlockSignatureCreator : public BaseSignatureCreator
{
BlockSignatureChecker checker;
public:
BlockSignatureCreator(const uint256& hashIn) : BaseSignatureCreator(), checker(hashIn) {};
const BaseSignatureChecker& Checker() const override { return checker; }
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
};
/** A signature creator for transactions. */
class MutableTransactionSignatureCreator : public BaseSignatureCreator {
const CMutableTransaction* txTo;

View file

@ -274,7 +274,9 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
pindexNew->nStatus = diskindex.nStatus;
pindexNew->nTx = diskindex.nTx;
if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams))
// Block index guts do not include the payload, so we cannot check the POW for
// signets here
if (!consensusParams.signature_pow && !CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams))
return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
pcursor->Next();

View file

@ -950,13 +950,16 @@ std::string ArgsManager::GetChainName() const
{
bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest");
bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet");
bool signet = ArgsManagerHelper::GetNetBoolArg(*this, "-signet");
if (fTestNet && fRegTest)
throw std::runtime_error("Invalid combination of -regtest and -testnet.");
if (fTestNet + fRegTest + signet > 1)
throw std::runtime_error("Invalid combination of -regtest, -testnet, and -signet.");
if (fRegTest)
return CBaseChainParams::REGTEST;
if (fTestNet)
return CBaseChainParams::TESTNET;
if (signet)
return CBaseChainParams::SIGNET;
return CBaseChainParams::MAIN;
}

View file

@ -3887,6 +3887,100 @@ static UniValue bumpfee(const JSONRPCRequest& request)
return result;
}
void SignBlockHashWithWallet(const uint256& hash, CWallet* const pwallet)
{
SignatureData solution_in;
if (g_blockheader_payload_map.count(hash) && g_blockheader_payload_map.at(hash).size()) {
solution_in = SignatureData(CScript(g_blockheader_payload_map[hash].begin(), g_blockheader_payload_map[hash].end()));
}
CScript blockscript(Params().GetConsensus().blockscript.begin(), Params().GetConsensus().blockscript.end());
size_t siglen = gArgs.GetArg("-signet_siglen", 0);
// sign until we have a sufficiently small signature, or until we run out of tries
bool res;
size_t smallest = 9999;
std::vector<uint8_t> sigdata;
size_t overhead = GetSizeOfCompactSize(siglen);
for (size_t i = 0; i < 1000; ++i) {
SignatureData solution(solution_in);
res = ProduceSignature(*pwallet, BlockSignatureCreator(hash), blockscript, solution);
if (!res) {
throw JSONRPCError(RPC_VERIFY_ERROR, "could not produce a signature -- do you have the private key(s)?");
}
if (solution.scriptSig.size() < smallest) {
smallest = solution.scriptSig.size();
if (!siglen || smallest + overhead <= siglen) {
sigdata = std::vector<uint8_t>(solution.scriptSig.begin(), solution.scriptSig.end());
break;
}
}
}
if (siglen && sigdata.size() == 0) {
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("unable to produce a signature of size <= %zu (smallest found was %zu)", siglen, smallest + overhead));
}
g_blockheader_payload_map[hash] = sigdata;
}
UniValue signblock(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (!g_solution_blocks) {
throw std::runtime_error(
"signblock can only be used with signet networks"
);
}
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"signblock \"blockhex\"\n"
"\nSigns a block proposal, checking that it would be accepted first\n"
"\nArguments:\n"
"1. \"blockhex\" (string, required) The hex-encoded block from getnewblockhex\n"
"\nResult\n"
" sig (hex) The signature\n"
"\nExamples:\n"
+ HelpExampleCli("signblock", "0000002018c6f2f913f9902aeab...5ca501f77be96de63f609010000000000000000015100000000")
);
}
CBlock block;
if (!DecodeHexBlk(block, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
}
LOCK(cs_main);
uint256 hash = block.GetHash();
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) {
throw JSONRPCError(RPC_VERIFY_ERROR, "already have block");
}
CBlockIndex* const pindexPrev = chainActive.Tip();
// TestBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != pindexPrev->GetBlockHash()) {
throw JSONRPCError(RPC_VERIFY_ERROR, "proposal was not based on our best chain");
}
CValidationState state;
if (!TestBlockValidity(state, Params(), block, pindexPrev, false, true) || !state.IsValid()) {
std::string strRejectReason = state.GetRejectReason();
if (strRejectReason.empty()) {
throw JSONRPCError(RPC_VERIFY_ERROR, state.IsInvalid() ? "Block proposal was invalid" : "Error checking block proposal");
}
throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason);
}
SignBlockHashWithWallet(hash, pwallet);
return HexStr(g_blockheader_payload_map.at(hash));
}
UniValue generate(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@ -3934,6 +4028,76 @@ UniValue generate(const JSONRPCRequest& request)
return generateBlocks(coinbase_script, num_generate, max_tries, true);
}
#include <miner.h>
UniValue getnewblockhex(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() > 1) {
throw std::runtime_error(
"getnewblockhex ( broadcast )\n"
"\nGets hex representation of a proposed, unmined new block, optionally\n"
"signing and broadcasting it to the network.\n"
"\nArguments:\n"
"1. broadcast (boolean, optional, default=false) Sign and broadcast the block immediately, returning the blockhash\n"
"\nResult (for broadcast=false)\n"
"blockhex (hex) The block hex\n"
"\nResult (for broadcast=true)\n"
"blockhash (hash) The block hash\n"
"\nExamples:\n"
+ HelpExampleCli("getnewblockhex", "")
+ HelpExampleCli("getnewblockhex true", "")
);
}
bool broadcast = !request.params[0].isNull() && request.params[0].get_bool();
std::shared_ptr<CReserveScript> coinbase_script;
pwallet->GetScriptForMining(coinbase_script);
// If the keypool is exhausted, no script is returned at all. Catch this.
if (!coinbase_script) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
//throw an error if no script was provided
if (coinbase_script->reserveScript.empty()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available");
}
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbase_script->reserveScript));
{
// IncrementExtraNonce sets coinbase flags and builds merkle tree
LOCK(cs_main);
unsigned int nExtraNonce = 0;
IncrementExtraNonce(&pblocktemplate->block, chainActive.Tip(), nExtraNonce);
}
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
ssBlock << pblocktemplate->block;
if (broadcast) {
// attempt to sign
uint256 hash = pblocktemplate->block.GetHash();
SignBlockHashWithWallet(hash, pwallet);
// and submit
UniValue submitblock(const JSONRPCRequest& request);
UniValue params(UniValue::VARR);
params.push_back(HexStr(ssBlock.begin(), ssBlock.end()));
params.push_back(HexStr(g_blockheader_payload_map.at(hash).begin(), g_blockheader_payload_map.at(hash).end()));
JSONRPCRequest req;
req.params = params;
return submitblock(req);
}
return HexStr(ssBlock.begin(), ssBlock.end());
}
UniValue rescanblockchain(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@ -4839,6 +5003,10 @@ static const CRPCCommand commands[] =
{ "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
{ "wallet", "setlabel", &setlabel, {"address","label"} },
// sigtest mining
{ "wallet", "signblock", &signblock, {"blockhex"} },
{ "mining", "getnewblockhex", &getnewblockhex, {"broadcast"} },
{ "generating", "generate", &generate, {"nblocks","maxtries"} },
};