Exemplo n.º 1
0
        public async Task <bool> OnMessage(CouncilMessage message, NodeConnection connection)
        {
            if (_containers.TryGetValue(message.ChainId, out var container))
            {
                var council = container.GetCouncil(message.ChainType, message.ChainIndex);
                if (council == null)
                {
                    return(false);
                }

                var key = _coreChain.GetValidPublicChainKeyWithFlags(council.ChainId, council.ChainIndex, council.LocalKeyIndex, council.RequiresChainKeyFlags, Time.Timestamp);
                if (!message.IsValidCouncilMemberSignature(key?.PublicKey))
                {
                    return(false);
                }

                await council.OnMessage(message, connection);
            }

            return(false);
        }
Exemplo n.º 2
0
        TransactionResultTypes ConsumeTransaction(CoreTransaction transaction, bool addExtraTime)
        {
            if (transaction.IsExpired(addExtraTime))
            {
                return(TransactionResultTypes.Expired);
            }

            var r = _coreChain.BlockStorage.HistoryContainsTransactionOrRegistration(transaction);

            if (r != TransactionResultTypes.Ok)
            {
                return(r);
            }

            var coreType = transaction.TransactionType;

            if (coreType != CoreTransactionTypes.AccountRegistration)
            {
                var account = GetCoreAccount(transaction.AccountId);
                if (account == null)
                {
                    return(TransactionResultTypes.InvalidCoreAccount);
                }

                var key = account.AccountKey;

                if (coreType == CoreTransactionTypes.ChainUpdate)
                {
                    var update   = transaction as ChainUpdateCoreTransaction;
                    var chain    = GetChainInfo(update.ChainId);
                    var keyIndex = update.SignKeyIndex;

                    if (keyIndex != Protocol.CoreAccountSignKeyIndex)
                    {
                        var result = CheckChainKey(update.ChainId, keyIndex, true, ref key);
                        if (result != TransactionResultTypes.Ok)
                        {
                            return(result);
                        }
                    }
                    else if (transaction.AccountId != chain.AccountId)
                    {
                        return(TransactionResultTypes.InvalidCoreAccount);
                    }
                }
                else if (coreType == CoreTransactionTypes.ServiceBlock)
                {
                    var serviceBlockTransaction = transaction as ServiceBlockCoreTransaction;
                    var block = serviceBlockTransaction.ServiceBlock;
                    key = _coreChain.GetValidPublicChainKeyWithFlags(block.ChainId, block.ChainIndex, block.Issuer, PublicChainKeyFlags.ServiceChainVoteKey, transaction.Timestamp)?.PublicKey;
                }

                if (!transaction.IsSignatureValid(key))
                {
                    return(TransactionResultTypes.InvalidSignature);
                }
            }
            else
            {
                var register = transaction as AccountRegistrationCoreTransaction;
                if (!transaction.IsSignatureValid(register.PublicKey))
                {
                    return(TransactionResultTypes.InvalidSignature);
                }
            }

            if (coreType == CoreTransactionTypes.AccountRegistration)
            {
                var registration = transaction as AccountRegistrationCoreTransaction;
                var account      = new CoreAccount(NextAccountId, registration.PublicKey);
                _accounts[account.AccountId] = account;
                NextAccountId++;

                _blockInfo.AddNewAccount(registration, account);

                return(TransactionResultTypes.Ok);
            }

            if (coreType == CoreTransactionTypes.ChainRegistration || coreType == CoreTransactionTypes.ChainUpdate)
            {
                var update       = transaction as ChainUpdateCoreTransaction;
                var registration = transaction as ChainRegistrationCoreTransaction;
                var isUpdate     = update != null;

                var account = GetCoreAccount(transaction.AccountId);
                if (account == null)
                {
                    return(TransactionResultTypes.InvalidCoreAccount);
                }

                ChainInfo chain = null;
                if (isUpdate)
                {
                    chain = GetChainInfo(update.ChainId);
                    if (chain == null)
                    {
                        return(TransactionResultTypes.ChainNotFound);
                    }
                }

                if (!registration.ChainWebsite.IsValdiUrl())
                {
                    return(TransactionResultTypes.InvalidChainWebsite);
                }

                if (registration.ChainName != null && registration.ChainName.Length > ChainRegistrationCoreTransaction.MaxNameLength)
                {
                    return(TransactionResultTypes.InvalidChainName);
                }

                foreach (var endPoint in registration.PublicEndpoints)
                {
                    if (!endPoint.IsValdiUrl(false))
                    {
                        return(TransactionResultTypes.InvalidChainEndpoint);
                    }
                }

                var indices = new HashSet <short>();
                foreach (var chainKey in registration.ChainKeys)
                {
                    if (indices.Contains(chainKey.KeyIndex))
                    {
                        return(TransactionResultTypes.InvaidChainKey);
                    }

                    indices.Add(chainKey.KeyIndex);
                }

                foreach (var purchase in registration.Purchases)
                {
                    if (purchase.PurchaseType == PurchaseTypes.None)
                    {
                        return(TransactionResultTypes.InvalidChainPurchase);
                    }

                    foreach (var p in registration.Purchases)
                    {
                        if (purchase == p)
                        {
                            continue;
                        }

                        if (p.PurchaseItemId == purchase.PurchaseItemId && p.PurchaseGroupId == purchase.PurchaseGroupId)
                        {
                            return(TransactionResultTypes.InvalidChainPurchase);
                        }

                        if (p.PurchaseGroupId == purchase.PurchaseGroupId && p.PurchaseType != purchase.PurchaseType)
                        {
                            return(TransactionResultTypes.InvalidChainPurchase);
                        }
                    }
                }

                if (!isUpdate)
                {
                    chain = new ChainInfo(NextChainId, registration.AccountId, registration.ChainName, registration.ChainWebsite);
                    var operation = new ChainInfoOperation(chain.ChainId, chain.AccountId, chain.Name, chain.Website, registration.Timestamp, registration.ChainKeys, registration.PublicEndpoints, registration.Purchases);

                    _chains[chain.ChainId] = chain;
                    NextChainId++;

                    _blockInfo.AddChainUpdate(registration, operation);
                }
                else
                {
                    var result = chain.IsUpdateValid(update);
                    if (result != TransactionResultTypes.Ok)
                    {
                        return(result);
                    }

                    var operation = new ChainInfoOperation(chain.ChainId, update.AccountId, update.ChainName, update.ChainWebsite, registration.Timestamp, update.ChainKeys, update.PublicEndpoints, update.Purchases, update.RevokeChainKeys, update.RemovePublicEndPoints, update.RemovePurchaseItems);
                    _blockInfo.AddChainUpdate(update, operation);
                }

                return(TransactionResultTypes.Ok);
            }

            if (coreType == CoreTransactionTypes.Transfer)
            {
                var transfer = transaction as TransferCoreTransaction;

                if (!AccountUpdateOperation.IsReasonValid(transfer.Reason))
                {
                    return(TransactionResultTypes.InvalidTransferReason);
                }

                if (transfer.AccountId == transfer.ReceiverAccountId)
                {
                    return(TransactionResultTypes.InvalidReceiverAccount);
                }

                var sender   = GetCoreAccount(transfer.AccountId);
                var receiver = GetCoreAccount(transfer.ReceiverAccountId);
                if (receiver == null)
                {
                    return(TransactionResultTypes.InvalidReceiverAccount);
                }

                if (sender != null)
                {
                    var amount = transfer.Amount;
                    if (sender.CanTransfer(amount))
                    {
                        sender.RemoveFromTranfser(amount);
                        receiver.AddFromTransfer(amount);

                        _blockInfo.AddTransfer(transfer);
                        return(TransactionResultTypes.Ok);
                    }
                    return(TransactionResultTypes.InsuficientBalance);
                }
                return(TransactionResultTypes.InvalidTransaction);
            }

            if (coreType == CoreTransactionTypes.ServiceBlock)
            {
                var serviceBlockTransaction = (transaction as ServiceBlockCoreTransaction);
                var block = serviceBlockTransaction.ServiceBlock;

                var chainInfo = GetChainInfo(block.ChainId);
                if (chainInfo == null)
                {
                    return(TransactionResultTypes.ChainNotFound);
                }

                if (block.TransactionCount == 0)
                {
                    return(TransactionResultTypes.InvalidTransaction);
                }

                var state = chainInfo.LastState;
                if ((state.BlockId + 1) != block.BlockId)
                {
                    return(TransactionResultTypes.InvalidBlock);
                }

                foreach (var serviceTransaction in block.Transactions)
                {
                    var serviceType = serviceTransaction.TransactionType;
                    var accountId   = serviceTransaction.AccountId;
                    var account     = GetCoreAccount(accountId);

                    if (account == null)
                    {
                        return(TransactionResultTypes.InvalidCoreAccount);
                    }

                    if (!serviceTransaction.IsSignatureValid(account.AccountKey))
                    {
                        return(TransactionResultTypes.InvalidSignature);
                    }

                    if (serviceType == ServiceTransactionTypes.Join)
                    {
                        var joinTransaction = serviceTransaction as JoinServiceTransaction;
                        var key             = joinTransaction.AccountKey;

                        if (key == null || (key != null && key.IsKeySignatureValid(account.AccountKey)))
                        {
                            continue;
                        }

                        return(TransactionResultTypes.InvalidSignature);
                    }

                    if (serviceType == ServiceTransactionTypes.Purchase)
                    {
                        var purchaseTransaction = serviceTransaction as PurchaseServiceTransaction;

                        var buyer    = GetCoreAccount(purchaseTransaction.AccountId);
                        var receiver = GetCoreAccount(purchaseTransaction.ReceiverAccountId);
                        if (buyer != null && receiver != null && chainInfo.IsPurchaseValid(purchaseTransaction.PurchaseGroupId, purchaseTransaction.PurchaseItemId, purchaseTransaction.Price))
                        {
                            var chainAccount = GetCoreAccount(chainInfo.AccountId);
                            if (chainAccount != null && buyer.CanPurchase(purchaseTransaction.Price))
                            {
                                //buyer.Purchase(purchaseTransaction.Price, chainAccount);
                                continue;
                            }
                            return(TransactionResultTypes.CannotPurchase);
                        }

                        return(TransactionResultTypes.InvalidCoreAccount);
                    }

                    if (serviceType == ServiceTransactionTypes.RequestRevenue)
                    {
                        var totalRevenue    = chainInfo.GetTotalAccountRevenue(transaction.Timestamp);
                        var totalPayout     = chainInfo.TotalAccountPayout;
                        var availablePayout = totalRevenue - totalPayout;

                        var revenueTransaction = serviceTransaction as RequestRevenueServiceTransaction;

                        if (availablePayout >= revenueTransaction.PayoutAmount)
                        {
                            continue;
                        }
                    }

                    return(TransactionResultTypes.InvalidTransaction);
                }

                if (!_coreChain.IsBlockProposalSignatureValid(block, serviceBlockTransaction.ProposalSignatures))
                {
                    return(TransactionResultTypes.InvalidBlockSignature);
                }

                _blockInfo.AddServiceBlock(serviceBlockTransaction);
                return(TransactionResultTypes.Ok);
            }

            return(TransactionResultTypes.InvalidTransaction);
        }