From 86e96e5cb70532a28c1a4777bc2e881b7c11c0f5 Mon Sep 17 00:00:00 2001 From: Afshin Arani Date: Tue, 12 Sep 2023 17:27:12 +0300 Subject: [PATCH] Backend(UtxoCoin): make sure fee is less than out This prevents any future bug to cause unreasonable fees. --- src/GWallet.Backend/Exceptions.fs | 1 + .../UtxoCoin/UtxoCoinAccount.fs | 37 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/GWallet.Backend/Exceptions.fs b/src/GWallet.Backend/Exceptions.fs index f2f9a1bce..aa5b2fde7 100644 --- a/src/GWallet.Backend/Exceptions.fs +++ b/src/GWallet.Backend/Exceptions.fs @@ -28,3 +28,4 @@ exception InvalidJson exception TransactionAlreadySigned exception TransactionNotSignedYet +exception MinerFeeHigherThanOutputs diff --git a/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs b/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs index 373876325..37f32ca3a 100644 --- a/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs +++ b/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs @@ -397,9 +397,42 @@ module Account = let internal CheckValidPassword (account: NormalAccount) (password: string) = GetPrivateKey account password |> ignore + let private ValidateMinerFee currency (rawTransaction: string) = + async { + let network = GetNetwork currency + + let txToValidate = Transaction.Parse (rawTransaction, network) + + let totalOutputsAmount = txToValidate.TotalOut + + let getInputAmount (input: TxIn) = + async { + let job = ElectrumClient.GetBlockchainTransaction (input.PrevOut.Hash.ToString()) + let! inputOriginTxString = Server.Query currency (QuerySettings.Default ServerSelectionMode.Fast) job None + let inputOriginTx = Transaction.Parse (inputOriginTxString, network) + return inputOriginTx.Outputs.[input.PrevOut.N].Value + } + + let! amounts = + txToValidate.Inputs + |> Seq.map getInputAmount + |> Async.Parallel + + let totalInputsAmount = Seq.sum amounts + + let minerFee = totalInputsAmount - totalOutputsAmount + if minerFee > totalOutputsAmount then + return raise MinerFeeHigherThanOutputs + + return () + } + let private BroadcastRawTransaction currency (rawTx: string): Async = - let job = ElectrumClient.BroadcastTransaction rawTx - Server.Query currency QuerySettings.Broadcast job None + async { + do! ValidateMinerFee currency rawTx + let job = ElectrumClient.BroadcastTransaction rawTx + return! Server.Query currency QuerySettings.Broadcast job None + } let internal BroadcastTransaction currency (transaction: SignedTransaction<_>) = // FIXME: stop embedding TransactionInfo element in SignedTransaction