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

Refactor: Easier support for chains with multiple genesis assets #164

Closed
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
74 changes: 54 additions & 20 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "util.h"
#include "utilstrencodings.h"
#include "amount.h"
#include "crypto/ripemd160.h"

#include <assert.h>

Expand All @@ -18,6 +19,20 @@

#include "chainparamsseeds.h"

static const uint32_t MAX_GENESIS_OUTPUTS = 500;

// Safer for users if they load incorrect parameters via arguments.
static std::vector<unsigned char> CommitToArguments(const Consensus::Params& params, const std::string& networkID)
{
CRIPEMD160 ripemd;
unsigned char commitment[20];
ripemd.Write((const unsigned char*)networkID.c_str(), networkID.length());
ripemd.Write((const unsigned char*)HexStr(params.fedpegScript).c_str(), HexStr(params.fedpegScript).length());
ripemd.Write((const unsigned char*)HexStr(params.signblockScript).c_str(), HexStr(params.signblockScript).length());
ripemd.Finalize(commitment);
return std::vector<unsigned char>(commitment, commitment + 20);
}

static CScript StrHexToScriptWithDefault(std::string strScript, const CScript defaultScript)
{
CScript returnScript;
Expand All @@ -30,24 +45,43 @@ static CScript StrHexToScriptWithDefault(std::string strScript, const CScript de
return returnScript;
}

static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, const CScript& scriptChallenge, int32_t nVersion, const CAmount& genesisReward, const uint32_t rewardShards, const CAsset& asset)
struct GenesisReward
{
const CAmount nTotalAmount;
const CScript outputScript;
const CAsset asset;
const uint32_t nShards;

GenesisReward(const CAmount& nTotalAmountIn, const CScript& outputScriptIn, const CAsset& assetIn, const uint32_t nShardsIn=1) :
nTotalAmount(nTotalAmountIn), outputScript(outputScriptIn), asset(assetIn), nShards(nShardsIn) {};
};

static CBlock CreateGenesisBlock(const Consensus::Params& params, const std::string& networkID, uint32_t nTime, int32_t nVersion, const std::vector<GenesisReward>& genesisRewards)
{
// Shards must be evenly divisible
assert(MAX_MONEY % rewardShards == 0);
CMutableTransaction txNew;
txNew.nVersion = 1;
txNew.vin.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.vout.resize(rewardShards);
for (unsigned int i = 0; i < rewardShards; i++) {
txNew.vout[i].nValue = genesisReward/rewardShards;
txNew.vout[i].nAsset = asset;
txNew.vout[i].scriptPubKey = genesisOutputScript;
// Any consensus-related values that are command-line set can be added here for anti-footgun
txNew.vin[0].scriptSig = CScript(CommitToArguments(params, networkID));

unsigned int totalOutputs = 0;
for (GenesisReward gReward : genesisRewards) totalOutputs += gReward.nShards;
assert(totalOutputs <= MAX_GENESIS_OUTPUTS);
txNew.vout.resize(totalOutputs);

for (GenesisReward gReward : genesisRewards) {
for (unsigned int i = 0; i < gReward.nShards; i++) {
// Shards must be evenly divisible
assert(gReward.nTotalAmount % gReward.nShards == 0);
txNew.vout[i].nValue = gReward.nTotalAmount / gReward.nShards;
txNew.vout[i].nAsset = gReward.asset;
txNew.vout[i].scriptPubKey = gReward.outputScript;
}
}

CBlock genesis;
genesis.nTime = nTime;
genesis.proof = CProof(scriptChallenge, CScript());
genesis.proof = CProof(CScript());
genesis.nVersion = nVersion;
genesis.vtx.push_back(txNew);
genesis.hashPrevBlock.SetNull();
Expand All @@ -72,7 +106,7 @@ class CElementsParams : public CChainParams {
CScript defaultSignblockScript;
// Default blocksign script for elements
defaultSignblockScript = CScript() << OP_2 << ParseHex("03206b45265ae687dfdc602b8faa7dd749d7865b0e51f986e12c532229f0c998be") << ParseHex("02cc276552e180061f64dc16e2a02e7f9ecbcc744dea84eddbe991721824df825c") << ParseHex("0204c6be425356d9200a3303d95f2c39078cc9473ca49619da1e0ec233f27516ca") << OP_3 << OP_CHECKMULTISIG;
CScript genesisChallengeScript = StrHexToScriptWithDefault(GetArg("-signblockscript", "", mapArgs), defaultSignblockScript);
consensus.signblockScript = StrHexToScriptWithDefault(GetArg("-signblockscript", "", mapArgs), defaultSignblockScript);
CScript defaultFedpegScript;
defaultFedpegScript = CScript() << OP_2 << ParseHex("02d51090b27ca8f1cc04984614bd749d8bab6f2a3681318d3fd0dd43b2a39dd774") << ParseHex("03a75bd7ac458b19f98047c76a6ffa442e592148c5d23a1ec82d379d5d558f4fd8") << ParseHex("034c55bede1bce8e486080f8ebb7a0e8f106b49efb295a8314da0e1b1723738c66") << OP_3 << OP_CHECKMULTISIG;
consensus.fedpegScript = StrHexToScriptWithDefault(GetArg("-fedpegscript", "", mapArgs), defaultFedpegScript);
Expand Down Expand Up @@ -123,12 +157,12 @@ class CElementsParams : public CChainParams {
nDefaultPort = 9042;
nPruneAfterHeight = 100000;

// SHA256 of Bitcoin genesis mainnet hash for NUMS bitcoin asset id
bitcoinID = BITCOINID;

parentGenesisBlockHash = uint256S("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
CScript scriptDestination(CScript() << std::vector<unsigned char>(parentGenesisBlockHash.begin(), parentGenesisBlockHash.end()) << OP_WITHDRAWPROOFVERIFY);
genesis = CreateGenesisBlock(strNetworkID.c_str(), scriptDestination, 1231006505, genesisChallengeScript, 1, MAX_MONEY, 100, bitcoinID);
const std::vector<GenesisReward> genesisRewards = {
GenesisReward(MAX_MONEY, scriptDestination, BITCOINID, 100),
};
genesis = CreateGenesisBlock(consensus, strNetworkID, 1231006505, 1, genesisRewards);
consensus.hashGenesisBlock = genesis.GetHash();

scriptCoinbaseDestination = CScript() << ParseHex("0229536c4c83789f59c30b93eb40d4abbd99b8dcc99ba8bd748f29e33c1d279e3c") << OP_CHECKSIG;
Expand Down Expand Up @@ -195,7 +229,7 @@ class CRegTestParams : public CChainParams {
void Reset(const std::map<std::string, std::string>& mapArgs)
{
const CScript defaultRegtestScript(CScript() << OP_TRUE);
CScript genesisChallengeScript = StrHexToScriptWithDefault(GetArg("-signblockscript", "", mapArgs), defaultRegtestScript);
consensus.signblockScript = StrHexToScriptWithDefault(GetArg("-signblockscript", "", mapArgs), defaultRegtestScript);
consensus.fedpegScript = StrHexToScriptWithDefault(GetArg("-fedpegscript", "", mapArgs), defaultRegtestScript);

strNetworkID = CHAINPARAMS_REGTEST;
Expand Down Expand Up @@ -230,10 +264,10 @@ class CRegTestParams : public CChainParams {
nDefaultPort = 7042;
nPruneAfterHeight = 1000;

// SHA256 of Bitcoin genesis mainnet hash for NUMS bitcoin asset id
bitcoinID = BITCOINID;

genesis = CreateGenesisBlock(strNetworkID.c_str(), defaultRegtestScript, 1296688602, genesisChallengeScript, 1, MAX_MONEY, 100, bitcoinID);
const std::vector<GenesisReward> genesisRewards = {
GenesisReward(MAX_MONEY, consensus.fedpegScript, BITCOINID, 100),
};
genesis = CreateGenesisBlock(consensus, strNetworkID, 1296688602, 1, genesisRewards);
consensus.hashGenesisBlock = genesis.GetHash();

parentGenesisBlockHash = uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206");
Expand Down
1 change: 0 additions & 1 deletion src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ class CChainParams
std::string strNetworkID;
CBlock genesis;
uint256 parentGenesisBlockHash;
CAsset bitcoinID;
std::vector<SeedSpec6> vFixedSeeds;
bool fMiningRequiresPeers;
bool fDefaultConsistencyChecks;
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ struct Params {
int64_t nPowTargetTimespan;
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
CScript fedpegScript;
CScript signblockScript;
};
} // namespace Consensus

Expand Down
2 changes: 1 addition & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0)
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
return InitError(_("Incorrect or no genesis block found. Wrong `-fedpegscript`, `-signblockscript`, or datadir for network?"));

// Initialize the block index (no-op if non-empty database was already loaded)
if (!InitBlockIndex(chainparams)) {
Expand Down
23 changes: 6 additions & 17 deletions src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,20 @@
#include "wallet/wallet.h"
#endif

CScript CombineBlockSignatures(const CBlockHeader& header, const CScript& scriptSig1, const CScript& scriptSig2)
CScript CombineBlockSignatures(const Consensus::Params& params, const CBlockHeader& header, const CScript& scriptSig1, const CScript& scriptSig2)
{
SignatureData sig1(scriptSig1);
SignatureData sig2(scriptSig2);
return GenericCombineSignatures(header.proof.challenge, header, sig1, sig2).scriptSig;
return GenericCombineSignatures(params.signblockScript, header, sig1, sig2).scriptSig;
}

bool CheckChallenge(const CBlockHeader& block, const CBlockIndex& indexLast, const Consensus::Params& params)
{
return block.proof.challenge == indexLast.proof.challenge;
return true;
}

void ResetChallenge(CBlockHeader& block, const CBlockIndex& indexLast, const Consensus::Params& params)
{
block.proof.challenge = indexLast.proof.challenge;
}

bool CheckBitcoinProof(const Sidechain::Bitcoin::CBlockHeader& block)
Expand All @@ -61,14 +60,14 @@ bool CheckProof(const CBlockHeader& block, const Consensus::Params& params)
{
if (block.GetHash() == params.hashGenesisBlock)
return true;
return GenericVerifyScript(block.proof.solution, block.proof.challenge, SCRIPT_VERIFY_P2SH, block);
return GenericVerifyScript(block.proof.solution, params.signblockScript, SCRIPT_VERIFY_P2SH, block);
}

bool MaybeGenerateProof(CBlockHeader *pblock, CWallet *pwallet)
bool MaybeGenerateProof(const Consensus::Params& params, CBlockHeader *pblock, CWallet *pwallet)
{
#ifdef ENABLE_WALLET
SignatureData solution(pblock->proof.solution);
bool res = GenericSignScript(*pwallet, *pblock, pblock->proof.challenge, solution);
bool res = GenericSignScript(*pwallet, *pblock, params.signblockScript, solution);
pblock->proof.solution = solution.scriptSig;
return res;
#endif
Expand All @@ -85,16 +84,6 @@ double GetChallengeDifficulty(const CBlockIndex* blockindex)
return 1;
}

std::string GetChallengeStr(const CBlockIndex& block)
{
return ScriptToAsmStr(block.proof.challenge);
}

std::string GetChallengeStrHex(const CBlockIndex& block)
{
return ScriptToAsmStr(block.proof.challenge);
}

uint32_t GetNonce(const CBlockHeader& block)
{
return 1;
Expand Down
6 changes: 2 additions & 4 deletions src/pow.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,15 @@ class uint256;
bool CheckBitcoinProof(const Sidechain::Bitcoin::CBlockHeader& block);
bool CheckProof(const CBlockHeader& block, const Consensus::Params&);
/** Scans nonces looking for a hash with at least some zero bits */
bool MaybeGenerateProof(CBlockHeader* pblock, CWallet* pwallet);
bool MaybeGenerateProof(const Consensus::Params& params, CBlockHeader* pblock, CWallet* pwallet);
void ResetProof(CBlockHeader& block);
bool CheckChallenge(const CBlockHeader& block, const CBlockIndex& indexLast, const Consensus::Params&);
void ResetChallenge(CBlockHeader& block, const CBlockIndex& indexLast, const Consensus::Params&);

CScript CombineBlockSignatures(const CBlockHeader& header, const CScript& scriptSig1, const CScript& scriptSig2);
CScript CombineBlockSignatures(const Consensus::Params& params, const CBlockHeader& header, const CScript& scriptSig1, const CScript& scriptSig2);

/** Avoid using these functions when possible */
double GetChallengeDifficulty(const CBlockIndex* blockindex);
std::string GetChallengeStr(const CBlockIndex& block);
std::string GetChallengeStrHex(const CBlockIndex& block);
uint32_t GetNonce(const CBlockHeader& block);
void SetNonce(CBlockHeader& block, uint32_t nNonce);

Expand Down
4 changes: 2 additions & 2 deletions src/primitives/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

std::string CProof::ToString() const
{
return strprintf("CProof(challenge=%s, solution=%s)",
ScriptToAsmStr(challenge), ScriptToAsmStr(solution));
return strprintf("CProof(solution=%s)",
ScriptToAsmStr(solution));
}

uint256 CBlockHeader::GetHash() const
Expand Down
7 changes: 2 additions & 5 deletions src/primitives/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,31 @@
class CProof
{
public:
CScript challenge;
CScript solution;

CProof()
{
SetNull();
}
CProof(CScript challengeIn, CScript solutionIn) : challenge(challengeIn), solution(solutionIn) {}
CProof(CScript solutionIn) : solution(solutionIn) {}

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
{
READWRITE(*(CScriptBase*)(&challenge));
if (!(nType & SER_GETHASH))
READWRITE(*(CScriptBase*)(&solution));
}

void SetNull()
{
challenge.clear();
solution.clear();
}

bool IsNull() const
{
return challenge.empty();
return solution.empty();
}

std::string ToString() const;
Expand Down
9 changes: 6 additions & 3 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "checkpoints.h"
#include "coins.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "main.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
Expand Down Expand Up @@ -62,7 +63,6 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.push_back(Pair("time", (int64_t)blockindex->nTime));
result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
result.push_back(Pair("nonce", (uint64_t)GetNonce(blockindex->GetBlockHeader())));
result.push_back(Pair("bits", GetChallengeStr(blockindex->GetBlockHeader())));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));

Expand Down Expand Up @@ -106,7 +106,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("time", block.GetBlockTime()));
result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
result.push_back(Pair("nonce", (uint64_t)GetNonce(block)));
result.push_back(Pair("bits", GetChallengeStr(block)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));

Expand Down Expand Up @@ -843,6 +842,8 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
"\nResult:\n"
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"signblockhex\": \"xxxx\", (string) the scriptPubKey for signing blocks as a hex string.\n"
" \"signblockasm\": \"xxxx\", (string) the scriptPubKey for signing blocks in a format more readable for humans (asm).\n"
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
" \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
" \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
Expand Down Expand Up @@ -879,10 +880,13 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getblockchaininfo", "")
);

const Consensus::Params& consensusParams = Params().GetConsensus();
LOCK(cs_main);

UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("signblockhex", HexStr(consensusParams.signblockScript)));
obj.push_back(Pair("signblockasm", ScriptToAsmStr(consensusParams.signblockScript)));
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
Expand All @@ -892,7 +896,6 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
obj.push_back(Pair("pruned", fPruneMode));

const Consensus::Params& consensusParams = Params().GetConsensus();
UniValue bip9_softforks(UniValue::VOBJ);
BIP9SoftForkDescPushBack(bip9_softforks, "csv", consensusParams, Consensus::DEPLOYMENT_CSV);
BIP9SoftForkDescPushBack(bip9_softforks, "segwit", consensusParams, Consensus::DEPLOYMENT_SEGWIT);
Expand Down
7 changes: 3 additions & 4 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,15 @@ UniValue combineblocksigs(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");

UniValue result(UniValue::VOBJ);
const Consensus::Params& consensusParams = Params().GetConsensus();
const UniValue& sigs = params[1].get_array();
for (unsigned int i = 0; i < sigs.size(); i++) {
const std::string& sig = sigs[i].get_str();
if (!IsHex(sig))
continue;
std::vector<unsigned char> vchScript = ParseHex(sig);
block.proof.solution = CombineBlockSignatures(block, block.proof.solution, CScript(vchScript.begin(), vchScript.end()));
if (CheckProof(block, Params().GetConsensus())) {
block.proof.solution = CombineBlockSignatures(consensusParams, block, block.proof.solution, CScript(vchScript.begin(), vchScript.end()));
if (CheckProof(block, consensusParams)) {
result.push_back(Pair("hex", EncodeHexBlock(block)));
result.push_back(Pair("complete", true));
return result;
Expand Down Expand Up @@ -728,7 +729,6 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
result.push_back(Pair("coinbaseaux", aux));
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue.GetAmount()));
result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
result.push_back(Pair("target", GetChallengeStrHex(*pblock)));
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
result.push_back(Pair("mutable", aMutable));
result.push_back(Pair("noncerange", "00000000ffffffff"));
Expand All @@ -741,7 +741,6 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE));
result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
result.push_back(Pair("curtime", pblock->GetBlockTime()));
result.push_back(Pair("bits", GetChallengeStr(*pblock)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())));
Expand Down
2 changes: 1 addition & 1 deletion src/test/test_bitcoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
newCoinbase.vout[i].scriptPubKey = scriptPubKey;
const_cast<CBlock&>(Params().GenesisBlock()).vtx[0] = newCoinbase;
const_cast<CBlock&>(Params().GenesisBlock()).hashMerkleRoot = BlockMerkleRoot(Params().GenesisBlock());
const_cast<CBlock&>(Params().GenesisBlock()).proof = CProof(CScript()<<OP_TRUE, CScript());
const_cast<CBlock&>(Params().GenesisBlock()).proof = CProof(CScript());
const_cast<Consensus::Params&>(Params().GetConsensus()).hashGenesisBlock = Params().GenesisBlock().GetHash();

ClearDatadirCache();
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2944,7 +2944,7 @@ UniValue signblock(const UniValue& params, bool fHelp)
}

block.proof.solution = CScript();
MaybeGenerateProof(&block, pwalletMain);
MaybeGenerateProof(Params().GetConsensus(), &block, pwalletMain);
return HexStr(block.proof.solution.begin(), block.proof.solution.end());
}

Expand Down