public async Task update_gas_price_should_succeed_if_sending_new_transaction_succeeds()
        {
            var transactionHash     = TestItem.KeccakA;
            var transaction         = Build.A.Transaction.TestObject;
            var sentTransactionHash = TestItem.KeccakB;
            var gasPrice            = 30.GWei();

            _blockchainBridge.GetTransactionAsync(transactionHash)
            .Returns(new NdmTransaction(transaction, true, 1, TestItem.KeccakB, 1));
            _blockchainBridge.SendOwnTransactionAsync(transaction).Returns(sentTransactionHash);
            var hash = await _transactionService.UpdateGasPriceAsync(transactionHash, gasPrice);

            hash.Should().Be(sentTransactionHash);
            transaction.GasPrice.Should().Be(gasPrice);
            await _blockchainBridge.Received().GetTransactionAsync(transactionHash);

            await _blockchainBridge.Received().GetNetworkIdAsync();

            await _blockchainBridge.Received().SendOwnTransactionAsync(transaction);
        }
示例#2
0
        public async Task send_own_transaction_should_invoke_blockchain_bridge_send_transaction_and_return_hash()
        {
            var transaction = Build.A.Transaction.TestObject;
            var hash        = TestItem.KeccakA;

            _txPoolBridge.SendTransaction(transaction, TxHandlingOptions.PersistentBroadcast | TxHandlingOptions.ManagedNonce).Returns(hash);
            var result = await _ndmBridge.SendOwnTransactionAsync(transaction);

            _txPoolBridge.Received().SendTransaction(transaction, TxHandlingOptions.PersistentBroadcast | TxHandlingOptions.ManagedNonce);
            result.Should().Be(hash);
        }
        public async Task send_own_transaction_should_invoke_blockchain_bridge_send_transaction_and_return_hash()
        {
            var transaction = Build.A.Transaction.TestObject;
            var hash        = TestItem.KeccakA;

            _blockchainBridge.SendTransaction(transaction, true).Returns(hash);
            var result = await _ndmBridge.SendOwnTransactionAsync(transaction);

            _blockchainBridge.Received().SendTransaction(transaction, true);
            result.Should().Be(hash);
        }
示例#4
0
        public async Task <Keccak> ClaimRefundAsync(Address onBehalfOf, RefundClaim refundClaim, UInt256 gasPrice)
        {
            byte[]      txData      = _abiEncoder.Encode(AbiEncodingStyle.IncludeSignature, ContractData.ClaimRefundSig, refundClaim.AssetId.Bytes, refundClaim.Units, refundClaim.Value, refundClaim.ExpiryTime, refundClaim.Pepper, refundClaim.Provider, onBehalfOf);
            Transaction transaction = new Transaction();

            transaction.Value         = 0;
            transaction.Data          = txData;
            transaction.To            = _contractAddress;
            transaction.SenderAddress = onBehalfOf;
            transaction.GasLimit      = (long)GasLimit;
            transaction.GasPrice      = gasPrice;
            transaction.Nonce         = await _blockchainBridge.ReserveOwnTransactionNonceAsync(onBehalfOf);

            _wallet.Sign(transaction, await _blockchainBridge.GetNetworkIdAsync());

            if (_logger.IsInfo)
            {
                _logger.Info($"Sending a refund claim transaction for {refundClaim.DepositId} to be refunded to {refundClaim.RefundTo}");
            }

            return(await _blockchainBridge.SendOwnTransactionAsync(transaction));
        }
        public async Task send_own_transaction_should_invoke_proxy_eth_sendRawTransaction_and_return_hash()
        {
            var transaction = Build.A.Transaction.TestObject;
            var data        = Rlp.Encode(transaction).Bytes;
            var hash        = TestItem.KeccakA;

            _proxy.eth_sendRawTransaction(Arg.Is <byte[]>(x => x.SequenceEqual(data)))
            .Returns(RpcResult <Keccak> .Ok(hash));
            var result = await _ndmBridge.SendOwnTransactionAsync(transaction);

            await _proxy.Received().eth_sendRawTransaction(Arg.Is <byte[]>(x => x.SequenceEqual(data)));

            result.Should().BeSameAs(hash);
        }
示例#6
0
        public async Task <Keccak?> MakeDepositAsync(Address onBehalfOf, Deposit deposit, UInt256 gasPrice)
        {
            var txData = _abiEncoder.Encode(AbiEncodingStyle.IncludeSignature, ContractData.DepositAbiSig,
                                            deposit.Id.Bytes, deposit.Units, deposit.ExpiryTime);
            Transaction transaction = new Transaction
            {
                Value         = deposit.Value,
                Data          = txData,
                To            = _contractAddress,
                SenderAddress = onBehalfOf,
                GasLimit      = (long)GasLimit,
                GasPrice      = gasPrice
            };

            // check
            _wallet.Sign(transaction, await _blockchainBridge.GetNetworkIdAsync());

            return(await _blockchainBridge.SendOwnTransactionAsync(transaction));
        }
示例#7
0
 public void Setup()
 {
     _blockchainBridge = Substitute.For <INdmBlockchainBridge>();
     _repository       = Substitute.For <IEthRequestRepository>();
     _repository.SumDailyRequestsTotalValueAsync(Arg.Any <DateTime>()).ReturnsForAnyArgs(UInt256.Zero);
     _faucetAddress = Address.FromNumber(1);
     _maxValue      = 1.Ether();
     _dailyRequestsTotalValueEth = 500;
     _enabled         = true;
     _timestamper     = new Timestamper();
     _wallet          = Substitute.For <IWallet>();
     _logManager      = LimboLogs.Instance;
     _host            = "127.0.0.1";
     _address         = Address.FromNumber(2);
     _value           = 1.Ether();
     _faucetAccount   = Account.TotallyEmpty;
     _transactionHash = Keccak.Zero;
     _blockchainBridge.GetNonceAsync(_faucetAddress).Returns(UInt256.Zero);
     _blockchainBridge.SendOwnTransactionAsync(Arg.Any <Transaction>()).Returns(_transactionHash);
 }
示例#8
0
        public async Task <Keccak?> ClaimPaymentAsync(PaymentClaim paymentClaim, Address coldWalletAddress,
                                                      UInt256 gasPrice)
        {
            byte[] txData = _abiEncoder.Encode(AbiEncodingStyle.IncludeSignature,
                                               ContractData.ClaimPaymentAbiSig,
                                               paymentClaim.AssetId.Bytes,
                                               paymentClaim.Units,
                                               paymentClaim.Value,
                                               paymentClaim.ExpiryTime,
                                               paymentClaim.Pepper,
                                               coldWalletAddress,
                                               paymentClaim.Consumer,
                                               new[] { paymentClaim.UnitsRange.From, paymentClaim.UnitsRange.To },
                                               paymentClaim.Signature.V,
                                               paymentClaim.Signature.R,
                                               paymentClaim.Signature.S);

            if (_logger.IsInfo)
            {
                _logger.Info($"Sending a payment claim transaction - Range: [{paymentClaim.UnitsRange.From},{paymentClaim.UnitsRange.To}] Units: {paymentClaim.Units} to be paid out to {coldWalletAddress}");
            }

            Transaction transaction = new Transaction
            {
                Value         = 0,
                Data          = txData,
                To            = _contractAddress,
                SenderAddress = paymentClaim.Provider,
                GasLimit      = (long)GasLimit, // when account does not exist then we pay for account creation of cold wallet
                GasPrice      = gasPrice,
                Nonce         = await _bridge.GetNonceAsync(paymentClaim.Provider)
            };

            // check
            _wallet.Sign(transaction, await _bridge.GetNetworkIdAsync());

            return(await _bridge.SendOwnTransactionAsync(transaction));
        }
        private async Task <Keccak> UpdateAsync(Keccak transactionHash, Action <Transaction> update)
        {
            if (transactionHash is null)
            {
                throw new ArgumentException("Transaction hash cannot be null.", nameof(transactionHash));
            }

            var transactionDetails = await _blockchainBridge.GetTransactionAsync(transactionHash);

            if (transactionDetails is null)
            {
                throw new ArgumentException($"Transaction was not found for hash: '{transactionHash}'.", nameof(transactionHash));
            }

            if (!transactionDetails.IsPending)
            {
                throw new InvalidOperationException($"Transaction with hash: '{transactionHash}' is not pending.");
            }

            var transaction = transactionDetails.Transaction;

            update(transaction);
            _wallet.Sign(transaction, await _blockchainBridge.GetNetworkIdAsync());
            var hash = await _blockchainBridge.SendOwnTransactionAsync(transaction);

            if (hash is null)
            {
                throw new InvalidOperationException("Transaction was not sent (received an empty hash).");
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Received a new transaction hash: '{hash}' (previous transaction hash: '{transactionHash}').");
            }

            return(hash);
        }
示例#10
0
        public async Task <FaucetResponse> TryRequestEthAsync(string node, Address?address, UInt256 value)
        {
            if (!_enabled)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info("NDM Faucet is disabled.");
                }
                return(FaucetResponse.FaucetDisabled);
            }

            if (!_initialized)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info("NDM Faucet is not initialized.");
                }
                return(FaucetResponse.FaucetDisabled);
            }

            if (_today.Date != _timestamper.UtcNow.Date)
            {
                lock (_locker)
                {
                    _today = _timestamper.UtcNow;
                    _todayRequestsTotalValueWei = 0;
                }

                if (_logger.IsInfo)
                {
                    _logger.Info($"NDM Faucet has updated its today's date ({_today.Date:d}) and reset the total requests value.");
                }
            }

            if (_faucetAddress is null || _faucetAddress == Address.Zero)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn("NDM Faucet address is not set.");
                }
                return(FaucetResponse.FaucetAddressNotSet);
            }

            if (string.IsNullOrWhiteSpace(node) || address is null || address == Address.Zero)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info("Invalid NDM Faucet request.");
                }
                return(FaucetResponse.InvalidNodeAddress);
            }

            if (_faucetAddress == address)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info("NDM Faucet request cannot be processed for the same address as NDM Faucet.");
                }
                return(FaucetResponse.SameAddressAsFaucet);
            }

            if (value == 0)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info("NDM Faucet request cannot be processed for the zero value.");
                }
                return(FaucetResponse.ZeroValue);
            }

            if (value > _maxValue)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"NDM Faucet request from: {node} has too big value: {value} wei > {_maxValue} wei.");
                }
                return(FaucetResponse.TooBigValue);
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Received NDM Faucet request from: {node}, address: {address}, value: {value} wei.");
            }
            if (_pendingRequests.TryGetValue(node, out _))
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"NDM Faucet request from: {node} is already being processed.");
                }
                return(FaucetResponse.RequestAlreadyProcessing);
            }

            var latestRequest = await _requestRepository.GetLatestAsync(node);

            var requestedAt = _timestamper.UtcNow;

            if (!(latestRequest is null) && latestRequest.RequestedAt.Date >= requestedAt.Date)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"NDM Faucet request from: {node} was already processed today at: {latestRequest.RequestedAt}.");
                }
                return(FaucetResponse.RequestAlreadyProcessedToday(FaucetRequestDetails.From(latestRequest)));
            }

            if (!_pendingRequests.TryAdd(node, true))
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Couldn't start processing NDM Faucet request from: {node}.");
                }
                return(FaucetResponse.RequestError);
            }

            lock (_locker)
            {
                _todayRequestsTotalValueWei += value;
                if (_logger.IsInfo)
                {
                    _logger.Info($"Increased NDM Faucet total value of today's ({_today.Date:d}) requests to {_todayRequestsTotalValueWei} wei.");
                }
            }

            if (_todayRequestsTotalValueWei > _dailyRequestsTotalValueWei)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Daily ({_today.Date:d}) requests value for NDM Faucet was reached ({_dailyRequestsTotalValueWei} wei).");
                }
                return(FaucetResponse.DailyRequestsTotalValueReached);
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"NDM Faucet is processing request for: {node}, address: {address}, value: {value} wei.");
            }
            try
            {
                var nonce = await _blockchainBridge.GetNonceAsync(_faucetAddress);

                var transaction = new Transaction
                {
                    Value         = value,
                    GasLimit      = Transaction.BaseTxGasCost,
                    GasPrice      = 20.GWei(),
                    To            = address,
                    SenderAddress = _faucetAddress,
                    Nonce         = nonce
                };
                _wallet.Sign(transaction, await _blockchainBridge.GetNetworkIdAsync());
                Keccak?transactionHash = await _blockchainBridge.SendOwnTransactionAsync(transaction);

                if (transactionHash == null)
                {
                    return(FaucetResponse.ProcessingRequestError);
                }

                if (latestRequest is null)
                {
                    Keccak requestId = Keccak.Compute(Rlp.Encode(Rlp.Encode(node)).Bytes);
                    latestRequest = new EthRequest(requestId, node, address, value, requestedAt, transactionHash);
                    await _requestRepository.AddAsync(latestRequest);
                }
                else
                {
                    latestRequest.UpdateRequestDetails(address, value, requestedAt, transactionHash);
                    await _requestRepository.UpdateAsync(latestRequest);
                }

                if (_logger.IsInfo)
                {
                    _logger.Info($"NDM Faucet has successfully processed request for: {node}, address: {address}, value: {value} wei.");
                }
                return(FaucetResponse.RequestCompleted(FaucetRequestDetails.From(latestRequest)));
            }
            catch (Exception ex)
            {
                if (_logger.IsError)
                {
                    _logger.Error(ex.Message, ex);
                }
                lock (_locker)
                {
                    _todayRequestsTotalValueWei -= value;
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Decreased NDM Faucet total value of today's ({_today.Date:d}) requests to {_todayRequestsTotalValueWei} wei.");
                    }
                }

                return(FaucetResponse.ProcessingRequestError);
            }
            finally
            {
                _pendingRequests.TryRemove(node, out _);
            }
        }