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 #191

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
66 changes: 48 additions & 18 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@

#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, const CScript& signblockscript)
static std::vector<unsigned char> CommitToArguments(const Consensus::Params& params, const std::string& networkID)
{
CSHA256 sha2;
unsigned char commitment[32];
sha2.Write((const unsigned char*)networkID.c_str(), networkID.length());
sha2.Write((const unsigned char*)HexStr(params.fedpegScript).c_str(), HexStr(params.fedpegScript).length());
sha2.Write((const unsigned char*)HexStr(signblockscript).c_str(), HexStr(signblockscript).length());
sha2.Write((const unsigned char*)HexStr(params.signblockScript).c_str(), HexStr(params.signblockScript).length());
sha2.Finalize(commitment);
return std::vector<unsigned char>(commitment, commitment + 32);
}
Expand All @@ -43,25 +45,43 @@ static CScript StrHexToScriptWithDefault(std::string strScript, const CScript de
return returnScript;
}

static CBlock CreateGenesisBlock(const Consensus::Params& params, const std::string& networkID, 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.vout.resize(rewardShards);
// Any consensus-related values that are command-line set can be added here for anti-footgun
txNew.vin[0].scriptSig = CScript(CommitToArguments(params, networkID, scriptChallenge));
for (unsigned int i = 0; i < rewardShards; i++) {
txNew.vout[i].nValue = genesisReward/rewardShards;
txNew.vout[i].nAsset = asset;
txNew.vout[i].scriptPubKey = genesisOutputScript;
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(MakeTransactionRef(std::move(txNew)));
genesis.hashPrevBlock.SetNull();
Expand All @@ -85,7 +105,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", ""), defaultSignblockScript);
consensus.signblockScript = StrHexToScriptWithDefault(GetArg("-signblockscript", ""), defaultSignblockScript);
CScript defaultFedpegScript;
defaultFedpegScript = CScript() << OP_2 << ParseHex("02d51090b27ca8f1cc04984614bd749d8bab6f2a3681318d3fd0dd43b2a39dd774") << ParseHex("03a75bd7ac458b19f98047c76a6ffa442e592148c5d23a1ec82d379d5d558f4fd8") << ParseHex("034c55bede1bce8e486080f8ebb7a0e8f106b49efb295a8314da0e1b1723738c66") << OP_3 << OP_CHECKMULTISIG;
consensus.fedpegScript = StrHexToScriptWithDefault(GetArg("-fedpegscript", ""), defaultFedpegScript);
Expand Down Expand Up @@ -145,13 +165,16 @@ class CElementsParams : public CChainParams {
parentGenesisBlockHash = uint256S("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");

// Generate pegged Bitcoin asset
std::vector<unsigned char> commit = CommitToArguments(consensus, strNetworkID, genesisChallengeScript);
std::vector<unsigned char> commit = CommitToArguments(consensus, strNetworkID);
uint256 entropy;
GenerateAssetEntropy(entropy, COutPoint(uint256(commit), 0), parentGenesisBlockHash);
CalculateAsset(consensus.pegged_asset, entropy);

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

scriptCoinbaseDestination = CScript() << ParseHex("0229536c4c83789f59c30b93eb40d4abbd99b8dcc99ba8bd748f29e33c1d279e3c") << OP_CHECKSIG;
Expand Down Expand Up @@ -212,7 +235,7 @@ class CRegTestParams : public CChainParams {
public:
CRegTestParams() {
const CScript defaultRegtestScript(CScript() << OP_TRUE);
CScript genesisChallengeScript = StrHexToScriptWithDefault(GetArg("-signblockscript", ""), defaultRegtestScript);
consensus.signblockScript = StrHexToScriptWithDefault(GetArg("-signblockscript", ""), defaultRegtestScript);
consensus.fedpegScript = StrHexToScriptWithDefault(GetArg("-fedpegscript", ""), defaultRegtestScript);

strNetworkID = CHAINPARAMS_REGTEST;
Expand Down Expand Up @@ -255,12 +278,15 @@ class CRegTestParams : public CChainParams {
parentGenesisBlockHash = uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206");

// Generate pegged Bitcoin asset
std::vector<unsigned char> commit = CommitToArguments(consensus, strNetworkID, genesisChallengeScript);
std::vector<unsigned char> commit = CommitToArguments(consensus, strNetworkID);
uint256 entropy;
GenerateAssetEntropy(entropy, COutPoint(uint256(commit), 0), parentGenesisBlockHash);
CalculateAsset(consensus.pegged_asset, entropy);

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


Expand Down Expand Up @@ -321,6 +347,10 @@ class CCustomParams : public CChainParams {
// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S(GetArg("-con_defaultassumevalid", "0x00"));

const CScript defaultRegtestScript(CScript() << OP_TRUE);
consensus.signblockScript = StrHexToScriptWithDefault(GetArg("-signblockscript", ""), defaultRegtestScript);
consensus.fedpegScript = StrHexToScriptWithDefault(GetArg("-fedpegscript", ""), defaultRegtestScript);

nDefaultPort = GetArg("-ndefaultport", 18444);
nPruneAfterHeight = GetArg("-npruneafterheight", 1000);
fDefaultConsistencyChecks = GetBoolArg("-fdefaultconsistencychecks", true);
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct Params {
CScript fedpegScript;
CAsset pegged_asset;
uint256 defaultAssumeValid;
CScript signblockScript;
};
} // namespace Consensus

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(uint256 hash, unsigned int nBits)
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(uint256 hash, unsigned int nBits);
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)
{
READWRITE(*(CScriptBase*)(&challenge));
if (!(s.GetType() & 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 @@ -10,6 +10,7 @@
#include "coins.h"
#include "consensus/validation.h"
#include "validation.h"
#include "core_io.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "rpc/server.h"
Expand Down Expand Up @@ -74,7 +75,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 @@ -118,7 +118,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 @@ -1046,6 +1045,8 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
"\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 @@ -1079,10 +1080,13 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
+ 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 @@ -1092,7 +1096,6 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
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 @@ -215,14 +215,15 @@ UniValue combineblocksigs(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");

UniValue result(UniValue::VOBJ);
const Consensus::Params& consensusParams = Params().GetConsensus();
const UniValue& sigs = request.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 @@ -738,7 +739,6 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
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 @@ -755,7 +755,6 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
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() && fSupportsSegwit) {
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 @@ -73,7 +73,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
newCoinbase.vout[i].scriptPubKey = scriptPubKey;
const_cast<CBlock&>(Params().GenesisBlock()).vtx[0] = MakeTransactionRef(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 @@ -3369,7 +3369,7 @@ UniValue signblock(const JSONRPCRequest& request)
}

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

Expand Down