public NewTransactionIncludeResult Validate(NodeIndex nodeIndex, OngoingBlock ongoingBlock, Transaction transaction)
        {
            if (!nodeIndex.IsEmpty && nodeIndex.Orders.AllOrders.ContainsKey(transaction.Signature))
            {
                throw new TransactionDeclinedException("Already processed.");
            }

            if (ongoingBlock.Transactions.Any(t => t.Signature == transaction.Signature))
            {
                throw new TransactionDeclinedException("Already received.");
            }

            if (ongoingBlock.Transactions.Any(t => t.User == transaction.User))
            {
                throw new TransactionDeclinedException("Not alowed to request many transaction for one block.");
            }

            UserIndex existUser;

            if (!nodeIndex.IsEmpty && nodeIndex.Users.AllUsers.TryGetValue(transaction.User, out existUser))
            {
                //check that user does not spam transactions. Only 1 transaction per block.
                //This requirement simplify transaction consistency validation
                if (existUser.LastTransaction.Signature != transaction.Previous)
                {
                    throw new TransactionDeclinedException("Wrong user transactions order.");
                }
            }
            else
            {
                existUser = null;
            }

            if (transaction.Message is OrderRequested)
            {
                return(_orderRequestedValidator.Validate(nodeIndex, existUser, ongoingBlock, (OrderRequested)transaction.Message));
            }
            else
            {
                if (transaction.Message is OrdersAssigned)
                {
                    return(_ordersAssignedValidator.Validate(nodeIndex, existUser, ongoingBlock, (OrdersAssigned)transaction.Message));
                }
                else
                {
                    throw new TransactionDeclinedException("Unkown user message type.");
                }
            }
        }
        public NewTransactionIncludeResult Calculate(NodeIndex nodeIndex, OngoingBlock ongoingBlock, OrdersAssigned newOrder)
        {
            var newPrize = _transactionPrizeCalculator.GetPrize(nodeIndex, newOrder);

            var usedOrders = new HashSet <HashValue>(newOrder.Orders);

            var toRemoveTransactionsDic = new Dictionary <HashValue, Transaction>();

            foreach (var ongoingTransaction in ongoingBlock.Transactions)
            {
                if (!(ongoingTransaction.Message is OrdersAssigned))
                {
                    continue;
                }

                var ongoingOrders = ((OrdersAssigned)ongoingTransaction.Message).Orders;
                foreach (var ongoingOrder in ongoingOrders)
                {
                    if (usedOrders.Contains(ongoingOrder))
                    {
                        toRemoveTransactionsDic[ongoingTransaction.Signature] = ongoingTransaction;
                        break;
                    }
                }
            }

            double lostPrize = 0;

            foreach (var t in toRemoveTransactionsDic.Values)
            {
                lostPrize += _transactionPrizeCalculator.GetPrize(nodeIndex, (OrdersAssigned)t.Message);
            }

            if (newPrize <= lostPrize)
            {
                return(NewTransactionIncludeResult.None);
            }

            return(new NewTransactionIncludeResult(toRemoveTransactionsDic.Values.ToArray()));
        }
        public NewTransactionIncludeResult Validate(NodeIndex nodeIndex, UserIndex userIndex, OngoingBlock ongoingBlock, OrdersAssigned message)
        {
            if (message.Fee < 0 || message.Fee > 1)
            {
                throw new TransactionDeclinedException("Invalid Fee.");
            }

            if (message.Orders.Count == 0)
            {
                throw new TransactionDeclinedException("Empty orders.");
            }

            return(_bestPrizeTransactionsSelector.Calculate(nodeIndex, ongoingBlock, message));
        }
        public NewTransactionIncludeResult Validate(NodeIndex nodeIndex, UserIndex userIndex, OngoingBlock ongoingBlock, OrderRequested message)
        {
            var order = message.Order;

            if (order.Payment <= 0)
            {
                throw new TransactionDeclinedException("Invalid order Payment.");
            }

            var validator = _validators[order.OrderType];

            validator.Validate(nodeIndex, userIndex, order);

            return(NewTransactionIncludeResult.Include);
        }