/// <summary> /// Check PoW and that the blocks connect correctly /// </summary> /// <param name="network">The network being used</param> /// <returns>True if PoW is correct</returns> public bool Validate(Network network) { if (network == null) { throw new ArgumentNullException("network"); } if (Height != 0 && Previous == null) { return(false); } if (Block.BlockSignature) { return(BlockStake.Validate(network, this)); } var heightCorrect = Height == 0 || Height == Previous.Height + 1; var genesisCorrect = Height != 0 || HashBlock == network.GetGenesis().GetHash(); var hashPrevCorrect = Height == 0 || Header.HashPrevBlock == Previous.HashBlock; var hashCorrect = HashBlock == Header.GetHash(); var workCorrect = CheckProofOfWorkAndTarget(network); return(heightCorrect && genesisCorrect && hashPrevCorrect && hashCorrect && workCorrect); }
public static bool CheckProofOfStake(this Block block) { return(BlockStake.CheckProofOfStake(block)); }
public Target GetWorkRequired(ChainedBlock chainedBlock, BlockStake blockStake, Consensus consensus) { return(BlockValidator.GetNextTargetRequired(this, chainedBlock.Previous, consensus, blockStake.IsProofOfStake())); }
public bool CheckPowPosAndTarget(ChainedBlock chainedBlock, BlockStake blockStake, Network network) { return(this.CheckPowPosAndTarget(chainedBlock, blockStake, network.Consensus)); }
public abstract void Set(uint256 blockid, BlockStake blockStake);
public static bool Check(Block block) { return(block.CheckMerkleRoot() && BlockStake.CheckProofOfWork(block) && BlockStake.CheckProofOfStake(block)); }
public static bool ComputeStakeModifier(ChainBase chainIndex, ChainedBlock pindex, BlockStake blockStake, StakeChain stakeChain) { var pindexPrev = pindex.Previous; var blockStakePrev = pindexPrev == null ? null : stakeChain.Get(pindexPrev.HashBlock); // compute stake modifier ulong nStakeModifier; bool fGeneratedStakeModifier; if (!ComputeNextStakeModifier(stakeChain, chainIndex, pindexPrev, out nStakeModifier, out fGeneratedStakeModifier)) { return(false); //error("AddToBlockIndex() : ComputeNextStakeModifier() failed"); } blockStake.SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); blockStake.StakeModifierV2 = ComputeStakeModifierV2( pindexPrev, blockStakePrev, blockStake.IsProofOfWork() ? pindex.HashBlock : blockStake.PrevoutStake.Hash); return(true); }
// Stratis kernel protocol // coinstake must meet hash target according to the protocol: // kernel (input 0) must meet the formula // hash(nStakeModifier + txPrev.block.nTime + txPrev.nTime + txPrev.vout.hash + txPrev.vout.n + nTime) < bnTarget * nWeight // this ensures that the chance of getting a coinstake is proportional to the // amount of coins one owns. // The reason this hash is chosen is the following: // nStakeModifier: scrambles computation to make it very difficult to precompute // future proof-of-stake // txPrev.block.nTime: prevent nodes from guessing a good timestamp to // generate transaction for future advantage, // obsolete since v3 // txPrev.nTime: slightly scrambles computation // txPrev.vout.hash: hash of txPrev, to reduce the chance of nodes // generating coinstake at the same time // txPrev.vout.n: output number of txPrev, to reduce the chance of nodes // generating coinstake at the same time // nTime: current timestamp // block/tx hash should not be used here as they can be generated in vast // quantities so as to generate blocks faster, degrading the system back into // a proof-of-work situation. // private static bool CheckStakeKernelHashV2(ChainedBlock pindexPrev, uint nBits, uint nTimeBlockFrom, BlockStake prevBlockStake, Transaction txPrev, OutPoint prevout, uint nTimeTx, out uint256 hashProofOfStake, out uint256 targetProofOfStake, bool fPrintProofOfStake) { targetProofOfStake = null; hashProofOfStake = null; if (nTimeTx < txPrev.Time) // Transaction timestamp violation { return(false); //error("CheckStakeKernelHash() : nTime violation"); } // Base target var bnTarget = new Target(nBits).ToBigInteger(); // Weighted target var nValueIn = txPrev.Outputs[prevout.N].Value.Satoshi; var bnWeight = BigInteger.ValueOf(nValueIn); bnTarget = bnTarget.Multiply(bnWeight); // todo: investigate this issue, is the convertion to uint256 similar to the c++ implementation //targetProofOfStake = Target.ToUInt256(bnTarget); var nStakeModifier = prevBlockStake.StakeModifier; //pindexPrev.Header.BlockStake.StakeModifier; uint256 bnStakeModifierV2 = prevBlockStake.StakeModifierV2; //pindexPrev.Header.BlockStake.StakeModifierV2; int nStakeModifierHeight = pindexPrev.Height; var nStakeModifierTime = pindexPrev.Header.Time; // Calculate hash using (var ms = new MemoryStream()) { var serializer = new BitcoinStream(ms, true); if (IsProtocolV3((int)nTimeTx)) { serializer.ReadWrite(bnStakeModifierV2); } else { serializer.ReadWrite(nStakeModifier); serializer.ReadWrite(nTimeBlockFrom); } serializer.ReadWrite(txPrev.Time); serializer.ReadWrite(prevout.Hash); serializer.ReadWrite(prevout.N); serializer.ReadWrite(nTimeTx); hashProofOfStake = Hashes.Hash256(ms.ToArray()); } if (fPrintProofOfStake) { //LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from timestamp=%s\n", // nStakeModifier, nStakeModifierHeight, // DateTimeStrFormat(nStakeModifierTime), // DateTimeStrFormat(nTimeBlockFrom)); //LogPrintf("CheckStakeKernelHash() : check modifier=0x%016x nTimeBlockFrom=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", // nStakeModifier, // nTimeBlockFrom, txPrev.nTime, prevout.n, nTimeTx, // hashProofOfStake.ToString()); } // Now check if proof-of-stake hash meets target protocol var hashProofOfStakeTarget = new BigInteger(hashProofOfStake.ToBytes(false)); if (hashProofOfStakeTarget.CompareTo(bnTarget) > 0) { return(false); } // if (fDebug && !fPrintProofOfStake) // { // LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from timestamp=%s\n", // nStakeModifier, nStakeModifierHeight, // DateTimeStrFormat(nStakeModifierTime), // DateTimeStrFormat(nTimeBlockFrom)); // LogPrintf("CheckStakeKernelHash() : pass modifier=0x%016x nTimeBlockFrom=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", // nStakeModifier, // nTimeBlockFrom, txPrev.nTime, prevout.n, nTimeTx, // hashProofOfStake.ToString()); // } return(true); }
private static bool CheckStakeKernelHash(ChainedBlock pindexPrev, uint nBits, Block blockFrom, Transaction txPrev, BlockStake prevBlockStake, OutPoint prevout, uint nTimeTx, out uint256 hashProofOfStake, out uint256 targetProofOfStake, bool fPrintProofOfStake) { targetProofOfStake = null; hashProofOfStake = null; if (IsProtocolV2(pindexPrev.Height + 1)) { return(CheckStakeKernelHashV2(pindexPrev, nBits, blockFrom.Header.Time, prevBlockStake, txPrev, prevout, nTimeTx, out hashProofOfStake, out targetProofOfStake, fPrintProofOfStake)); } else { return(CheckStakeKernelHashV1()); } }
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)); }
// a method to check a block, this may be moved to the full node. public static bool CheckBlock(Block block, bool checkPow = true, bool checkMerkleRoot = true, bool checkSig = true) { // These are checks that are independent of context // that can be verified before saving an orphan block. // Size limits if (!block.Transactions.Any() || block.GetSerializedSize() > MAX_BLOCK_SIZE) { return(false); // DoS(100, error("CheckBlock() : size limits failed")); } // Check proof of work matches claimed amount if (checkPow && BlockStake.IsProofOfWork(block) && !block.CheckProofOfWork()) { return(false); //DoS(50, error("CheckBlock() : proof of work failed")); } // Check timestamp if (block.Header.Time > FutureDriftV2(DateTime.UtcNow.Ticks)) //GetAdjustedTime())) { return(false); //error("CheckBlock() : block timestamp too far in he future"); } // First transaction must be coinbase, the rest must not be if (!block.Transactions[0].IsCoinBase) { return(false); // DoS(100, error("CheckBlock() : first tx is not coinbase")); } if (block.Transactions.Skip(1).Any(t => t.IsCoinBase)) { return(false); //DoS(100, error("CheckBlock() : more than one coinbase")); } if (BlockStake.IsProofOfStake(block)) { // Coinbase output should be empty if proof-of-stake block if (block.Transactions[0].Outputs.Count != 1 || !block.Transactions[0].Outputs[0].IsEmpty) { return(false); // DoS(100, error("CheckBlock() : coinbase output not empty for proof-of-stake block")); } // Second transaction must be coinstake, the rest must not be if (!block.Transactions[1].IsCoinStake) { return(false); // DoS(100, error("CheckBlock() : second tx is not coinstake")); } if (block.Transactions.Skip(2).Any(t => t.IsCoinStake)) { return(false); //DoS(100, error("CheckBlock() : more than one coinstake")); } } // Check proof-of-stake block signature if (checkSig && !CheckBlockSignature(block)) { return(false); //DoS(100, error("CheckBlock() : bad proof-of-stake block signature")); } // Check transactions foreach (var transaction in block.Transactions) { if (transaction.Check() != TransactionCheckResult.Success) { return(false); // DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); } // ppcoin: check transaction timestamp if (block.Header.Time < transaction.Time) { return(false); // DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); } } // Check for duplicate txids. This is caught by ConnectInputs(), // but catching it earlier avoids a potential DoS attack: var set = new HashSet <uint256>(); if (block.Transactions.Select(t => t.GetHash()).Any(h => !set.Add(h))) { return(false); //DoS(100, error("CheckBlock() : duplicate transaction")); } // todo: check if this is legacy from older implementtions and actually needed //uint nSigOps = 0; //foreach (var transaction in block.Transactions) //{ // nSigOps += GetLegacySigOpCount(transaction); //} //if (nSigOps > MAX_BLOCK_SIGOPS) // return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); // Check merkle root if (checkMerkleRoot && !block.CheckMerkleRoot()) { return(false); //DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); } return(true); }
public sealed override void Set(uint256 blockid, BlockStake blockStake) { // throw if item already exists this.items.Add(blockid, blockStake); }