public ServiceBlockGenerator(CoreChain coreChain, ServiceChain serviceChain, MaintainChain maintainChain, ServiceBlock lastBlock)
        {
            ChainId = serviceChain.ChainId;

            _blockInfo     = new ServiceBlockInfo(serviceChain);
            _coreChain     = coreChain;
            _serviceChain  = serviceChain;
            _maintainChain = maintainChain;
            _lastBlock     = lastBlock;
            _chainInfo     = coreChain.GetChainInfo(ChainId);
            _blockState    = _chainInfo.LastState;
        }
        public ServiceBlock GenerateBlock(short issuer, int revision, long timestamp)
        {
            if (!IsValid)
            {
                return(null);
            }

            var nextTransactionId   = Operation.FirstTransactionId;
            var blockId             = Protocol.GenesisBlockId;
            var previousHash        = Hash.Empty(Protocol.TransactionHashType);
            var lastTransactionHash = Hash.Empty(ValidationOperation.ValidationHashType);

            if (_lastBlock != null)
            {
                blockId             = _lastBlock.BlockId + 1;
                nextTransactionId   = _blockState.LastTransactionId + 1;
                previousHash        = _lastBlock.BlockHash;
                lastTransactionHash = _lastBlock.Items.Last().Validation.Hash;
            }

            _blockInfo.Sort();

            var transactions = new List <ServiceTransaction>();

            foreach (var transaction in _blockInfo.Transactions)
            {
                var accountId = transaction.AccountId;

                transaction.MetaData.SetTransactionId(nextTransactionId);

                transactions.Add(transaction);

                _blockInfo.FeatureGenerator.ProcessTransaction(transaction);

                ++nextTransactionId;
            }

            var block = new ServiceBlock(transactions, Protocol.Version, blockId, ChainId, issuer, revision, timestamp, previousHash, lastTransactionHash);

            // return a copy of the block and all its transactions
            // if we don't do this, transaction ids might change during another generator run and we get invalid ids
            return(Block.Restore <ServiceBlock>(block.BlockData));
        }
        public HashSet <long> CheckBlock(ServiceBlock block)
        {
            var invalid = new HashSet <long>();

            foreach (var transaction in block.Transactions)
            {
                var result = ConsumeTransaction(transaction, true); // add some extra time when checking blocks
                if (result != TransactionResultTypes.Ok)
                {
                    invalid.Add(transaction.TransactionId);
                }
            }

            var newBlock = GenerateBlock(block.Issuer, block.Revision, block.Timestamp);

            if (newBlock == null || newBlock.BlockHash != block.BlockHash)
            {
                if (newBlock != null)
                {
                    var count = newBlock.Items.Count;
                    for (var i = 0; i < count; i++)
                    {
                        var op1 = newBlock.Items[i].Validation;
                        var op2 = block.Items[i].Validation;

                        if (op1.Hash != op2.Hash)
                        {
                            invalid.Add(block.Items[i].Transaction.TransactionId);
                        }
                    }
                }

                if (invalid.Count <= 0)
                {
                    invalid.Add(Protocol.InvalidBlockId);
                }
            }

            return(invalid);
        }