string RefreseHash(string hash)
        {
            var array = HelperTools.HexStringToByteArray(hash);

            Array.Reverse(array);
            return(HelperTools.ByteToHexString(array));
        }
        public async Task <PrevTxOutput> GetPrevOutAsync(byte[] prevOutTxId, long prevOutN)
        {
            PrevTxOutput foundPrevOut;

            lock (prevTxOutputCache)
            {
                prevTxOutputCache.Cache.TryGetValue($"{HelperTools.ByteToHexString(prevOutTxId)}_{prevOutN}", out foundPrevOut);
            }
            if (foundPrevOut == null)
            {
                using var connection = GetDbConnection();

                string cmdText = @"
SELECT tx.txInternalId, tx.txExternalId, txinput.n
FROM tx 
INNER JOIN txinput ON txinput.txInternalId = tx.txInternalId
WHERE tx.txExternalId = @prevOutTxId
AND txinput.n = @prevOutN;
";
                foundPrevOut = await connection.QueryFirstOrDefaultAsync <PrevTxOutput>(cmdText, new { prevOutTxId, prevOutN });

                if (foundPrevOut != null)
                {
                    CachePrevOut(foundPrevOut);
                }
            }
            else
            {
                logger.LogInformation($"GetPrevOutAsync: prevOut was found in prevTxOutputCache, key={HelperTools.ByteToHexString(prevOutTxId)}_{prevOutN}.");
            }
            return(foundPrevOut);
        }
        private void CachePrevOut(PrevTxOutput prevTxOutput)
        {
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                                    .SetSize(1)
                                    .SetSlidingExpiration(TimeSpan.FromMinutes(30));

            prevTxOutputCache.Cache.Set <PrevTxOutput>($"{HelperTools.ByteToHexString(prevTxOutput.TxExternalId)}_{prevTxOutput.N}", prevTxOutput, cacheEntryOptions);
        }
Example #4
0
        public async Task <string> SendRawTransactionAsync(byte[] transaction, bool allowhighfees, bool dontCheckFees, CancellationToken?token)
        {
            var rpcResponse = await MakeRequestAsync <string>(token, new RpcRequest(1, "sendrawtransaction",
                                                                                    HelperTools.ByteToHexString(transaction),
                                                                                    allowhighfees,
                                                                                    dontCheckFees
                                                                                    ));

            return(rpcResponse.Result);
        }
        public async Task SubmitTransaction()
        {
            var(txHex, txId) = CreateNewTransaction();

            var payload = await SubmitTransactionAsync(txHex);

            Assert.AreEqual(payload.ReturnResult, "success");

            // Try to fetch tx from the node
            var txFromNode = await rpcClient0.GetRawTransactionAsBytesAsync(txId);

            Assert.AreEqual(txHex, HelperTools.ByteToHexString(txFromNode));
        }
        public static CallbackNotificationViewModelBase CreateFromNotificationData(IClock clock, NotificationData notificationData)
        {
            var txId      = new uint256(notificationData.TxExternalId).ToString();
            var blockHash = (notificationData.BlockHash == null || notificationData.BlockHash.Length == 0) ? "" : new uint256(notificationData.BlockHash).ToString();
            CallbackNotificationViewModelBase callbackModel;

            switch (notificationData.NotificationType)
            {
            case Domain.CallbackReason.DoubleSpend:
            case Domain.CallbackReason.DoubleSpendAttempt:
                callbackModel = new CallbackNotificationDoubleSpendViewModel
                {
                    CallbackPayload = new DsNotificationPayloadCallbackViewModel
                    {
                        DoubleSpendTxId = new uint256(notificationData.DoubleSpendTxId).ToString(),
                        Payload         = HelperTools.ByteToHexString(notificationData.Payload)
                    }
                };
                break;

            case Domain.CallbackReason.MerkleProof:
                if (notificationData.MerkleFormat == MerkleFormat.TSC)
                {
                    callbackModel = new CallbackNotificationMerkeProof2ViewModel
                    {
                        CallbackPayload = notificationData.MerkleProof2
                    };
                }
                else
                {
                    callbackModel = new CallbackNotificationMerkeProofViewModel
                    {
                        CallbackPayload = notificationData.MerkleProof
                    };
                }
                break;

            default:
                throw new BadRequestException("Unknown notification type.");
            }
            callbackModel.APIVersion     = Const.MERCHANT_API_VERSION;
            callbackModel.BlockHash      = blockHash;
            callbackModel.BlockHeight    = notificationData.BlockHeight;
            callbackModel.CallbackReason = notificationData.NotificationType;
            callbackModel.CallbackTxId   = txId;
            callbackModel.Timestamp      = clock.UtcNow();

            return(callbackModel);
        }
        public async Task SubmitTransactionValid()
        {
            var(txHex, tx, prevOuts) = await CreateNewConsolidationTx();

            Assert.IsTrue(Mapi.IsConsolidationTxn(tx, consolidationParameters, prevOuts));

            var payload = await SubmitTransaction(txHex);

            Assert.AreEqual("success", payload.ReturnResult);

            // Try to fetch tx from the node
            var txFromNode = await rpcClient0.GetRawTransactionAsBytesAsync(tx.GetHash().ToString());

            Assert.AreEqual(txHex, HelperTools.ByteToHexString(txFromNode));
        }
        public async Task SubmitTransactionAndWaitForProof2()
        {
            var(txHex, txId) = CreateNewTransaction();

            var payload = await SubmitTransactionAsync(txHex, merkleProof : true, merkleFormat : MerkleFormat.TSC);

            Assert.AreEqual(payload.ReturnResult, "success");

            // Try to fetch tx from the node
            var txFromNode = await rpcClient0.GetRawTransactionAsBytesAsync(txId);

            Assert.AreEqual(txHex, HelperTools.ByteToHexString(txFromNode));

            Assert.AreEqual(0, Callback.Calls.Length);

            var notificationEventSubscription = EventBus.Subscribe <NewNotificationEvent>();
            // This is not absolutely necessary, since we ar waiting for NotificationEvent too, but it helps
            // with troubleshooting:
            var generatedBlock = await GenerateBlockAndWaitForItTobeInsertedInDBAsync();

            loggerTest.LogInformation($"Generated block {generatedBlock} should contain our transaction");

            await WaitForEventBusEventAsync(notificationEventSubscription,
                                            $"Waiting for merkle notification event for tx {txId}",
                                            (evt) => evt.NotificationType == CallbackReason.MerkleProof &&
                                            new uint256(evt.TransactionId) == new uint256(txId)
                                            );

            WaitUntilEventBusIsIdle();

            // Check if callback was received
            Assert.AreEqual(1, Callback.Calls.Length);

            // Verify that it parses merkleproof2
            var callback = HelperTools.JSONDeserialize <JSONEnvelopeViewModel>(Callback.Calls[0].request)
                           .ExtractPayload <CallbackNotificationMerkeProof2ViewModel>();

            Assert.AreEqual(CallbackReason.MerkleProof, callback.CallbackReason);

            // Validate callback
            var blockHeader = BlockHeader.Parse(callback.CallbackPayload.Target, Network.RegTest);

            Assert.AreEqual(generatedBlock, blockHeader.GetHash());
            Assert.AreEqual(new uint256(txId), new uint256(callback.CallbackTxId));
            Assert.AreEqual(new uint256(txId), new uint256(callback.CallbackPayload.TxOrId));
        }
        private Task ProcessSubscriptionAsync(ZMQSubscription subscription)
        {
            if (subscription.Socket.TryReceiveFrameString(TimeSpan.FromMilliseconds(100), out string msgTopic))
            {
                var msg = subscription.Socket.ReceiveMultipartBytes();
                logger.LogDebug($"Received message with topic {msgTopic}. Length: {msg.Count}");
                switch (msgTopic)
                {
                case ZMQTopic.HashBlock:
                    string blockHash = HelperTools.ByteToHexString(msg[0]);
                    logger.LogInformation($"New block with hash {blockHash}.");
                    eventBus.Publish(new NewBlockDiscoveredEvent()
                    {
                        CreationDate = clock.UtcNow(), BlockHash = blockHash
                    });
                    break;

                case ZMQTopic.InvalidTx:
                    var invalidTxMsg = JsonSerializer.Deserialize <InvalidTxMessage>(msg[0]);
                    logger.LogInformation($"Invalid tx notification for tx {invalidTxMsg.TxId} with reason {invalidTxMsg.RejectionCode} - {invalidTxMsg.RejectionReason}.");
                    eventBus.Publish(new InvalidTxDetectedEvent()
                    {
                        CreationDate = clock.UtcNow(), Message = invalidTxMsg
                    });
                    break;

                case ZMQTopic.DiscardedFromMempool:
                    var removedFromMempoolMsg = JsonSerializer.Deserialize <RemovedFromMempoolMessage>(msg[0]);
                    logger.LogInformation($"Removed from mempool tx notification for tx {removedFromMempoolMsg.TxId} with reason {removedFromMempoolMsg.Reason}. ColidedWith.TxId = {removedFromMempoolMsg.CollidedWith?.TxId}");
                    eventBus.Publish(new RemovedFromMempoolEvent()
                    {
                        CreationDate = clock.UtcNow(), Message = removedFromMempoolMsg
                    });
                    break;

                default:
                    logger.LogInformation($"Unknown message topic {msgTopic} received. Ignoring.");
                    logger.LogInformation($"Message: {Encoding.UTF8.GetString(msg[0])}");
                    break;
                }
                subscription.LastMessageAt = clock.UtcNow();
            }
            return(Task.CompletedTask);
        }