public static bool IsCanonicalBlockSignature(Block block, bool checkLowS) { if (BlockStake.IsProofOfWork(block)) { return(block.BlockSignatur.IsEmpty()); } return(checkLowS ? ScriptEvaluationContext.IsLowDerSignature(block.BlockSignatur.Signature) : ScriptEvaluationContext.IsValidSignatureEncoding(block.BlockSignatur.Signature)); }
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)); }
public bool CheckPowPosAndTarget(ChainedBlock chainedBlock, BlockStake blockStake, Consensus consensus) { if (chainedBlock.Height == 0) { return(true); } if (blockStake.IsProofOfWork() && !chainedBlock.Header.CheckProofOfWork()) { return(false); } return(chainedBlock.Header.Bits == this.GetWorkRequired(chainedBlock, blockStake, consensus)); }
public static bool CheckBlockSignature(Block block) { if (BlockStake.IsProofOfWork(block)) { return(block.BlockSignatur.IsEmpty()); } if (block.BlockSignatur.IsEmpty()) { return(false); } var txout = block.Transactions[1].Outputs[1]; if (PayToPubkeyTemplate.Instance.CheckScriptPubKey(txout.ScriptPubKey)) { var pubKey = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(txout.ScriptPubKey); return(pubKey.Verify(block.GetHash(), new ECDSASignature(block.BlockSignatur.Signature))); } if (IsProtocolV3((int)block.Header.Time)) { // Block signing key also can be encoded in the nonspendable output // This allows to not pollute UTXO set with useless outputs e.g. in case of multisig staking var ops = txout.ScriptPubKey.ToOps().ToList(); if (!ops.Any()) // script.GetOp(pc, opcode, vchPushValue)) { return(false); } if (ops.ElementAt(0).Code != OpcodeType.OP_RETURN) // OP_RETURN) { return(false); } if (ops.Count < 2) // script.GetOp(pc, opcode, vchPushValue) { return(false); } var data = ops.ElementAt(1).PushData; if (!ScriptEvaluationContext.IsCompressedOrUncompressedPubKey(data)) { return(false); } return(new PubKey(data).Verify(block.GetHash(), new ECDSASignature(block.BlockSignatur.Signature))); } return(false); }
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); }
// 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); }