public static bool CheckKernel(IBlockRepository blockStore, ITransactionRepository trasnactionStore, IBlockTransactionMapStore mapStore, StakeChain stakeChain, ChainedBlock pindexPrev, uint nBits, long nTime, OutPoint prevout, ref long pBlockTime) { uint256 hashProofOfStake = null, targetProofOfStake = null; var txPrev = trasnactionStore.Get(prevout.Hash); if (txPrev == null) { return(false); } // Read block header var blockHashPrev = mapStore.GetBlockHash(prevout.Hash); var block = blockHashPrev == null ? null : blockStore.GetBlock(blockHashPrev); if (block == null) { return(false); } if (IsProtocolV3((int)nTime)) { int nDepth = 0; if (IsConfirmedInNPrevBlocks(blockStore, txPrev, pindexPrev, StakeMinConfirmations - 1, ref nDepth)) { return(false); // tx.DoS(100, error("CheckProofOfStake() : tried to stake at depth %d", nDepth + 1)); } } else { var nTimeBlockFrom = block.Header.Time; if (nTimeBlockFrom + StakeMinAge > nTime) { return(false); // error("CheckProofOfStake() : min age violation"); } } var prevBlockStake = stakeChain.Get(pindexPrev.HashBlock); if (prevBlockStake == null) { return(false); // the stake proof of the previous block is not set } // todo: check this unclear logic //if (pBlockTime) // pBlockTime = block.Header.Time; return(CheckStakeKernelHash(pindexPrev, nBits, block, txPrev, prevBlockStake, prevout, (uint)nTime, out hashProofOfStake, out targetProofOfStake, false)); }
// Check kernel hash target and coinstake signature public static bool CheckProofOfStake(IBlockRepository blockStore, ITransactionRepository trasnactionStore, IBlockTransactionMapStore mapStore, ChainedBlock pindexPrev, BlockStake prevBlockStake, Transaction tx, uint nBits, out uint256 hashProofOfStake, out uint256 targetProofOfStake) { targetProofOfStake = null; hashProofOfStake = null; // todo: Comments on this mehtod: // the store objects (IBlockRepository and ITransactionRepository) should be a singleton instance of // the BlockValidator and would be initiated as part of a Dependency Injection freamwork if (!tx.IsCoinStake) { return(false); // error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString()); } // Kernel (input 0) must match the stake hash target per coin age (nBits) var txIn = tx.Inputs[0]; // First try finding the previous transaction in database var txPrev = trasnactionStore.Get(txIn.PrevOut.Hash); if (txPrev == null) { return(false); // tx.DoS(1, error("CheckProofOfStake() : INFO: read txPrev failed")); // previous transaction not in main chain, may occur during initial download } // Verify signature if (!VerifySignature(txPrev, tx, 0, ScriptVerify.None)) { return(false); // tx.DoS(100, error("CheckProofOfStake() : VerifySignature failed on coinstake %s", tx.GetHash().ToString())); } // Read block header var blockHashPrev = mapStore.GetBlockHash(txIn.PrevOut.Hash); var block = blockHashPrev == null ? null : blockStore.GetBlock(blockHashPrev); if (block == null) { return(false); //fDebug? error("CheckProofOfStake() : read block failed") : false; // unable to read block of previous transaction } // Min age requirement if (IsProtocolV3((int)tx.Time)) { int nDepth = 0; if (IsConfirmedInNPrevBlocks(blockStore, txPrev, pindexPrev, StakeMinConfirmations - 1, ref nDepth)) { return(false); // tx.DoS(100, error("CheckProofOfStake() : tried to stake at depth %d", nDepth + 1)); } } else { var nTimeBlockFrom = block.Header.Time; if (nTimeBlockFrom + StakeMinAge > tx.Time) { return(false); // error("CheckProofOfStake() : min age violation"); } } if (!CheckStakeKernelHash(pindexPrev, nBits, block, txPrev, prevBlockStake, txIn.PrevOut, tx.Time, out hashProofOfStake, out targetProofOfStake, false)) { return(false); // tx.DoS(1, error("CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s", tx.GetHash().ToString(), hashProofOfStake.ToString())); // may occur during initial download or if behind on block chain sync } return(true); }
public const uint ModifierInterval = 10 * 60; // time to elapse before new modifier is computed public static bool CheckAndComputeStake(IBlockRepository blockStore, ITransactionRepository trasnactionStore, IBlockTransactionMapStore mapStore, StakeChain stakeChain, ChainBase chainIndex, ChainedBlock pindex, Block block, out BlockStake blockStake) { if (block.GetHash() != pindex.HashBlock) { throw new ArgumentException(); } blockStake = new BlockStake(block); uint256 hashProof = null; // Verify hash target and signature of coinstake tx if (BlockStake.IsProofOfStake(block)) { var pindexPrev = pindex.Previous; var prevBlockStake = stakeChain.Get(pindexPrev.HashBlock); if (prevBlockStake == null) { return(false); // the stake proof of the previous block is not set } uint256 targetProofOfStake; if (!CheckProofOfStake(blockStore, trasnactionStore, mapStore, pindexPrev, prevBlockStake, block.Transactions[1], pindex.Header.Bits.ToCompact(), out hashProof, out targetProofOfStake)) { return(false); // error("AcceptBlock() : check proof-of-stake failed for block %s", hash.ToString()); } } // PoW is checked in CheckBlock() if (BlockStake.IsProofOfWork(block)) { hashProof = pindex.Header.GetPoWHash(); } // todo: is this the same as chain work? // compute chain trust score //pindexNew.nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + pindexNew->GetBlockTrust(); // compute stake entropy bit for stake modifier if (!blockStake.SetStakeEntropyBit(blockStake.GetStakeEntropyBit())) { return(false); //error("AddToBlockIndex() : SetStakeEntropyBit() failed"); } // Record proof hash value blockStake.HashProof = hashProof; // compute stake modifier return(ComputeStakeModifier(chainIndex, pindex, blockStake, stakeChain)); }
// ppcoin: total coin age spent in transaction, in the unit of coin-days. // Only those coins meeting minimum age requirement counts. As those // transactions not in main chain are not currently indexed so we // might not find out about their coin age. Older transactions are // guaranteed to be in main chain by sync-checkpoint. This rule is // introduced to help nodes establish a consistent view of the coin // age (trust score) of competing branches. public static bool GetCoinAge(IBlockRepository blockStore, ITransactionRepository trasnactionStore, IBlockTransactionMapStore mapStore, Transaction trx, ChainedBlock pindexPrev, out ulong nCoinAge) { BigInteger bnCentSecond = BigInteger.Zero; // coin age in the unit of cent-seconds nCoinAge = 0; if (trx.IsCoinBase) { return(true); } foreach (var txin in trx.Inputs) { // First try finding the previous transaction in database Transaction txPrev = trasnactionStore.Get(txin.PrevOut.Hash); if (txPrev == null) { continue; // previous transaction not in main chain } if (trx.Time < txPrev.Time) { return(false); // Transaction timestamp violation } if (IsProtocolV3((int)trx.Time)) { int nSpendDepth = 0; if (IsConfirmedInNPrevBlocks(blockStore, txPrev, pindexPrev, StakeMinConfirmations - 1, ref nSpendDepth)) { //LogPrint("coinage", "coin age skip nSpendDepth=%d\n", nSpendDepth + 1); continue; // only count coins meeting min confirmations requirement } } else { // Read block header var block = blockStore.GetBlock(txPrev.GetHash()); if (block == null) { return(false); // unable to read block of previous transaction } if (block.Header.Time + StakeMinAge > trx.Time) { continue; // only count coins meeting min age requirement } } long nValueIn = txPrev.Outputs[txin.PrevOut.N].Value; var multiplier = BigInteger.ValueOf((trx.Time - txPrev.Time) / CENT); bnCentSecond = bnCentSecond.Add(BigInteger.ValueOf(nValueIn).Multiply(multiplier)); //bnCentSecond += new BigInteger(nValueIn) * (trx.Time - txPrev.Time) / CENT; //LogPrint("coinage", "coin age nValueIn=%d nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString()); } BigInteger bnCoinDay = bnCentSecond.Multiply(BigInteger.ValueOf(CENT / COIN / (24 * 60 * 60))); //BigInteger bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60); //LogPrint("coinage", "coin age bnCoinDay=%s\n", bnCoinDay.ToString()); nCoinAge = new Target(bnCoinDay).ToCompact(); return(true); }