Verus Proof of Stake Compete with Additional ant-fork protection on block 1
This commit is contained in:
@@ -80,12 +80,9 @@ void *chainparams_commandline(void *ptr);
|
||||
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
|
||||
extern uint32_t ASSETCHAIN_INIT;
|
||||
extern uint32_t ASSETCHAINS_MAGIC;
|
||||
extern uint64_t ASSETCHAINS_SUPPLY;
|
||||
extern uint64_t ASSETCHAINS_ALGO;
|
||||
extern uint64_t ASSETCHAINS_EQUIHASH;
|
||||
extern uint64_t ASSETCHAINS_VERUSHASH;
|
||||
extern uint32_t ASSETCHAIN_INIT, ASSETCHAINS_MAGIC;
|
||||
extern int32_t VERUS_BLOCK_POSUNITS, ASSETCHAINS_LWMAPOS;
|
||||
extern uint64_t ASSETCHAINS_SUPPLY, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH;
|
||||
|
||||
const arith_uint256 maxUint = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
|
||||
|
||||
@@ -244,6 +241,18 @@ void *chainparams_commandline(void *ptr)
|
||||
mainParams.consensus.powAlternate = uint256S("00000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f");
|
||||
}
|
||||
|
||||
if (ASSETCHAINS_LWMAPOS != 0)
|
||||
{
|
||||
mainParams.consensus.posLimit = uint256S("000000000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f");
|
||||
mainParams.consensus.nPOSAveragingWindow = 100;
|
||||
// spacing is 1000 units per block to get better resolution, POS is 50% hard coded for now, we can vary it later
|
||||
// when we get reliable integer math on nLwmaPOSAjustedWeight
|
||||
mainParams.consensus.nPOSTargetSpacing = VERUS_BLOCK_POSUNITS * 2;
|
||||
// nLwmaPOSAjustedWeight = (N+1)/2 * (0.9989^(500/nPOSAveragingWindow)) * nPOSTargetSpacing
|
||||
// this needs to be recalculated if VERUS_BLOCK_POSUNITS is changed
|
||||
mainParams.consensus.nLwmaPOSAjustedWeight = 100446;
|
||||
}
|
||||
|
||||
checkpointData = //(Checkpoints::CCheckpointData)
|
||||
{
|
||||
boost::assign::map_list_of
|
||||
|
||||
@@ -97,11 +97,17 @@ struct Params {
|
||||
int64_t nPowMaxAdjustDown;
|
||||
int64_t nPowMaxAdjustUp;
|
||||
int64_t nPowTargetSpacing;
|
||||
int64_t nMaxFutureBlockTime;
|
||||
|
||||
// Verus algorithm's lwma difficulty
|
||||
int64_t nLwmaAjustedWeight;
|
||||
|
||||
/* Proof of stake parameters */
|
||||
uint256 posLimit;
|
||||
int64_t nPOSAveragingWindow; // can be completely different than POW and initially trying a relatively large number, like 100
|
||||
int64_t nPOSTargetSpacing; // spacing is 1000 units per block to get better resolution, (100 % = 1000, 50% = 2000, 10% = 10000)
|
||||
int64_t nLwmaPOSAjustedWeight;
|
||||
|
||||
/* applied to all block times */
|
||||
int64_t nMaxFutureBlockTime;
|
||||
|
||||
int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; }
|
||||
int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; }
|
||||
int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; }
|
||||
|
||||
@@ -30,8 +30,8 @@ Optimized Implementations for Haraka256 and Haraka512
|
||||
|
||||
#define NUMROUNDS 5
|
||||
|
||||
#define u64 unsigned long
|
||||
#define u128 __m128i
|
||||
typedef unsigned long u64;
|
||||
typedef __m128i u128;
|
||||
|
||||
extern u128 rc[40];
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
|
||||
unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
|
||||
|
||||
//#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
|
||||
|
||||
@@ -557,7 +558,7 @@ uint64_t komodo_seed(int32_t height)
|
||||
return(seed);
|
||||
}
|
||||
|
||||
uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
|
||||
uint32_t komodo_txtime(uint64_t *valuep,uint256 hash, int32_t n, char *destaddr)
|
||||
{
|
||||
CTxDestination address; CTransaction tx; uint256 hashBlock;
|
||||
*valuep = 0;
|
||||
@@ -666,18 +667,19 @@ int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
|
||||
else memset(pubkey33,0,33);
|
||||
if ( block->vtx[0].vout.size() > 0 )
|
||||
{
|
||||
#ifdef KOMODO_ZCASH
|
||||
uint8_t *ptr = (uint8_t *)block->vtx[0].vout[0].scriptPubKey.data();
|
||||
#else
|
||||
uint8_t *ptr = (uint8_t *)&block->vtx[0].vout[0].scriptPubKey[0];
|
||||
#endif
|
||||
//komodo_init(0);
|
||||
n = block->vtx[0].vout[0].scriptPubKey.size();
|
||||
if ( n == 35 )
|
||||
txnouttype whichType;
|
||||
vector<vector<unsigned char>> vch = vector<vector<unsigned char>>();
|
||||
if (Solver(block->vtx[0].vout[0].scriptPubKey, whichType, vch) && whichType == TX_PUBKEY)
|
||||
{
|
||||
memcpy(pubkey33,ptr+1,33);
|
||||
return(1);
|
||||
CPubKey pubKey(vch[0]);
|
||||
if (pubKey.IsValid())
|
||||
{
|
||||
memcpy(pubkey33,vch[0].data(),33);
|
||||
return true;
|
||||
}
|
||||
else memset(pubkey33,0,33);
|
||||
}
|
||||
else memset(pubkey33,0,33);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
@@ -1256,6 +1258,95 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
|
||||
return(isPoS);
|
||||
}
|
||||
|
||||
// if slow flag is 1, this does a slower check that checks the target with consensus, otherwise quick, insecure check for internal integrity
|
||||
bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
|
||||
{
|
||||
CBlockIndex *pastBlockIndex;
|
||||
uint256 txid, blkHash;
|
||||
int32_t txn_count;
|
||||
uint32_t voutNum;
|
||||
bool isPOS = false;
|
||||
CTxDestination voutaddress;
|
||||
arith_uint256 target, hash;
|
||||
CTransaction tx;
|
||||
|
||||
// TODO(miketout) must initialize destaddr properly
|
||||
char voutaddr[64],destaddr[64];
|
||||
|
||||
target.SetCompact(pblock->GetVerusPOSTarget());
|
||||
txn_count = pblock->vtx.size();
|
||||
|
||||
if ( txn_count > 1 )
|
||||
{
|
||||
txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
|
||||
voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
|
||||
|
||||
#ifndef KOMODO_ZCASH
|
||||
if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
|
||||
#else
|
||||
if (!GetTransaction(txid, tx, blkHash, true))
|
||||
#endif
|
||||
{
|
||||
fprintf(stderr,"ERROR: invalid PoS block %s - no transaction\n",blkHash.ToString().c_str());
|
||||
}
|
||||
else if (!(pastBlockIndex = komodo_chainactive(height - COINBASE_MATURITY)))
|
||||
{
|
||||
fprintf(stderr,"ERROR: invalid PoS block %s - no past block hash\n",blkHash.ToString().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
hash = UintToArith256(tx.GetVerusPOSHash(voutNum, height, pastBlockIndex->GetBlockHash())) / tx.vout[voutNum].nValue;
|
||||
if (hash <= target)
|
||||
{
|
||||
if ((mapBlockIndex.count(blkHash) == 0) ||
|
||||
!(pastBlockIndex = mapBlockIndex[blkHash]) ||
|
||||
(height - pastBlockIndex->nHeight) < VERUS_MIN_STAKEAGE)
|
||||
{
|
||||
fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
|
||||
}
|
||||
else if ( slowflag != 0 )
|
||||
{
|
||||
// make sure we have the right target
|
||||
CBlockIndex *previndex;
|
||||
if (!(previndex = mapBlockIndex[pblock->hashPrevBlock]))
|
||||
{
|
||||
fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
arith_uint256 cTarget;
|
||||
cTarget.SetCompact(lwmaGetNextPOSRequired(previndex, Params().GetConsensus()));
|
||||
if (cTarget != target)
|
||||
{
|
||||
fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
|
||||
}
|
||||
else if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
|
||||
{
|
||||
strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
|
||||
if ( strcmp(destaddr,voutaddr) == 0 )
|
||||
{
|
||||
isPOS = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake destination\n",blkHash.ToString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// with fast check, we get true here, slow check ensures destination address
|
||||
// of staking transaction matches original source and that the target
|
||||
// matches the consensus target
|
||||
isPOS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(isPOS);
|
||||
}
|
||||
|
||||
int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
{
|
||||
uint256 hash; arith_uint256 bnTarget,bhash; bool fNegative,fOverflow; uint8_t *script,pubkey33[33],pubkeys[64][33]; int32_t i,possible,PoSperc,is_PoSblock=0,n,failed = 0,notaryid = -1; int64_t checktoshis,value; CBlockIndex *pprev;
|
||||
@@ -1278,6 +1369,14 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
if ( height == 0 )
|
||||
return(0);
|
||||
}
|
||||
if ( ASSETCHAINS_LWMAPOS != 0 && bhash > bnTarget )
|
||||
{
|
||||
// if proof of stake is active, check if this is a valid PoS block before we fail
|
||||
if (verusCheckPOSBlock(slowflag, pblock, height))
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget )
|
||||
{
|
||||
failed = 1;
|
||||
|
||||
@@ -78,6 +78,11 @@ uint32_t ASSETCHAINS_NONCESHIFT[] = {32,40};
|
||||
uint32_t ASSETCHAINS_HASHESPERROUND[] = {1,512};
|
||||
uint32_t ASSETCHAINS_ALGO = _ASSETCHAINS_EQUIHASH;
|
||||
|
||||
// Verus proof of stake controls
|
||||
int32_t ASSETCHAINS_LWMAPOS = 0; // percentage of blocks should be PoS
|
||||
int32_t VERUS_BLOCK_POSUNITS = 1000; // one block is 1000 units
|
||||
int32_t VERUS_MIN_STAKEAGE = 200; // 1/2 this should also be a cap on the POS averaging window, or startup could be too easy
|
||||
|
||||
uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
|
||||
uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10;
|
||||
|
||||
|
||||
@@ -1020,7 +1020,7 @@ int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_
|
||||
|
||||
// get a pseudo random number that is the same for each block individually at all times and different
|
||||
// from all other blocks. the sequence is extremely likely, but not guaranteed to be unique for each block chain
|
||||
uint64_t blockPRG(uint32_t nHeight)
|
||||
uint64_t komodo_block_prg(uint32_t nHeight)
|
||||
{
|
||||
int i;
|
||||
uint8_t hashSrc[8];
|
||||
@@ -1052,7 +1052,7 @@ int64_t komodo_block_unlocktime(uint32_t nHeight)
|
||||
unlocktime = ASSETCHAINS_TIMEUNLOCKTO;
|
||||
else
|
||||
{
|
||||
unlocktime = blockPRG(nHeight) / (0xffffffffffffffff / ((ASSETCHAINS_TIMEUNLOCKTO - ASSETCHAINS_TIMEUNLOCKFROM) + 1));
|
||||
unlocktime = komodo_block_prg(nHeight) / (0xffffffffffffffff / ((ASSETCHAINS_TIMEUNLOCKTO - ASSETCHAINS_TIMEUNLOCKFROM) + 1));
|
||||
// boundary and power of 2 can make it exceed to time by 1
|
||||
unlocktime = unlocktime + ASSETCHAINS_TIMEUNLOCKFROM;
|
||||
if (unlocktime > ASSETCHAINS_TIMEUNLOCKTO)
|
||||
@@ -1602,6 +1602,12 @@ uint64_t komodo_ac_block_subsidy(int nHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( nHeight == 1 )
|
||||
if ( ASSETCHAINS_LASTERA == 0 )
|
||||
subsidy = ASSETCHAINS_SUPPLY * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff);
|
||||
else
|
||||
subsidy += ASSETCHAINS_SUPPLY * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff);
|
||||
|
||||
return(subsidy);
|
||||
}
|
||||
|
||||
@@ -1701,6 +1707,8 @@ void komodo_args(char *argv0)
|
||||
ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey","");
|
||||
if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 )
|
||||
ASSETCHAINS_STAKED = 100;
|
||||
if ( (ASSETCHAINS_LWMAPOS = GetArg("-ac_veruspos",0)) > 100 )
|
||||
ASSETCHAINS_LWMAPOS = 100;
|
||||
|
||||
if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 && ASSETCHAINS_COMMISSION > 0 && ASSETCHAINS_COMMISSION <= 100000000 )
|
||||
decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str());
|
||||
@@ -1752,6 +1760,11 @@ void komodo_args(char *argv0)
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ALGO),(void *)&ASSETCHAINS_ALGO);
|
||||
}
|
||||
|
||||
if ( ASSETCHAINS_LWMAPOS != 0 )
|
||||
{
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_LWMAPOS),(void *)&ASSETCHAINS_LWMAPOS);
|
||||
}
|
||||
|
||||
val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffffff) << 40);
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val);
|
||||
}
|
||||
|
||||
31
src/main.cpp
31
src/main.cpp
@@ -907,6 +907,14 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||
*/
|
||||
bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeight)
|
||||
{
|
||||
int64_t valOut = tx.GetValueOut(), sub = komodo_ac_block_subsidy(nHeight);
|
||||
if ((uint64_t)(tx.GetValueOut()) != komodo_ac_block_subsidy(nHeight))
|
||||
{
|
||||
// failed with invalid coinbase output
|
||||
fprintf(stderr, "ERROR: invalid block #%i, reward=%li, subsidy should be %li", nHeight, valOut, sub);
|
||||
return(false);
|
||||
}
|
||||
|
||||
// if time locks are on, ensure that this coin base is time locked exactly as it should be
|
||||
if ((uint64_t)(tx.GetValueOut()) >= ASSETCHAINS_TIMELOCKGTE)
|
||||
{
|
||||
@@ -1731,7 +1739,7 @@ bool ReadBlockFromDisk(int32_t height,CBlock& block, const CDiskBlockPos& pos,bo
|
||||
if ( 0 && checkPOW != 0 )
|
||||
{
|
||||
komodo_block2pubkey33(pubkey33,(CBlock *)&block);
|
||||
if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus(),block.nTime)))
|
||||
if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(block, pubkey33, height, Params().GetConsensus())))
|
||||
{
|
||||
int32_t i; for (i=0; i<33; i++)
|
||||
fprintf(stderr,"%02x",pubkey33[i]);
|
||||
@@ -1774,10 +1782,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( nHeight == 1 )
|
||||
return(ASSETCHAINS_SUPPLY * COIN + (ASSETCHAINS_MAGIC & 0xffffff));
|
||||
else
|
||||
return(komodo_ac_block_subsidy(nHeight));
|
||||
return(komodo_ac_block_subsidy(nHeight));
|
||||
}
|
||||
/*
|
||||
// Mining slow start
|
||||
@@ -3328,6 +3333,13 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
|
||||
bool fInvalidFound = false;
|
||||
const CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
||||
|
||||
// asset chains cannot reorg past block 1, which is specific to the asset chain
|
||||
if (ASSETCHAINS_SYMBOL[0] != 0 && pindexFork && pindexFork->nHeight < 1 && chainActive.Tip()->nHeight != pindexFork->nHeight)
|
||||
{
|
||||
LogPrintf("Failed attempt to reorg past block 1 in asset chain %s\n", ASSETCHAINS_SYMBOL);
|
||||
return false;
|
||||
}
|
||||
|
||||
// - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks.
|
||||
// - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain,
|
||||
@@ -3847,10 +3859,10 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
|
||||
}
|
||||
if ( fCheckPOW )
|
||||
{
|
||||
//if ( !CheckEquihashSolution(&block, Params()) )
|
||||
//if ( !CheckEquihashSolution(&block, Params()) )
|
||||
// return state.DoS(100, error("CheckBlock: Equihash solution invalid"),REJECT_INVALID, "invalid-solution");
|
||||
komodo_block2pubkey33(pubkey33,(CBlock *)&block);
|
||||
if ( !CheckProofOfWork(height,pubkey33,hash,block.nBits,Params().GetConsensus(),block.nTime) )
|
||||
if ( !CheckProofOfWork(block,pubkey33,height,Params().GetConsensus()) )
|
||||
{
|
||||
int32_t z; for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&hash)[z]);
|
||||
@@ -3933,7 +3945,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
|
||||
assert(pindexPrev);
|
||||
|
||||
int nHeight = pindexPrev->nHeight+1;
|
||||
|
||||
|
||||
// Check proof of work
|
||||
if ( (ASSETCHAINS_SYMBOL[0] != 0 || nHeight < 235300 || nHeight > 236000) && block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
|
||||
{
|
||||
@@ -3997,6 +4009,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
|
||||
{
|
||||
const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
|
||||
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||
bool checkBlockOne = (nHeight == 1);
|
||||
|
||||
// Check that all transactions are finalized
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
|
||||
@@ -4005,7 +4018,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
|
||||
if (!ContextualCheckTransaction(tx, state, nHeight, 100)) {
|
||||
return false; // Failure reason has been set in validation state object
|
||||
}
|
||||
|
||||
|
||||
int nLockTimeFlags = 0;
|
||||
int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST)
|
||||
? pindexPrev->GetMedianTimePast()
|
||||
|
||||
@@ -111,7 +111,7 @@ extern int32_t ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOS
|
||||
extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED;
|
||||
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
|
||||
extern const char *ASSETCHAINS_ALGORITHMS[];
|
||||
extern int32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
|
||||
extern int32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_LWMAPOS, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern std::string NOTARY_PUBKEY;
|
||||
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
@@ -127,6 +127,7 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_
|
||||
int64_t komodo_block_unlocktime(uint32_t nHeight);
|
||||
uint64_t komodo_commission(const CBlock *block);
|
||||
int32_t komodo_staked(CPubKey &pubkey, CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig);
|
||||
int32_t verus_staked(CPubKey &pubkey, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig);
|
||||
int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33);
|
||||
|
||||
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, bool isStake)
|
||||
@@ -450,11 +451,24 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, bool isStake)
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr;
|
||||
uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr;
|
||||
CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1);
|
||||
|
||||
//if ( blocktime > pindexPrev->GetMedianTimePast()+60 )
|
||||
// blocktime = pindexPrev->GetMedianTimePast() + 60;
|
||||
if ( (siglen= komodo_staked(key, txStaked,pblock->nBits,&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 )
|
||||
if (ASSETCHAINS_LWMAPOS != 0)
|
||||
{
|
||||
uint32_t nBitsPOS;
|
||||
arith_uint256 posHash;
|
||||
siglen = verus_staked(key, txStaked, nBitsPOS, posHash, utxosig);
|
||||
blocktime = GetAdjustedTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
siglen = komodo_staked(key, txStaked, pblock->nBits, &blocktime, &txtime, &utxotxid, &utxovout, &utxovalue, utxosig);
|
||||
}
|
||||
|
||||
if ( siglen > 0 )
|
||||
{
|
||||
CAmount txfees = 0;
|
||||
if ( GetAdjustedTime() < blocktime-13 )
|
||||
@@ -1478,7 +1492,7 @@ void static BitcoinMiner()
|
||||
// (x_1, x_2, ...) = A(I, V, n, k)
|
||||
LogPrint("pow", "Running Equihash solver \"%s\" with nNonce = %s\n",solver, pblock->nNonce.ToString());
|
||||
arith_uint256 hashTarget;
|
||||
if ( NOTARY_PUBKEY33[0] == 0 && ASSETCHAINS_STAKED > 0 && ASSETCHAINS_STAKED < 100 )
|
||||
if ( NOTARY_PUBKEY33[0] == 0 && ASSETCHAINS_STAKED > 0 && ASSETCHAINS_STAKED <= 100 )
|
||||
hashTarget = HASHTarget_POW;
|
||||
else hashTarget = HASHTarget;
|
||||
std::function<bool(std::vector<unsigned char>)> validBlock =
|
||||
@@ -1726,13 +1740,13 @@ void static BitcoinMiner()
|
||||
minerThreads = NULL;
|
||||
}
|
||||
|
||||
if ((nThreads == 0 && ASSETCHAINS_STAKED == 0) || !fGenerate)
|
||||
if ((nThreads == 0 && ASSETCHAINS_LWMAPOS == 0) || !fGenerate)
|
||||
return;
|
||||
|
||||
minerThreads = new boost::thread_group();
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
if (ASSETCHAINS_STAKED != 0)
|
||||
if (ASSETCHAINS_LWMAPOS != 0)
|
||||
{
|
||||
minerThreads->create_thread(boost::bind(&VerusStaker, pwallet));
|
||||
}
|
||||
|
||||
83
src/pow.cpp
83
src/pow.cpp
@@ -22,6 +22,7 @@
|
||||
uint32_t komodo_chainactive_timestamp();
|
||||
|
||||
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH;
|
||||
extern int32_t VERUS_BLOCK_POSUNITS;
|
||||
unsigned int lwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params);
|
||||
unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
|
||||
|
||||
@@ -142,6 +143,73 @@ unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const
|
||||
return nextTarget.GetCompact();
|
||||
}
|
||||
|
||||
bool DoesHashQualify(const CBlockIndex *pbindex)
|
||||
{
|
||||
// if it fails hash test and PoW validation, consider it POS. it could also be invalid
|
||||
arith_uint256 hash = UintToArith256(pbindex->GetBlockHash());
|
||||
// to be considered POS, we first can't qualify as POW
|
||||
if (hash > hash.SetCompact(pbindex->nBits))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// the goal is to keep POS at a solve time that is a ratio of block time units. the low resolution makes a stable solution more challenging
|
||||
// and requires that the averaging window be quite long.
|
||||
unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params)
|
||||
{
|
||||
arith_uint256 nextTarget {0}, sumTarget {0}, bnTmp, bnLimit;
|
||||
bnLimit = UintToArith256(params.posLimit);
|
||||
unsigned int nProofOfStakeLimit = bnLimit.GetCompact();
|
||||
|
||||
// Find the first block in the averaging interval as we total the linearly weighted average
|
||||
// of POS solve times
|
||||
const CBlockIndex* pindexFirst = pindexLast;
|
||||
const CBlockIndex* pindexNext;
|
||||
|
||||
int64_t t = 0, solvetime = 0, k = params.nLwmaPOSAjustedWeight, N = params.nPOSAveragingWindow;
|
||||
|
||||
for (int i = 0, j = N - 1; pindexFirst && i < N; i++, j--) {
|
||||
pindexNext = pindexFirst;
|
||||
// we measure our solve time in passing of blocks, where one bock == VERUS_BLOCK_POSUNITS units
|
||||
for (int x = 0; x < params.nPOSAveragingWindow; x++)
|
||||
{
|
||||
solvetime += VERUS_BLOCK_POSUNITS;
|
||||
pindexFirst = pindexFirst->pprev;
|
||||
// in this loop, unqualified blocks are assumed POS
|
||||
if (!pindexFirst || !DoesHashQualify(pindexFirst))
|
||||
break;
|
||||
}
|
||||
if (!pindexFirst)
|
||||
break;
|
||||
|
||||
// weighted sum
|
||||
t += solvetime * j;
|
||||
|
||||
// Target sum divided by a factor, (k N^2).
|
||||
// The factor is a part of the final equation. However we divide
|
||||
// here to avoid potential overflow.
|
||||
bnTmp.SetCompact(pindexNext->nBits); // TODO(miketout): this must be POS nBits
|
||||
sumTarget += bnTmp / (k * N * N);
|
||||
}
|
||||
|
||||
// Check we have enough blocks
|
||||
if (!pindexFirst)
|
||||
return nProofOfStakeLimit;
|
||||
|
||||
// Keep t reasonable in case strange solvetimes occurred.
|
||||
if (t < N * k / 3)
|
||||
t = N * k / 3;
|
||||
|
||||
bnTmp = bnLimit;
|
||||
nextTarget = t * sumTarget;
|
||||
if (nextTarget > bnTmp)
|
||||
nextTarget = bnTmp;
|
||||
|
||||
return nextTarget.GetCompact();
|
||||
}
|
||||
|
||||
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params)
|
||||
{
|
||||
if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH)
|
||||
@@ -184,7 +252,6 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param
|
||||
int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
|
||||
int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],uint32_t blocktimes[66],int32_t height,uint8_t pubkey33[33],uint32_t blocktime);
|
||||
int32_t komodo_currentheight();
|
||||
CBlockIndex *komodo_chainactive(int32_t height);
|
||||
void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height);
|
||||
extern int32_t KOMODO_CHOSEN_ONE;
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
@@ -195,9 +262,10 @@ int32_t KOMODO_LOADINGBLOCKS = 1;
|
||||
|
||||
extern std::string NOTARY_PUBKEY;
|
||||
|
||||
bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash,unsigned int nBits,const Consensus::Params& params,uint32_t blocktime)
|
||||
bool CheckProofOfWork(const CBlockHeader &blkHeader, uint8_t *pubkey33, int32_t height, const Consensus::Params& params)
|
||||
{
|
||||
extern int32_t KOMODO_REWIND;
|
||||
uint256 hash;
|
||||
bool fNegative,fOverflow; uint8_t origpubkey33[33]; int32_t i,nonzpkeys=0,nonz=0,special=0,special2=0,notaryid=-1,flag = 0, mids[66]; uint32_t tiptime,blocktimes[66];
|
||||
arith_uint256 bnTarget; uint8_t pubkeys[66][33];
|
||||
//for (i=31; i>=0; i--)
|
||||
@@ -206,7 +274,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash,unsigned int
|
||||
memcpy(origpubkey33,pubkey33,33);
|
||||
memset(blocktimes,0,sizeof(blocktimes));
|
||||
tiptime = komodo_chainactive_timestamp();
|
||||
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
|
||||
bnTarget.SetCompact(blkHeader.nBits, &fNegative, &fOverflow);
|
||||
if ( height == 0 )
|
||||
{
|
||||
height = komodo_currentheight() + 1;
|
||||
@@ -226,7 +294,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash,unsigned int
|
||||
return(true); // will come back via different path with pubkey set
|
||||
}
|
||||
flag = komodo_eligiblenotary(pubkeys,mids,blocktimes,&nonzpkeys,height);
|
||||
special2 = komodo_is_special(pubkeys,mids,blocktimes,height,pubkey33,blocktime);
|
||||
special2 = komodo_is_special(pubkeys,mids,blocktimes,height,pubkey33,blkHeader.nTime);
|
||||
if ( notaryid >= 0 )
|
||||
{
|
||||
if ( height > 10000 && height < 80000 && (special != 0 || special2 > 0) )
|
||||
@@ -253,11 +321,13 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash,unsigned int
|
||||
arith_uint256 bnLimit = (height <= 1 || ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH) ? UintToArith256(params.powLimit) : UintToArith256(params.powAlternate);
|
||||
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > bnLimit)
|
||||
return error("CheckProofOfWork(): nBits below minimum work");
|
||||
|
||||
// Check proof of work matches claimed amount
|
||||
if ( UintToArith256(hash) > bnTarget )
|
||||
if ( UintToArith256(hash = blkHeader.GetHash()) > bnTarget && !blkHeader.isVerusPOSBlock() )
|
||||
{
|
||||
if ( KOMODO_LOADINGBLOCKS != 0 )
|
||||
return true;
|
||||
|
||||
if ( ASSETCHAINS_SYMBOL[0] != 0 || height > 792000 )
|
||||
{
|
||||
//if ( 0 && height > 792000 )
|
||||
@@ -294,6 +364,9 @@ arith_uint256 GetBlockProof(const CBlockIndex& block)
|
||||
bool fNegative;
|
||||
bool fOverflow;
|
||||
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
|
||||
|
||||
// TODO(miketout): proof of stake blocks must be marked as having the minimum POW in this context
|
||||
|
||||
if (fNegative || fOverflow || bnTarget == 0)
|
||||
return 0;
|
||||
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
|
||||
|
||||
@@ -21,11 +21,13 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
||||
int64_t nLastBlockTime, int64_t nFirstBlockTime,
|
||||
const Consensus::Params&);
|
||||
|
||||
unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
|
||||
|
||||
/** Check whether the Equihash solution in a block header is valid */
|
||||
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams&);
|
||||
|
||||
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
|
||||
bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned int nBits, const Consensus::Params&,uint32_t blocktime);
|
||||
bool CheckProofOfWork(const CBlockHeader &blkHeader, uint8_t *pubkey33, int32_t height, const Consensus::Params& params);
|
||||
arith_uint256 GetBlockProof(const CBlockIndex& block);
|
||||
|
||||
/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "primitives/transaction.h"
|
||||
#include "serialize.h"
|
||||
#include "uint256.h"
|
||||
#include "arith_uint256.h"
|
||||
|
||||
/** 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
|
||||
@@ -88,6 +89,41 @@ public:
|
||||
{
|
||||
return (int64_t)nTime;
|
||||
}
|
||||
|
||||
int32_t GetVerusPOSTarget() const
|
||||
{
|
||||
uint32_t nBits = 0;
|
||||
|
||||
for (const unsigned char *p = nNonce.begin() + 3; p >= nNonce.begin(); p--)
|
||||
{
|
||||
nBits += *p;
|
||||
nBits <<= 8;
|
||||
}
|
||||
return nBits;
|
||||
}
|
||||
|
||||
bool isVerusPOSBlock() const
|
||||
{
|
||||
arith_uint256 arNonce = UintToArith256(nNonce);
|
||||
arith_uint256 tmpNonce = ((arNonce << 128) >> 128);
|
||||
CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
|
||||
hashWriter << ArithToUint256(tmpNonce);
|
||||
return (nNonce == ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce));
|
||||
}
|
||||
|
||||
void SetVerusPOSTarget(int32_t nBits)
|
||||
{
|
||||
CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
|
||||
uint256 hash;
|
||||
arith_uint256 tmpNonce;
|
||||
|
||||
arith_uint256 arNonce = UintToArith256(nNonce);
|
||||
arNonce = ((arNonce >> 32) << 32) | nBits;
|
||||
|
||||
tmpNonce = ((arNonce << 128) >> 128);
|
||||
hashWriter << ArithToUint256(tmpNonce);
|
||||
nNonce = ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -108,7 +144,6 @@ public:
|
||||
CBlock(const CBlockHeader &header)
|
||||
{
|
||||
SetNull();
|
||||
*((CBlockHeader*)this) = header;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "serialize.h"
|
||||
#include "uint256.h"
|
||||
#include "consensus/consensus.h"
|
||||
#include "hash.h"
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <stdint.h>
|
||||
@@ -24,6 +25,8 @@
|
||||
#include "zcash/JoinSplit.hpp"
|
||||
#include "zcash/Proof.hpp"
|
||||
|
||||
extern uint32_t ASSETCHAINS_MAGIC;
|
||||
|
||||
class JSDescription
|
||||
{
|
||||
public:
|
||||
@@ -469,6 +472,28 @@ public:
|
||||
return a.hash != b.hash;
|
||||
}
|
||||
|
||||
// verus hash will be the same for a given txid, output number, block height, and blockhash of 100 blocks past
|
||||
static uint256 _GetVerusPOSHash(const uint256 &txid, int32_t voutNum, int32_t height, const uint256 &pastHash, int64_t value)
|
||||
{
|
||||
CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
|
||||
|
||||
hashWriter << ASSETCHAINS_MAGIC;
|
||||
hashWriter << pastHash;
|
||||
hashWriter << height;
|
||||
hashWriter << txid;
|
||||
hashWriter << voutNum;
|
||||
return hashWriter.GetHash();
|
||||
}
|
||||
|
||||
uint256 GetVerusPOSHash(int32_t voutNum, int32_t height, const uint256 &pastHash) const
|
||||
{
|
||||
uint256 txid = GetHash();
|
||||
if (voutNum >= vout.size())
|
||||
return uint256();
|
||||
|
||||
return _GetVerusPOSHash(txid, voutNum, height, pastHash, (uint64_t)vout[voutNum].nValue);
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ UniValue generate(const UniValue& params, bool fHelp)
|
||||
LOCK(cs_main);
|
||||
pblock->nSolution = soln;
|
||||
solutionTargetChecks.increment();
|
||||
return CheckProofOfWork(chainActive.Height(),NOTARY_PUBKEY33,pblock->GetHash(), pblock->nBits, Params().GetConsensus(),pblock->nTime);
|
||||
return CheckProofOfWork(*pblock,NOTARY_PUBKEY33,chainActive.Height(),Params().GetConsensus());
|
||||
};
|
||||
bool found = EhBasicSolveUncancellable(n, k, curr_state, validBlock);
|
||||
ehSolverRuns.increment();
|
||||
|
||||
@@ -58,6 +58,7 @@ extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
|
||||
extern uint32_t ASSETCHAINS_CC;
|
||||
extern uint32_t ASSETCHAINS_MAGIC;
|
||||
extern uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY,ASSETCHAINS_LASTERA;
|
||||
extern int32_t ASSETCHAINS_LWMAPOS;
|
||||
extern uint64_t ASSETCHAINS_ENDSUBSIDY[],ASSETCHAINS_REWARD[],ASSETCHAINS_HALVING[],ASSETCHAINS_DECAY[];
|
||||
|
||||
UniValue getinfo(const UniValue& params, bool fHelp)
|
||||
@@ -202,6 +203,8 @@ UniValue getinfo(const UniValue& params, bool fHelp)
|
||||
obj.push_back(Pair("commission", ASSETCHAINS_COMMISSION));
|
||||
if ( ASSETCHAINS_STAKED != 0 )
|
||||
obj.push_back(Pair("staked", ASSETCHAINS_STAKED));
|
||||
if ( ASSETCHAINS_LWMAPOS != 0 )
|
||||
obj.push_back(Pair("verus proof of stake percent", ASSETCHAINS_LWMAPOS));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -222,10 +222,11 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||
return whichType != TX_NONSTANDARD;
|
||||
}
|
||||
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||
bool ExtractDestination(const CScript& _scriptPubKey, CTxDestination& addressRet)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
CScript scriptPubKey = _scriptPubKey;
|
||||
|
||||
// if this is a CLTV script, get the destination after CLTV
|
||||
if (scriptPubKey.IsCheckLockTimeVerify())
|
||||
@@ -234,10 +235,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||
uint32_t scriptStart = pushOp + 3;
|
||||
|
||||
// check post CLTV script
|
||||
CScript postfix = CScript(scriptPubKey.size() > scriptStart ? scriptPubKey.begin() + scriptStart : scriptPubKey.end(), scriptPubKey.end());
|
||||
|
||||
// check again with only postfix subscript
|
||||
return(ExtractDestination(postfix, addressRet));
|
||||
scriptPubKey = CScript(scriptPubKey.size() > scriptStart ? scriptPubKey.begin() + scriptStart : scriptPubKey.end(), scriptPubKey.end());
|
||||
}
|
||||
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
||||
|
||||
@@ -532,7 +532,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||
{
|
||||
uint8_t pubkey33[33];
|
||||
komodo_index2pubkey33(pubkey33,pindexNew,pindexNew->nHeight);
|
||||
if (!CheckProofOfWork(pindexNew->nHeight,pubkey33,pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus(),pindexNew->nTime))
|
||||
if (!CheckProofOfWork(header,pubkey33,pindexNew->nHeight,Params().GetConsensus()))
|
||||
return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
|
||||
}
|
||||
pcursor->Next();
|
||||
|
||||
@@ -19,6 +19,8 @@ uint32_t ASSETCHAINS_MAGIC = 2387029918;
|
||||
uint32_t ASSETCHAINS_EQUIHASH = 0;
|
||||
uint32_t ASSETCHAINS_VERUSHASH = 1;
|
||||
uint32_t ASSETCHAINS_ALGO = 0;
|
||||
int32_t ASSETCHAINS_LWMAPOS = 0;
|
||||
int32_t VERUS_BLOCK_POSUNITS = 1000;
|
||||
|
||||
unsigned int MAX_BLOCK_SIGOPS = 20000;
|
||||
|
||||
|
||||
@@ -4660,3 +4660,8 @@ int32_t komodo_staked(CPubKey &pubkey, CMutableTransaction &txNew,uint32_t nBits
|
||||
}
|
||||
return(siglen);
|
||||
}
|
||||
|
||||
int32_t verus_staked(CPubKey &pubkey, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig)
|
||||
{
|
||||
return pwalletMain->VerusStakeTransaction(pubkey, txNew, nBits, hashResult, utxosig);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ bool fPayAtLeastCustomFee = true;
|
||||
|
||||
extern int32_t KOMODO_EXCHANGEWALLET;
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
CBlockIndex *komodo_chainactive(int32_t height);
|
||||
|
||||
/**
|
||||
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
|
||||
@@ -991,6 +992,105 @@ CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries,
|
||||
return txOrdered;
|
||||
}
|
||||
|
||||
// looks through all wallet UTXOs and checks to see if any qualify to stake the block at the current height. it always returns the qualified
|
||||
// UTXO with the smallest coin age if there is more than one, as larger coin age will win more often and is worth saving
|
||||
// each attempt consists of taking a VerusHash of the following values:
|
||||
// ASSETCHAINS_MAGIC, nHeight, txid, voutNum
|
||||
bool CWallet::VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, const arith_uint256 &target) const
|
||||
{
|
||||
arith_uint256 curHash;
|
||||
vector<COutput> vecOutputs;
|
||||
COutput *pwinner = NULL;
|
||||
CBlockIndex *pastBlockIndex;
|
||||
|
||||
pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
|
||||
|
||||
if (pastBlockIndex = komodo_chainactive(nHeight - COINBASE_MATURITY))
|
||||
{
|
||||
uint256 pastHash = pastBlockIndex->GetBlockHash();
|
||||
|
||||
BOOST_FOREACH(COutput &txout, vecOutputs)
|
||||
{
|
||||
if ((curHash = UintToArith256(txout.tx->GetVerusPOSHash(txout.i, nHeight, pastHash)) / txout.tx->vout[txout.i].nValue) <= target &&
|
||||
txout.fSpendable)
|
||||
{
|
||||
// get the smallest winner
|
||||
if (!pwinner || pwinner->tx->vout[pwinner->i].nValue > txout.tx->vout[txout.i].nValue)
|
||||
pwinner = &txout;
|
||||
}
|
||||
}
|
||||
if (pwinner)
|
||||
{
|
||||
stakeSource = *(pwinner->tx);
|
||||
voutNum = pwinner->i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t CWallet::VerusStakeTransaction(CPubKey &pubkey, CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const
|
||||
{
|
||||
arith_uint256 target;
|
||||
CTransaction stakeSource;
|
||||
int32_t voutNum, siglen = 0;
|
||||
int64_t nValue;
|
||||
|
||||
CBlockIndex *tipindex = chainActive.Tip();
|
||||
bnTarget = lwmaGetNextPOSRequired(tipindex, Params().GetConsensus());
|
||||
target.SetCompact(bnTarget);
|
||||
|
||||
if (!VerusSelectStakeOutput(hashResult, stakeSource, voutNum, tipindex->nHeight, target))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// komodo create transaction code below this line
|
||||
bool signSuccess;
|
||||
SignatureData sigdata;
|
||||
uint64_t txfee;
|
||||
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
txNew.vin.resize(1);
|
||||
txNew.vout.resize(1);
|
||||
txfee = 0;
|
||||
txNew.vin[0].prevout.hash = stakeSource.GetHash();
|
||||
txNew.vin[0].prevout.n = voutNum;
|
||||
|
||||
/*
|
||||
uint8_t *script;
|
||||
int32_t i;
|
||||
uint8_t *ptr;
|
||||
|
||||
txNew.vout[0].scriptPubKey.resize(35);
|
||||
ptr = (uint8_t *)pubkey.begin();
|
||||
script = (uint8_t *)(txNew.vout[0].scriptPubKey.data());
|
||||
script[0] = 33;
|
||||
for (i=0; i<33; i++)
|
||||
script[i+1] = ptr[i];
|
||||
script[34] = OP_CHECKSIG;
|
||||
*/
|
||||
txNew.vout[0].scriptPubKey << ToByteVector(pubkey) << OP_CHECKSIG;
|
||||
|
||||
nValue = txNew.vout[0].nValue = voutNum - txfee;
|
||||
txNew.nLockTime = 0;
|
||||
CTransaction txNewConst(txNew);
|
||||
signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), stakeSource.vout[voutNum].scriptPubKey, sigdata, consensusBranchId);
|
||||
if (!signSuccess)
|
||||
fprintf(stderr,"failed to create signature\n");
|
||||
else
|
||||
{
|
||||
uint8_t *ptr;
|
||||
UpdateTransaction(txNew,0,sigdata);
|
||||
ptr = (uint8_t *)sigdata.scriptSig.data();
|
||||
siglen = sigdata.scriptSig.size();
|
||||
for (int i=0; i<siglen; i++)
|
||||
utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
|
||||
}
|
||||
return(siglen);
|
||||
}
|
||||
|
||||
void CWallet::MarkDirty()
|
||||
{
|
||||
{
|
||||
|
||||
@@ -1148,6 +1148,9 @@ public:
|
||||
bool ignoreSpent=true,
|
||||
bool ignoreUnspendable=true);
|
||||
|
||||
// staking functions
|
||||
bool VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, const arith_uint256 &target) const;
|
||||
int32_t VerusStakeTransaction(CPubKey &pubkey, CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const;
|
||||
};
|
||||
|
||||
/** A key allocated from the key pool. */
|
||||
|
||||
Reference in New Issue
Block a user