// 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 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)); }