public async Task <BuildTransactionResponse> BuildSingleTransactionAsync(BuildSingleTransactionRequest request,
                                                                                 decimal feeFactor)
        {
            if (request.OperationId == Guid.Empty)
            {
                throw new BusinessException(ErrorReason.BadRequest, "Operation id is invalid");
            }

            // Check to see if already broadcasted.
            var cachedResult = await _broadcastTxRepo.GetAsync(request.OperationId.ToString());

            if (cachedResult != null)
            {
                throw new BusinessException(ErrorReason.DuplicateRecord, "Operation already broadcast");
            }

            var unsignedTx = await _unsignedTxRepo.GetAsync(request.OperationId.ToString());

            if (unsignedTx?.ResponseJson != null)
            {
                return(JsonConvert.DeserializeObject <BuildTransactionResponse>(unsignedTx.ResponseJson));
            }

            var response = await _builder.BuildSingleTransactionAsync(request, feeFactor);

            var entity = new UnsignedTransactionEntity(
                request.OperationId,
                JsonConvert.SerializeObject(request),
                JsonConvert.SerializeObject(response)
                );

            await _unsignedTxRepo.InsertAsync(entity);

            return(response);
        }
        public async Task UpdateHealthStatus()
        {
            var result = new List <HealthIssue>();

            try
            {
                result.AddRange(await GetDcrdHealthIssues());
                result.AddRange(await GetDcrdataHealthIssues());
            }
            catch (Exception e)
            {
                _log.Error(e);

                result.Add(HealthIssue.Create("UnknownHealthIssue", e.Message));
            }

            await _healthStatusRepo.InsertAsync(new HealthStatusEntity
            {
                HealthIssues = result.Select(p => new HealthStatusEntity.HealthIssue
                {
                    Type  = p.Type,
                    Value = p.Value
                }).ToArray()
            });
        }
        /// <summary>
        /// Adds the given address to the observation repository.
        ///
        /// If the address is already in the repository, a BusinessException is thrown.
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public async Task SubscribeAsync(string address)
        {
            if (!_addressValidator.IsValid(address))
            {
                throw new BusinessException(ErrorReason.InvalidAddress, "Address is invalid");
            }

            await _observableWalletRepository.InsertAsync(new ObservableWalletEntity { Address = address }, false);
        }
        /// <summary>
        /// Broadcasts a signed transaction to the Decred network
        /// </summary>
        /// <param name="operationId"></param>
        /// <param name="hexTransaction"></param>
        /// <returns></returns>
        /// <exception cref="TransactionBroadcastException"></exception>
        public async Task Broadcast(Guid operationId, string hexTransaction)
        {
            if (operationId == Guid.Empty)
            {
                throw new BusinessException(ErrorReason.BadRequest, "Operation id is invalid");
            }
            if (string.IsNullOrWhiteSpace(hexTransaction))
            {
                throw new BusinessException(ErrorReason.BadRequest, "SignedTransaction is invalid");
            }

            var txBytes = HexUtil.ToByteArray(hexTransaction);
            var msgTx   = new MsgTx();

            msgTx.Decode(txBytes);

            // If the operation exists in the cache, throw exception
            var cachedResult = await _broadcastTxRepo.GetAsync(operationId.ToString());

            if (cachedResult != null)
            {
                throw new BusinessException(ErrorReason.DuplicateRecord, "Operation already broadcast");
            }

            // Submit the transaction to the network via dcrd
            var result = await _dcrdClient.SendRawTransactionAsync(hexTransaction);

            if (result.Error != null)
            {
                throw new TransactionBroadcastException($"[{result.Error.Code}] {result.Error.Message}");
            }

            // Flag the consumed outpoints as spent.
            var outpoints = GetOutpointKeysForRawTransaction(txBytes);

            foreach (var outpoint in outpoints)
            {
                _broadcastedOutpointRepo.InsertAsync(new BroadcastedOutpoint {
                    Value = outpoint
                });
            }

            var txHash = HexUtil.FromByteArray(msgTx.GetHash().Reverse().ToArray());

            await SaveBroadcastedTransaction(new BroadcastedTransaction
            {
                OperationId        = operationId,
                Hash               = txHash,
                EncodedTransaction = hexTransaction
            });
        }
示例#5
0
        private async Task SaveBroadcastedTransaction(BroadcastedTransaction broadcastedTx)
        {
            // Store tx Hash to OperationId lookup
            await _broadcastTxHashRepo.InsertAsync(
                new BroadcastedTransactionByHash
            {
                Hash        = broadcastedTx.Hash,
                OperationId = broadcastedTx.OperationId
            }
                );

            // Store operation
            await _broadcastTxRepo.InsertAsync(broadcastedTx);
        }
示例#6
0
 /// <summary>
 /// Observe receiving transactions for this address.
 /// Only need this to return expected errors.
 /// </summary>
 /// <param name="address"></param>
 /// <returns></returns>
 public async Task SubscribeAddressFrom(string address)
 {
     _addressValidator.AssertValid(address);
     var entity = new ObservableAddressEntity(address, TxDirection.Outgoing);
     await _operationRepo.InsertAsync(entity);
 }