Example #1
0
        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));
        }
Example #2
0
        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));
        }
Example #3
0
        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));
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        // 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);
        }