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

Multi-Algo - Defence against 51% attacks? #100

Open
wants to merge 9 commits into
base: 0.14.0
Choose a base branch
from
158 changes: 157 additions & 1 deletion src/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chain.h>
#include "chainparams.h"

/**
* CChain implementation
Expand Down Expand Up @@ -118,7 +119,79 @@ void CBlockIndex::BuildSkip()
pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
}

arith_uint256 GetBlockProof(const CBlockIndex& block)
arith_uint256 uint256_nthRoot(const int root, const arith_uint256 bn)
{
assert(root > 1);
if (bn==0)
return 0;
assert(bn > 0);

// starting approximation
int nRootBits = (bn.bits() + root - 1) / root;
int nStartingBits = std::min(8, nRootBits);
arith_uint256 bnUpper = bn;
bnUpper >>= (nRootBits - nStartingBits)*root;
arith_uint256 bnCur = 0;
for (int i = nStartingBits - 1; i >= 0; i--) {
arith_uint256 bnNext = bnCur;
bnNext += 1 << i;
arith_uint256 bnPower = 1;
for (int j = 0; j < root; j++)
bnPower *= bnNext;
if (bnPower <= bnUpper)
bnCur = bnNext;
}
if (nRootBits == nStartingBits)
return bnCur;
bnCur <<= nRootBits - nStartingBits;

// iterate: cur = cur + (bn / cur^^(root-1) - cur)/root
arith_uint256 bnDelta;
const arith_uint256 bnRoot = root;
int nTerminate = 0;
bool fNegativeDelta = false;
// this should always converge in fewer steps, but limit just in case
for (int it = 0; it < 20; it++)
{
arith_uint256 bnDenominator = 1;
for (int i = 0; i < root - 1; i++)
bnDenominator *= bnCur;
if (bnCur > bn/bnDenominator)
fNegativeDelta = true;
if (bnCur == bn/bnDenominator) // bnDelta=0
return bnCur;
if (fNegativeDelta) {
bnDelta = bnCur - bn/bnDenominator;
if (nTerminate == 1)
return bnCur - 1;
fNegativeDelta = false;
if (bnDelta <= bnRoot) {
bnCur -= 1;
nTerminate = -1;
continue;
}
fNegativeDelta = true;
} else {
bnDelta = bn/bnDenominator - bnCur;
if (nTerminate == -1)
return bnCur;
if (bnDelta <= bnRoot) {
bnCur += 1;
nTerminate = 1;
continue;
}
}
if (fNegativeDelta) {
bnCur -= bnDelta / bnRoot;
} else {
bnCur += bnDelta / bnRoot;
}
nTerminate = 0;
}
return bnCur;
}

arith_uint256 GetBlockProofBase(const CBlockIndex& block)
{
arith_uint256 bnTarget;
bool fNegative;
Expand All @@ -133,6 +206,77 @@ arith_uint256 GetBlockProof(const CBlockIndex& block)
return (~bnTarget / (bnTarget + 1)) + 1;
}

arith_uint256 GetPrevWorkForAlgoWithDecay(const CBlockIndex& block, int algo)
{
int nDistance = 0;
arith_uint256 nWork;
const CBlockIndex* pindex = &block;
while (pindex != NULL)
{
if (nDistance > 100)
{
return arith_uint256(0);
}
if (pindex->GetAlgo() == algo)
{
arith_uint256 nWork = GetBlockProofBase(*pindex);
nWork *= (100 - nDistance);
nWork /= 100;
return nWork;
}
pindex = pindex->pprev;
nDistance++;
}
return arith_uint256(0);
}

arith_uint256 GetGeometricMeanPrevWork(const CBlockIndex& block)
{
arith_uint256 bnRes;
arith_uint256 nBlockWork = GetBlockProofBase(block);
int nAlgo = block.GetAlgo();

// Compute the geometric mean
// We use the nthRoot product rule here:
// nthRoot(a*b*...) = nthRoot(a)*nthRoot(b)*...
// This is to ensure we never overflow a uint256.
nBlockWork = uint256_nthRoot(NUM_ALGOS, nBlockWork);

for (int algo = 0; algo < NUM_ALGOS_IMPL; algo++)
{
if (algo != nAlgo)
{
arith_uint256 nBlockWorkAlt = GetPrevWorkForAlgoWithDecay(block, algo);
if (nBlockWorkAlt != 0)
nBlockWork *= uint256_nthRoot(NUM_ALGOS,nBlockWorkAlt); // Again, the nthRoot product rule.
}
}
// In the past we have computed the geometric mean here,
// but do not need to from the nthRoot product rule above.
bnRes = nBlockWork;

// Scale to roughly match the old work calculation
bnRes <<= 8;

return bnRes;

}

arith_uint256 GetBlockProof(const CBlockIndex& block)
{
Consensus::Params params = Params().GetConsensus();
int nHeight = block.nHeight;

if(nHeight > params.nStartMultiAlgoHash)
{
return GetGeometricMeanPrevWork(block);
}
else
{
return GetBlockProofBase(block);
}
}

int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
{
arith_uint256 r;
Expand Down Expand Up @@ -168,3 +312,15 @@ const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex*
assert(pa == pb);
return pa;
}

const CBlockIndex* GetLastBlockIndexForAlgo(const CBlockIndex* pindex, int algo)
{
for (;;)
{
if (!pindex)
return NULL;
if (pindex->GetAlgo() == algo)
return pindex;
pindex = pindex->pprev;
}
}
12 changes: 9 additions & 3 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,14 @@ class CBlockIndex
return *phashBlock;
}

uint256 GetBlockPoWHash() const
uint256 GetBlockPoWHash(const Consensus::Params& params) const
{
return GetBlockHeader().GetPoWHash(nHeight);
return GetBlockHeader().GetPoWHash(nHeight, params);
}

int GetAlgo() const
{
return ::GetAlgo(nVersion);
}

int64_t GetBlockTime() const
Expand Down Expand Up @@ -369,7 +374,8 @@ arith_uint256 GetBlockProof(const CBlockIndex& block);
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&);
/** Find the forking point between two chain tips. */
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb);

/** Return the index to the last block of algo */
const CBlockIndex* GetLastBlockIndexForAlgo(const CBlockIndex* pindex, int algo);

/** Used to marshal pointers into hashes for db storage. */
class CDiskBlockIndex : public CBlockIndex
Expand Down
35 changes: 30 additions & 5 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ class CMainParams : public CChainParams {
// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x4b151d928c0aae106c9d69347df59e0088cbd33dd659deab126506865a8b0060"); //898726

consensus.nStartLyra2reHash = 208301; // height where lyra2re replaced scrypt-n
consensus.nStartLyra2re2Hash = 347000; // height where lyra2re2 replaced lyra2re
consensus.nStartLyra2re3Hash = 1080000; // height where lyra2re3 replaced lyra2re2
consensus.nStartMultiAlgoHash = 10000000; // height where multi-algorithm is active - UPDATE

consensus.nStartKGWWorkCalc = 26754; // height where KimotoGravityWell replaces bitcoin's difficulty algorithm

// multishield parameters
consensus.nAveragingInterval = 10; // 10 blocks
consensus.nMaxAdjustDown = 16; // 16% adjustment down
consensus.nMaxAdjustUp = 8; // 8% adjustment up

/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
Expand Down Expand Up @@ -181,7 +193,7 @@ class CTestNetParams : public CChainParams {
strNetworkID = "test";
consensus.testnet = true;
consensus.nSubsidyHalvingInterval = 840000;
consensus.BIP16Height = 0;
consensus.BIP16Height = 0;
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 2.5 * 60;
Expand All @@ -193,24 +205,37 @@ class CTestNetParams : public CChainParams {
// Deployment of BIP65, BIP66, and BIP34.
consensus.vDeployments[Consensus::DEPLOYMENT_NVERSIONBIPS].bit = 2;
consensus.vDeployments[Consensus::DEPLOYMENT_NVERSIONBIPS].nStartTime = 1486865123;
consensus.vDeployments[Consensus::DEPLOYMENT_NVERSIONBIPS].nTimeout = 1517356801;
consensus.vDeployments[Consensus::DEPLOYMENT_NVERSIONBIPS].nTimeout = 1517356801;

// Deployment of BIP68, BIP112, and BIP113.
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1486865123;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1517356801;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1486865123;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1517356801;

// Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1486865123;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1517356801;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1517356801;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000000000000000100010");

// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x69ab56f74d75afa90b65b1fe10df8adaf2769e2ba64df1e1dc99c4d6717e1a2a"); //9000

consensus.nStartLyra2reHash = 0; // height where lyra2re replaced scrypt-n
consensus.nStartLyra2re2Hash = 0; // height where lyra2re2 replaced lyra2re
consensus.nStartLyra2re3Hash = 158220; // height where lyra2re3 replaced lyra2re2
consensus.nStartMultiAlgoHash = 210000; // height where multi-algorithm is active - UPDATE

consensus.nStartKGWWorkCalc = 2116; // height where KimotoGravityWell replaces bitcoin's difficulty algorithm

// multishield parameters
consensus.nAveragingInterval = 10; // 10 blocks
consensus.nMaxAdjustDown = 16; // 16% adjustment down
consensus.nMaxAdjustUp = 8; // 8% adjustment up
consensus.nLocalTargetAdjustment = 4; //target adjustment per algo

pchMessageStart[0] = 'v';
pchMessageStart[1] = 'e';
pchMessageStart[2] = 'r';
Expand Down
10 changes: 10 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ struct Params {
uint256 nMinimumChainWork;
uint256 defaultAssumeValid;
bool testnet;

int nStartLyra2reHash;
int nStartLyra2re2Hash;
int nStartLyra2re3Hash;
int nStartMultiAlgoHash;
int nStartKGWWorkCalc;
int nAveragingInterval;
int nMaxAdjustDown;
int nMaxAdjustUp;
int nLocalTargetAdjustment;
};
} // namespace Consensus

Expand Down
15 changes: 14 additions & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ std::string LicenseInfo()
const std::string URL_SOURCE_CODE = "<https://github.com/vertcoin-project/vertcoin-core>";
const std::string URL_WEBSITE = "<https://vertcoin.org>";

return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2014, COPYRIGHT_YEAR) + " ",
return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2014, COPYRIGHT_YEAR) + " ",
strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" +
"\n" +
strprintf(_("Please contribute if you find %s useful. "
Expand Down Expand Up @@ -1156,6 +1156,19 @@ bool AppInitParameterInteraction()
}
}
}

// Set Mining Algorithm
std::string strAlgo = gArgs.GetArg("-algo", "lyra2rev3");
transform(strAlgo.begin(),strAlgo.end(),strAlgo.begin(),::tolower);
if (strAlgo == "lyra2rev3" || strAlgo == "lyra2re3" || strAlgo == "lyra2re")
miningAlgo = ALGO_LYRA2REV3;
else if (strAlgo == "newalgo1")
miningAlgo = ALGO_NEWALGO1;
else if (strAlgo == "newalgo2")
miningAlgo = ALGO_NEWALGO2;
else
miningAlgo = ALGO_LYRA2REV3;

return true;
}

Expand Down
9 changes: 6 additions & 3 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam

// Updating time can change work required on testnet:
if (consensusParams.fPowAllowMinDifficultyBlocks)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams, pblock->GetAlgo());

return nNewTime - nOldTime;
}
Expand Down Expand Up @@ -105,7 +105,7 @@ void BlockAssembler::resetBlock()
nFees = 0;
}

std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx)
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, int algo, bool fMineWitnessTx)
{
int64_t nTimeStart = GetTimeMicros();

Expand Down Expand Up @@ -133,6 +133,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
if (chainparams.MineBlocksOnDemand())
pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion);

// multi-algo: encode algo into nVersion
pblock->SetAlgo(algo);

pblock->nTime = GetAdjustedTime();
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();

Expand Down Expand Up @@ -174,7 +177,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus(), algo);
pblock->nNonce = 0;
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);

Expand Down
2 changes: 1 addition & 1 deletion src/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class BlockAssembler
BlockAssembler(const CChainParams& params, const Options& options);

/** Construct a new block template with coinbase to scriptPubKeyIn */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true);
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, int algo, bool fMineWitnessTx=true);

private:
// utility functions
Expand Down
Loading