internal static void UnpinServerIfNeededOnRetryableCommitException(CoreTransaction transaction, Exception exception)
 {
     if (ShouldUnpinServerOnRetryableCommitException(exception))
     {
         transaction.PinnedServer = null;
     }
 }
Example #2
0
        public void Execute_should_use_serverApi_in_transaction(
            [Values(false, true)] bool useServerApi,
            [Values(false, true)] bool async)
        {
            var serverApi = useServerApi ? new ServerApi(ServerApiVersion.V1, true, true) : null;

            var connection = new MockConnection();

            connection.Description = __connectionDescription;
            var commandResponse = MessageHelper.BuildCommandResponse(CreateRawBsonDocument(new BsonDocument("ok", 1)));

            connection.EnqueueCommandResponseMessage(commandResponse);
            var subject = new CommandWireProtocol <BsonDocument>(
                CreateMockSessionInTransaction(),
                ReadPreference.Primary,
                new DatabaseNamespace("test"),
                new BsonDocument("moreGet", 1),
                commandPayloads: null,
                NoOpElementNameValidator.Instance,
                additionalOptions: null,
                postWriteAction: null,
                CommandResponseHandling.Return,
                BsonDocumentSerializer.Instance,
                new MessageEncoderSettings(),
                serverApi);

            if (async)
            {
                subject.ExecuteAsync(connection, CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                subject.Execute(connection, CancellationToken.None);
            }

            SpinWait.SpinUntil(() => connection.GetSentMessages().Count >= 1, TimeSpan.FromSeconds(4)).Should().BeTrue();

            var sentMessages = MessageHelper.TranslateMessagesToBsonDocuments(connection.GetSentMessages());

            sentMessages.Count.Should().Be(1);
            var actualRequestId         = sentMessages[0]["requestId"].AsInt32;
            var expectedServerApiString = useServerApi ? ", apiVersion : \"1\", apiStrict : true, apiDeprecationErrors : true" : "";

            sentMessages[0].Should().Be($"{{ opcode : \"opmsg\", requestId : {actualRequestId}, responseTo : 0, sections : [ {{ payloadType : 0, document : {{ moreGet : 1, $db : \"test\", txnNumber : NumberLong(1), autocommit : false{expectedServerApiString} }} }} ] }}");

            ICoreSession CreateMockSessionInTransaction()
            {
                var transaction = new CoreTransaction(1, new TransactionOptions());

                transaction.SetState(CoreTransactionState.InProgress);

                var mockSession = new Mock <ICoreSession>();

                mockSession.SetupGet(m => m.CurrentTransaction).Returns(transaction);
                mockSession.SetupGet(m => m.IsInTransaction).Returns(true);

                return(mockSession.Object);
            }
        }
Example #3
0
        private ICoreSession CreateSession(
            CoreTransaction currentTransaction = null,
            bool isCausallyConsistent          = false,
            bool isInTransaction        = false,
            BsonTimestamp operationTime = null)
        {
            var mockSession = new Mock <ICoreSession>();

            mockSession.SetupGet(m => m.CurrentTransaction).Returns(currentTransaction);
            mockSession.SetupGet(m => m.IsCausallyConsistent).Returns(isCausallyConsistent);
            mockSession.SetupGet(m => m.IsInTransaction).Returns(isInTransaction);
            mockSession.SetupGet(m => m.OperationTime).Returns(operationTime);
            return(mockSession.Object);
        }
Example #4
0
        public void GetReadConcernForFirstCommandInTransaction_should_return_expected_result(
            bool isCausallyConsistent,
            int?operationTime,
            string readConcernJson,
            string expectedResult)
        {
            var readConcern        = ReadConcern.FromBsonDocument(BsonDocument.Parse(readConcernJson));
            var transactionOptions = new TransactionOptions(readConcern);
            var transaction        = new CoreTransaction(1, transactionOptions);
            var session            = CreateSession(
                currentTransaction: transaction,
                isCausallyConsistent: isCausallyConsistent,
                operationTime: operationTime.HasValue ? new BsonTimestamp(operationTime.Value) : null);
            var connectionDescription = CreateConnectionDescription(areSessionsSupported: true);

            var result = ReadConcernHelper.GetReadConcernForFirstCommandInTransaction(session, connectionDescription);

            result.Should().Be(expectedResult);
        }
 private static bool IsChannelPinned(CoreTransaction coreTransaction) => coreTransaction?.PinnedChannel != null;
 public TransactionResultTypes ConsumeTransaction(CoreTransaction transaction)
 {
     return(ConsumeTransaction(transaction, false));
 }
        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);
        }
 public CoreItem(long payload, SenderTypes sender, CoreTransaction transaction, Connection connection) : base(payload, sender, connection)
 {
     Transaction = transaction;
 }