From 739e3641cf4b0947d42c6aee67ff56e652c349fd Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Mon, 18 Jan 2021 00:10:03 +0800 Subject: [PATCH] Update fantomas to v4.4.0-alpha-008 Things I don't like: 1) are we sure it cannot be in a single line?: member __.GetLastCachedData (): CachedNetworkData = lock cacheFiles.CachedNetworkData - (fun _ -> sessionCachedNetworkData) + (fun _ -> sessionCachedNetworkData + ) 2) are we sure it cannot be in a single line?: raise (TlsNotSupportedYetInGWalletException ("TLS not yet supported")) raise ( TlsNotSupportedYetInGWalletException ("TLS not yet supported") ) Things I should report (if not reported yet): 1) Processing src/GWallet.Backend/Ether/EtherServer.fs The following exception occurs while formatting stdin: Fantomas.FormatConfig+FormatException: Formatted content is not valid F# code at Fantomas.Extras.FakeHelpers.formatContentInternalAsync@95-5.Invoke(Boolean _arg2) in C:\Users\nojaf\Projects\fantomas\src\Fantomas.Extras\FakeHelpers.fs:line 96 at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvokeNoHijackCheck[a,b](AsyncActivation`1 ctxt, FSharpFunc`2 userCode, b result1) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 404 at Fantomas.CodeFormatterImpl.isValidFSharpCode@378-7.Invoke(AsyncActivation`1 ctxt) in C:\Users\nojaf\Projects\fantomas\src\Fantomas\CodeFormatterImpl.fs:line 378 at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 104 --- End of stack trace from previous location --- at Microsoft.FSharp.Control.AsyncResult`1.Commit() in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 337 at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronouslyInCurrentThread[a](CancellationToken cancellationToken, FSharpAsync`1 computation) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 870 at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 878 at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1142 at Program.processSourceString(Boolean isFsiFile, String s, FSharpChoice`2 tw, FormatConfig config) in C:\Users\nojaf\Projects\fantomas\src\Fantomas.CoreGlobalTool\Program.fs:line 113 at Program.stringToFile@310(Boolean force, Boolean profile, String s, String outFile, FormatConfig config) in C:\Users\nojaf\Projects\fantomas\src\Fantomas.CoreGlobalTool\Program.fs:line 322 2) Processing src/GWallet.Backend/FaultTolerantParallelClient.fs The following exception occurs while formatting stdin: Fantomas.FormatConfig+FormatException: Formatted content is not valid F# code at Fantomas.Extras.FakeHelpers.formatContentInternalAsync@95-5.Invoke(Boolean _arg2) in C:\Users\nojaf\Projects\fantomas\src\Fantomas.Extras\FakeHelpers.fs:line 96 at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvokeNoHijackCheck[a,b](AsyncActivation`1 ctxt, FSharpFunc`2 userCode, b result1) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 404 at Fantomas.CodeFormatterImpl.isValidFSharpCode@378-7.Invoke(AsyncActivation`1 ctxt) in C:\Users\nojaf\Projects\fantomas\src\Fantomas\CodeFormatterImpl.fs:line 378 at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 104 --- End of stack trace from previous location --- at Microsoft.FSharp.Control.AsyncResult`1.Commit() in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 337 at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronouslyInCurrentThread[a](CancellationToken cancellationToken, FSharpAsync`1 computation) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 870 at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 878 at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1142 at Program.processSourceString(Boolean isFsiFile, String s, FSharpChoice`2 tw, FormatConfig config) in C:\Users\nojaf\Projects\fantomas\src\Fantomas.CoreGlobalTool\Program.fs:line 113 at Program.stringToFile@310(Boolean force, Boolean profile, String s, String outFile, FormatConfig config) in C:\Users\nojaf\Projects\fantomas\src\Fantomas.CoreGlobalTool\Program.fs:line 322 NOTE: one of these two above may be https://github.com/fsprojects/fantomas/issues/1241 3) D:\a\geewallet\geewallet\src\GWallet.Backend\UtxoCoin\UtxoCoinAccount.fs(639,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (638:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\UtxoCoin\UtxoCoinAccount.fs(639,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (638:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\UtxoCoin\UtxoCoinAccount.fs(640,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (638:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\UtxoCoin\UtxoCoinAccount.fs(640,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (638:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\Ether\EtherAccount.fs(582,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (581:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\Ether\EtherAccount.fs(582,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (581:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\Ether\EtherAccount.fs(583,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (581:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\Ether\EtherAccount.fs(583,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (581:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe build failed D:\a\geewallet\geewallet\src\GWallet.Backend\Account.fs(489,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (488:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\Account.fs(489,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (488:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\Account.fs(490,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (488:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] D:\a\geewallet\geewallet\src\GWallet.Backend\Account.fs(490,13): error FS0058: Possible incorrect indentation: this token is offside of context started at position (488:13). Try indenting this token further or using standard formatting conventions. [D:\a\geewallet\geewallet\src\GWallet.Backend\GWallet.Backend.fsproj] --- src/GWallet.Backend/Account.fs | 326 ++++++++------- src/GWallet.Backend/AccountTypes.fs | 42 +- src/GWallet.Backend/Caching.fs | 350 +++++++++------- src/GWallet.Backend/Config.fs | 47 ++- src/GWallet.Backend/Currency.fs | 5 +- src/GWallet.Backend/Ether/EtherAccount.fs | 310 ++++++++------- src/GWallet.Backend/Ether/EtherExceptions.fs | 66 +-- src/GWallet.Backend/Ether/EtherMinerFee.fs | 11 +- src/GWallet.Backend/Ether/TokenManager.fs | 29 +- src/GWallet.Backend/FSharpUtil.fs | 97 +++-- src/GWallet.Backend/FiatValueEstimation.fs | 9 +- src/GWallet.Backend/Formatting.fs | 9 +- src/GWallet.Backend/Infrastructure.fs | 30 +- src/GWallet.Backend/JsonRpcTcpClient.fs | 55 ++- src/GWallet.Backend/Marshalling.fs | 130 +++--- src/GWallet.Backend/Networking.fs | 120 +++--- src/GWallet.Backend/Server.fs | 39 +- src/GWallet.Backend/ServerManager.fs | 64 +-- src/GWallet.Backend/Shuffler.fs | 25 +- src/GWallet.Backend/TransferAmount.fs | 9 +- .../UtxoCoin/ElectrumClient.fs | 59 +-- .../UtxoCoin/ElectrumServer.fs | 29 +- src/GWallet.Backend/UtxoCoin/StratumClient.fs | 164 +++++--- .../UtxoCoin/UtxoCoinAccount.fs | 375 ++++++++++-------- .../UtxoCoin/UtxoCoinMinerFee.fs | 9 +- .../UtxoCoin/UtxoCoinServer.fs | 78 ++-- src/GWallet.Backend/WarpKey.fs | 28 +- 27 files changed, 1450 insertions(+), 1065 deletions(-) diff --git a/src/GWallet.Backend/Account.fs b/src/GWallet.Backend/Account.fs index 689d29a7d..7aaf4443d 100644 --- a/src/GWallet.Backend/Account.fs +++ b/src/GWallet.Backend/Account.fs @@ -9,10 +9,11 @@ open GWallet.Backend.FSharpUtil.UwpHacks module Account = - let private GetShowableBalanceInternal (account: IAccount) - (mode: ServerSelectionMode) - (cancelSourceOption: Option) - : Async> = + let private GetShowableBalanceInternal + (account: IAccount) + (mode: ServerSelectionMode) + (cancelSourceOption: Option) + : Async> = match account with | :? UtxoCoin.IUtxoAccount as utxoAccount -> if not (account.Currency.IsUtxo ()) then @@ -34,10 +35,11 @@ module Account = Ether.Account.GetShowableBalance account mode cancelSourceOption - let GetShowableBalance (account: IAccount) - (mode: ServerSelectionMode) - (cancelSourceOption: Option) - : Async> = + let GetShowableBalance + (account: IAccount) + (mode: ServerSelectionMode) + (cancelSourceOption: Option) + : Async> = async { if Config.NoNetworkBalanceForDebuggingPurposes then return Fresh 1m @@ -49,10 +51,11 @@ module Account = match maybeBalance with | None -> return - NotFresh - (Caching.Instance.RetrieveLastCompoundBalance + NotFresh ( + Caching.Instance.RetrieveLastCompoundBalance account.PublicAddress - account.Currency) + account.Currency + ) | Some balance -> let compoundBalance, _ = Caching.Instance.RetrieveAndUpdateLastCompoundBalance @@ -63,10 +66,11 @@ module Account = return Fresh compoundBalance } - let internal GetAccountFromFile accountFile - (currency: Currency) - kind - : IAccount = + let internal GetAccountFromFile + accountFile + (currency: Currency) + kind + : IAccount = if currency.IsUtxo () then UtxoCoin.Account.GetAccountFromFile accountFile currency kind elif currency.IsEtherBased () then @@ -129,8 +133,9 @@ module Account = EtherPublicAddress = etherPublicAddress } - let GetArchivedAccountsWithPositiveBalance (cancelSourceOption: Option) - : Async> = + let GetArchivedAccountsWithPositiveBalance + (cancelSourceOption: Option) + : Async> = let asyncJobs = seq>> { let allCurrencies = Currency.GetAll () @@ -145,8 +150,9 @@ module Account = else failwith <| SPrintF1 "Unknown currency %A" currency - let fromConfigAccountFileToPublicAddressFunc (accountConfigFile: FileRepresentation) - = + let fromConfigAccountFileToPublicAddressFunc + (accountConfigFile: FileRepresentation) + = let privateKeyFromConfigFile = accountConfigFile.Content () @@ -157,10 +163,11 @@ module Account = [ currency ] AccountKind.Archived do let account = - ArchivedAccount - (currency, - accountFile, - fromConfigAccountFileToPublicAddressFunc) + ArchivedAccount ( + currency, + accountFile, + fromConfigAccountFileToPublicAddressFunc + ) let maybeBalanceJob = GetShowableBalanceInternal @@ -211,10 +218,11 @@ module Account = } - let EstimateFee (account: IAccount) - (amount: TransferAmount) - destination - : Async = + let EstimateFee + (account: IAccount) + (amount: TransferAmount) + destination + : Async = async { match account with | :? UtxoCoin.IUtxoAccount as utxoAccount -> @@ -239,10 +247,11 @@ module Account = return fee :> IBlockchainFeeInfo } - let private SaveOutgoingTransactionInCache transactionProposal - (fee: IBlockchainFeeInfo) - txId - = + let private SaveOutgoingTransactionInCache + transactionProposal + (fee: IBlockchainFeeInfo) + txId + = let amountTransferredPlusFeeIfCurrencyFeeMatches = if transactionProposal.Amount.BalanceAtTheMomentOfSending = transactionProposal.Amount.ValueToSend || transactionProposal.Amount.Currency <> fee.Currency then @@ -260,9 +269,10 @@ module Account = // FIXME: if out of gas, miner fee is still spent, we should inspect GasUsed and use it for the call to // SaveOutgoingTransactionInCache - let private CheckIfOutOfGas (transactionMetadata: IBlockchainFeeInfo) - (txHash: string) - : Async = + let private CheckIfOutOfGas + (transactionMetadata: IBlockchainFeeInfo) + (txHash: string) + : Async = async { match transactionMetadata with | :? Ether.TransactionMetadata as etherTxMetadata -> @@ -280,11 +290,12 @@ module Account = with ex -> return raise - <| Exception - (SPrintF1 + <| Exception ( + SPrintF1 "An issue occurred while trying to check if the following transaction ran out of gas: %s" txHash, - ex) + ex + ) | _ -> () } @@ -315,12 +326,13 @@ module Account = return uri } - let SignTransaction (account: NormalAccount) - (destination: string) - (amount: TransferAmount) - (transactionMetadata: IBlockchainFeeInfo) - (password: string) - = + let SignTransaction + (account: NormalAccount) + (destination: string) + (amount: TransferAmount) + (transactionMetadata: IBlockchainFeeInfo) + (password: string) + = match transactionMetadata with | :? Ether.TransactionMetadata as etherTxMetadata -> @@ -372,9 +384,10 @@ module Account = Async.Parallel checkJobs - let private CreateArchivedAccount (currency: Currency) - (unencryptedPrivateKey: string) - : ArchivedAccount = + let private CreateArchivedAccount + (currency: Currency) + (unencryptedPrivateKey: string) + : ArchivedAccount = let fromUnencryptedPrivateKeyToPublicAddressFunc = if currency.IsUtxo () then UtxoCoin.Account.GetPublicAddressFromUnencryptedPrivateKey @@ -384,8 +397,9 @@ module Account = else failwith <| SPrintF1 "Unknown currency %A" currency - let fromConfigFileToPublicAddressFunc (accountConfigFile: FileRepresentation) - = + let fromConfigFileToPublicAddressFunc + (accountConfigFile: FileRepresentation) + = // there's no ETH unencrypted standard: https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition // ... so we simply write the private key in string format let privateKeyFromConfigFile = accountConfigFile.Content () @@ -411,8 +425,11 @@ module Account = let newAccountFile = Config.AddAccount conceptAccount AccountKind.Archived - ArchivedAccount - (currency, newAccountFile, fromConfigFileToPublicAddressFunc) + ArchivedAccount ( + currency, + newAccountFile, + fromConfigFileToPublicAddressFunc + ) let Archive (account: NormalAccount) (password: string): unit = let currency = (account :> IAccount).Currency @@ -433,11 +450,12 @@ module Account = CreateArchivedAccount currency privateKeyAsString |> ignore Config.RemoveNormalAccount account - let SweepArchivedFunds (account: ArchivedAccount) - (balance: decimal) - (destination: IAccount) - (txMetadata: IBlockchainFeeInfo) - = + let SweepArchivedFunds + (account: ArchivedAccount) + (balance: decimal) + (destination: IAccount) + (txMetadata: IBlockchainFeeInfo) + = match txMetadata with | :? Ether.TransactionMetadata as etherTxMetadata -> Ether.Account.SweepArchivedFunds @@ -458,16 +476,19 @@ module Account = "If tx metadata is UTXO type, archived account should be too" | _ -> failwith "tx metadata type unknown" - let SendPayment (account: NormalAccount) - (txMetadata: IBlockchainFeeInfo) - (destination: string) - (amount: TransferAmount) - (password: string) - : Async = + let SendPayment + (account: NormalAccount) + (txMetadata: IBlockchainFeeInfo) + (destination: string) + (amount: TransferAmount) + (password: string) + : Async = let baseAccount = account :> IAccount - if (baseAccount.PublicAddress.Equals - (destination, StringComparison.InvariantCultureIgnoreCase)) then + if (baseAccount.PublicAddress.Equals ( + destination, + StringComparison.InvariantCultureIgnoreCase + )) then raise DestinationEqualToOrigin let currency = baseAccount.Currency @@ -525,10 +546,11 @@ module Account = return uri } - let SignUnsignedTransaction (account) - (unsignedTrans: UnsignedTransaction) - password - = + let SignUnsignedTransaction + (account) + (unsignedTrans: UnsignedTransaction) + password + = let rawTransaction = SignTransaction account @@ -592,7 +614,8 @@ module Account = for etherCurrency in Currency .GetAll() .Where(fun currency -> currency.IsEtherBased ()) do - do! ValidateAddress + do! + ValidateAddress etherCurrency watchWalletInfo.EtherPublicAddress @@ -645,9 +668,10 @@ module Account = let Remove (account: ReadOnlyAccount) = Config.RemoveReadOnlyAccount account - let private CreateConceptEtherAccountInternal (password: string) - (seed: array) - : Async string)> = + let private CreateConceptEtherAccountInternal + (password: string) + (seed: array) + : Async string)> = async { let! virtualFile = Ether.Account.Create password seed @@ -655,10 +679,11 @@ module Account = virtualFile, Ether.Account.GetPublicAddressFromNormalAccountFile } - let private CreateConceptAccountInternal (currency: Currency) - (password: string) - (seed: array) - : Async string)> = + let private CreateConceptAccountInternal + (currency: Currency) + (password: string) + (seed: array) + : Async string)> = async { if currency.IsUtxo () then let! virtualFile = @@ -675,10 +700,11 @@ module Account = } - let CreateConceptAccount (currency: Currency) - (password: string) - (seed: array) - : Async = + let CreateConceptAccount + (currency: Currency) + (password: string) + (seed: array) + : Async = async { let! virtualFile, fromEncPrivKeyToPublicAddressFunc = CreateConceptAccountInternal currency password seed @@ -692,18 +718,20 @@ module Account = } } - let private CreateConceptAccountAux (currency: Currency) - (password: string) - (seed: array) - : Async> = + let private CreateConceptAccountAux + (currency: Currency) + (password: string) + (seed: array) + : Async> = async { let! singleAccount = CreateConceptAccount currency password seed return singleAccount :: List.Empty } - let CreateEtherNormalAccounts (password: string) - (seed: array) - : Async> = + let CreateEtherNormalAccounts + (password: string) + (seed: array) + : Async> = let supportedEtherCurrencies = Currency .GetAll() @@ -733,15 +761,17 @@ module Account = let CreateNormalAccount (conceptAccount: ConceptAccount): NormalAccount = let newAccountFile = Config.AddAccount conceptAccount AccountKind.Normal - NormalAccount - (conceptAccount.Currency, - newAccountFile, - conceptAccount.ExtractPublicAddressFromConfigFileFunc) - - let GenerateMasterPrivateKey (passphrase: string) - (dobPartOfSalt: DateTime) - (emailPartOfSalt: string) - : Async> = + NormalAccount ( + conceptAccount.Currency, + newAccountFile, + conceptAccount.ExtractPublicAddressFromConfigFileFunc + ) + + let GenerateMasterPrivateKey + (passphrase: string) + (dobPartOfSalt: DateTime) + (emailPartOfSalt: string) + : Async> = async { let salt = SPrintF2 @@ -753,9 +783,10 @@ module Account = return privateKeyBytes } - let CreateAllConceptAccounts (privateKeyBytes: array) - (encryptionPassword: string) - : Async> = + let CreateAllConceptAccounts + (privateKeyBytes: array) + (encryptionPassword: string) + : Async> = async { let etherAccounts = CreateEtherNormalAccounts encryptionPassword privateKeyBytes @@ -793,9 +824,10 @@ module Account = return allConceptAccounts } - let CreateAllAccounts (masterPrivateKeyTask: Task>) - (encryptionPassword: string) - : Async = + let CreateAllAccounts + (masterPrivateKeyTask: Task>) + (encryptionPassword: string) + : Async = async { let! privateKeyBytes = Async.AwaitTask masterPrivateKeyTask @@ -806,10 +838,11 @@ module Account = CreateNormalAccount conceptAccount |> ignore } - let CheckValidSeed (passphrase: string) - (dobPartOfSalt: DateTime) - (emailPartOfSalt: string) - = + let CheckValidSeed + (passphrase: string) + (dobPartOfSalt: DateTime) + (emailPartOfSalt: string) + = async { let! masterPrivateKey = GenerateMasterPrivateKey @@ -823,19 +856,19 @@ module Account = (Guid.NewGuid().ToString()) return - allConceptAccounts.All - (fun conceptAccount -> - GetAllActiveAccounts() - .Any(fun account -> - let publicAddressOfConceptAccount = - conceptAccount.ExtractPublicAddressFromConfigFileFunc - conceptAccount.FileRepresentation - - let publicAddressMatches = - (account.PublicAddress = - publicAddressOfConceptAccount) - - publicAddressMatches)) + allConceptAccounts.All (fun conceptAccount -> + GetAllActiveAccounts() + .Any(fun account -> + let publicAddressOfConceptAccount = + conceptAccount.ExtractPublicAddressFromConfigFileFunc + conceptAccount.FileRepresentation + + let publicAddressMatches = + (account.PublicAddress = + publicAddressOfConceptAccount) + + publicAddressMatches) + ) } let WipeAll () = @@ -845,9 +878,10 @@ module Account = let public ExportUnsignedTransactionToJson trans = Marshalling.Serialize trans - let private SerializeUnsignedTransactionPlain (transProposal: UnsignedTransactionProposal) - (txMetadata: IBlockchainFeeInfo) - : string = + let private SerializeUnsignedTransactionPlain + (transProposal: UnsignedTransactionProposal) + (txMetadata: IBlockchainFeeInfo) + : string = let readOnlyAccounts = GetAllActiveAccounts().OfType () match txMetadata with @@ -863,65 +897,75 @@ module Account = readOnlyAccounts | _ -> failwith "fee type unknown" - let SaveUnsignedTransaction (transProposal: UnsignedTransactionProposal) - (txMetadata: IBlockchainFeeInfo) - (filePath: string) - = + let SaveUnsignedTransaction + (transProposal: UnsignedTransactionProposal) + (txMetadata: IBlockchainFeeInfo) + (filePath: string) + = let json = SerializeUnsignedTransactionPlain transProposal txMetadata File.WriteAllText (filePath, json) - let public ImportUnsignedTransactionFromJson (json: string) - : UnsignedTransaction = + let public ImportUnsignedTransactionFromJson + (json: string) + : UnsignedTransaction = let transType = Marshalling.ExtractType json match transType with - | _ when transType = typeof> -> + | _ when + transType = typeof> -> let deserializedBtcTransaction: UnsignedTransaction = Marshalling.Deserialize json deserializedBtcTransaction.ToAbstract () - | _ when transType = typeof> -> + | _ when + transType = typeof> -> let deserializedBtcTransaction: UnsignedTransaction = Marshalling.Deserialize json deserializedBtcTransaction.ToAbstract () | unexpectedType -> raise - <| Exception - (SPrintF1 + <| Exception ( + SPrintF1 "Unknown unsignedTransaction subtype: %s" - unexpectedType.FullName) + unexpectedType.FullName + ) - let public ImportSignedTransactionFromJson (json: string) - : SignedTransaction = + let public ImportSignedTransactionFromJson + (json: string) + : SignedTransaction = let transType = Marshalling.ExtractType json match transType with - | _ when transType = typeof> -> + | _ when + transType = typeof> -> let deserializedBtcTransaction: SignedTransaction = Marshalling.Deserialize json deserializedBtcTransaction.ToAbstract () - | _ when transType = typeof> -> + | _ when + transType = typeof> -> let deserializedBtcTransaction: SignedTransaction = Marshalling.Deserialize json deserializedBtcTransaction.ToAbstract () | unexpectedType -> raise - <| Exception - (SPrintF1 + <| Exception ( + SPrintF1 "Unknown signedTransaction subtype: %s" - unexpectedType.FullName) + unexpectedType.FullName + ) let LoadSignedTransactionFromFile (filePath: string) = let signedTransInJson = File.ReadAllText (filePath) ImportSignedTransactionFromJson signedTransInJson - let LoadUnsignedTransactionFromFile (filePath: string) - : UnsignedTransaction = + let LoadUnsignedTransactionFromFile + (filePath: string) + : UnsignedTransaction = let unsignedTransInJson = File.ReadAllText (filePath) ImportUnsignedTransactionFromJson unsignedTransInJson diff --git a/src/GWallet.Backend/AccountTypes.fs b/src/GWallet.Backend/AccountTypes.fs index be5cbdf1d..399f2ff82 100644 --- a/src/GWallet.Backend/AccountTypes.fs +++ b/src/GWallet.Backend/AccountTypes.fs @@ -44,9 +44,12 @@ type IAccount = abstract PublicAddress: string [] -type BaseAccount (currency: Currency, - accountFile: FileRepresentation, - fromAccountFileToPublicAddress: FileRepresentation -> string) = +type BaseAccount + ( + currency: Currency, + accountFile: FileRepresentation, + fromAccountFileToPublicAddress: FileRepresentation -> string + ) = member val AccountFile = accountFile abstract Kind: AccountKind @@ -56,27 +59,36 @@ type BaseAccount (currency: Currency, member val PublicAddress = fromAccountFileToPublicAddress accountFile -type NormalAccount (currency: Currency, - accountFile: FileRepresentation, - fromAccountFileToPublicAddress: FileRepresentation -> string) = - inherit BaseAccount(currency, accountFile, fromAccountFileToPublicAddress) +type NormalAccount + ( + currency: Currency, + accountFile: FileRepresentation, + fromAccountFileToPublicAddress: FileRepresentation -> string + ) = + inherit BaseAccount (currency, accountFile, fromAccountFileToPublicAddress) member internal __.GetEncryptedPrivateKey () = accountFile.Content () override __.Kind = AccountKind.Normal -type ReadOnlyAccount (currency: Currency, - accountFile: FileRepresentation, - fromAccountFileToPublicAddress: FileRepresentation -> string) = - inherit BaseAccount(currency, accountFile, fromAccountFileToPublicAddress) +type ReadOnlyAccount + ( + currency: Currency, + accountFile: FileRepresentation, + fromAccountFileToPublicAddress: FileRepresentation -> string + ) = + inherit BaseAccount (currency, accountFile, fromAccountFileToPublicAddress) override __.Kind = AccountKind.ReadOnly -type ArchivedAccount (currency: Currency, - accountFile: FileRepresentation, - fromAccountFileToPublicAddress: FileRepresentation -> string) = - inherit BaseAccount(currency, accountFile, fromAccountFileToPublicAddress) +type ArchivedAccount + ( + currency: Currency, + accountFile: FileRepresentation, + fromAccountFileToPublicAddress: FileRepresentation -> string + ) = + inherit BaseAccount (currency, accountFile, fromAccountFileToPublicAddress) member internal __.GetUnencryptedPrivateKey () = accountFile.Content () diff --git a/src/GWallet.Backend/Caching.fs b/src/GWallet.Backend/Caching.fs index 857447793..1d5fc9c4a 100644 --- a/src/GWallet.Backend/Caching.fs +++ b/src/GWallet.Backend/Caching.fs @@ -51,9 +51,10 @@ type CachedNetworkData = } member self.ToDietCache (readOnlyAccounts: seq) = - let rec extractAddressesFromAccounts (acc: Map>) - (accounts: List) - : Map> = + let rec extractAddressesFromAccounts + (acc: Map>) + (accounts: List) + : Map> = match accounts with | [] -> acc | head :: tail -> @@ -63,10 +64,11 @@ type CachedNetworkData = | Some currencies -> currencies let newAcc = - acc.Add - (head.PublicAddress, - head.Currency.ToString () - :: existingCurrenciesForHeadAddress) + acc.Add ( + head.PublicAddress, + head.Currency.ToString () + :: existingCurrenciesForHeadAddress + ) extractAddressesFromAccounts newAcc tail @@ -87,9 +89,9 @@ type CachedNetworkData = seq { for (KeyValue (currency, currencyBalances)) in self.Balances do for (KeyValue (address, (balance, _))) in currencyBalances do - if readOnlyAccounts.Any - (fun account -> - (account :> IAccount).PublicAddress = address) then + if readOnlyAccounts.Any (fun account -> + (account :> IAccount).PublicAddress = address + ) then yield (currency.ToString (), balance) } |> Map.ofSeq @@ -120,13 +122,16 @@ module Caching = let private defaultCacheFiles = { CachedNetworkData = - FileInfo - (Path.Combine (GetCacheDir().FullName, "networkdata.json")) + FileInfo ( + Path.Combine (GetCacheDir().FullName, "networkdata.json") + ) ServerStats = - FileInfo - (Path.Combine - (GetCacheDir().FullName, - ServerRegistry.ServersEmbeddedResourceFileName)) + FileInfo ( + Path.Combine ( + GetCacheDir().FullName, + ServerRegistry.ServersEmbeddedResourceFileName + ) + ) } let public ImportFromJson<'T> (cacheData: string): 'T = @@ -160,8 +165,9 @@ module Caching = Infrastructure.LogError "Warning: cleaning incompatible cache data found" - Infrastructure.LogDebug - (SPrintF1 "JSON content: <<<%s>>>" json) + Infrastructure.LogDebug ( + SPrintF1 "JSON content: <<<%s>>>" json + ) None with :? FileNotFoundException -> None @@ -171,8 +177,9 @@ module Caching = let private WeirdNullCheckToDetectVersionConflicts x = Object.ReferenceEquals (x, null) - let private LoadFromDisk (files: CacheFiles) - : bool * CachedNetworkData * ServerRanking = + let private LoadFromDisk + (files: CacheFiles) + : bool * CachedNetworkData * ServerRanking = let maybeNetworkData = LoadFromDiskInternal files.CachedNetworkData @@ -194,11 +201,12 @@ module Caching = | None -> maybeFirstRun, resultingNetworkData, Map.empty | Some serverStats -> false, resultingNetworkData, serverStats - let rec private MergeRatesInternal (oldMap: Map<'K, CachedValue<'V>>) - (newMap: Map<'K, CachedValue<'V>>) - (currencyList: List<'K>) - (accumulator: Map<'K, CachedValue<'V>>) - = + let rec private MergeRatesInternal + (oldMap: Map<'K, CachedValue<'V>>) + (newMap: Map<'K, CachedValue<'V>>) + (currencyList: List<'K>) + (accumulator: Map<'K, CachedValue<'V>>) + = match currencyList with | [] -> accumulator | address :: tail -> @@ -220,17 +228,19 @@ module Caching = MergeRatesInternal oldMap newMap tail newAcc - let private MergeRates (oldMap: Map<'K, CachedValue<'V>>) - (newMap: Map<'K, CachedValue<'V>>) - = + let private MergeRates + (oldMap: Map<'K, CachedValue<'V>>) + (newMap: Map<'K, CachedValue<'V>>) + = let currencyList = Map.toList newMap |> List.map fst MergeRatesInternal oldMap newMap currencyList oldMap - let rec private MergeBalancesInternal (oldMap: Map>>) - (newMap: Map>>) - (addressList: List) - (accumulator: Map>>) - : Map>> = + let rec private MergeBalancesInternal + (oldMap: Map>>) + (newMap: Map>>) + (addressList: List) + (accumulator: Map>>) + : Map>> = match addressList with | [] -> accumulator | (currency, address) :: tail -> @@ -258,8 +268,10 @@ module Caching = let newCachedBalance = newMap.[currency].[address] let newAccBalances = - accBalancesForThisCurrency.Add - (address, newCachedBalance) + accBalancesForThisCurrency.Add ( + address, + newCachedBalance + ) let newAcc = accumulator.Add (currency, newAccBalances) MergeBalancesInternal oldMap newMap tail newAcc @@ -269,8 +281,10 @@ module Caching = let newAcc = if (newTime > time) then let newAccBalances = - accBalancesForThisCurrency.Add - (address, (newBalance, newTime)) + accBalancesForThisCurrency.Add ( + address, + (newBalance, newTime) + ) accumulator.Add (currency, newAccBalances) else @@ -278,9 +292,10 @@ module Caching = MergeBalancesInternal oldMap newMap tail newAcc - let private MergeBalances (oldMap: Map>>) - (newMap: Map>>) - : Map>> = + let private MergeBalances + (oldMap: Map>>) + (newMap: Map>>) + : Map>> = let addressList = seq { for currency, subMap in Map.toList newMap do @@ -303,12 +318,16 @@ module Caching = comb List.Empty lst - let MapCombinations<'K, 'V when 'K: comparison> (map: Map<'K, 'V>) - : List> = + let MapCombinations<'K, 'V when 'K: comparison> + (map: Map<'K, 'V>) + : List> = Map.toList map |> ListCombinations - type MainCache (maybeCacheFiles: Option, - unconfTxExpirationSpan: TimeSpan) = + type MainCache + ( + maybeCacheFiles: Option, + unconfTxExpirationSpan: TimeSpan + ) = let cacheFiles = match maybeCacheFiles with | Some files -> files @@ -318,8 +337,10 @@ module Caching = let networkDataInJson = Marshalling.Serialize newCachedData // it is assumed that SaveToDisk is being run under a lock() block - File.WriteAllText - (cacheFiles.CachedNetworkData.FullName, networkDataInJson) + File.WriteAllText ( + cacheFiles.CachedNetworkData.FullName, + networkDataInJson + ) // we return back the rankings because the serialization process could remove dupes (and deserialization time // is basically negligible, i.e. took 15 milliseconds max in my MacBook in Debug mode) @@ -327,8 +348,10 @@ module Caching = let serverStatsInJson = ServerRegistry.Serialize serverStats // it is assumed that SaveToDisk is being run under a lock() block - File.WriteAllText - (cacheFiles.ServerStats.FullName, serverStatsInJson) + File.WriteAllText ( + cacheFiles.ServerStats.FullName, + serverStatsInJson + ) match LoadFromDiskInternal cacheFiles.ServerStats with | None -> failwith "should return something after having saved it" @@ -341,11 +364,12 @@ module Caching = for KeyValue (currency, servers) in mergedAndSaved do for server in servers do if server.CommunicationHistory.IsNone then - Infrastructure.LogError - (SPrintF2 + Infrastructure.LogError ( + SPrintF2 "WARNING: no history stats about %A server %s" currency - server.ServerInfo.NetworkPath) + server.ServerInfo.NetworkPath + ) mergedServers @@ -357,10 +381,11 @@ module Caching = let mutable sessionCachedNetworkData = initialSessionCachedNetworkData let mutable sessionServerRanking = initialServerStats - let GetSumOfAllTransactions (trans: Map>>>) - currency - address - : decimal = + let GetSumOfAllTransactions + (trans: Map>>>) + currency + address + : decimal = let now = DateTime.UtcNow let currencyTrans = trans.TryFind currency @@ -373,45 +398,48 @@ module Caching = | None -> 0m | Some someMap -> Map.toSeq someMap - |> Seq.sumBy - (fun (_, (txAmount, txDate)) -> - // FIXME: develop some kind of cache cleanup to remove these expired txs? - if (now < txDate + unconfTxExpirationSpan) then - txAmount - else - 0m) + |> Seq.sumBy (fun (_, (txAmount, txDate)) -> + // FIXME: develop some kind of cache cleanup to remove these expired txs? + if (now < txDate + unconfTxExpirationSpan) then + txAmount + else + 0m + ) let rec RemoveRangeFromMap (map: Map<'K, 'V>) (list: List<'K * 'V>) = match list with | [] -> map | (key, _) :: tail -> RemoveRangeFromMap (map.Remove key) tail - let GatherDebuggingInfo (previousBalance) - (currency) - (address) - (newCache) - = + let GatherDebuggingInfo + (previousBalance) + (currency) + (address) + (newCache) + = let json1 = Marshalling.Serialize previousBalance let json2 = Marshalling.Serialize currency let json3 = Marshalling.Serialize address let json4 = Marshalling.Serialize newCache String.Join (Environment.NewLine, json1, json2, json3, json4) - let ReportProblem (negativeBalance: decimal) - (previousBalance) - (currency) - (address) - (newCache) - = - Infrastructure.ReportError - (SPrintF2 + let ReportProblem + (negativeBalance: decimal) + (previousBalance) + (currency) + (address) + (newCache) + = + Infrastructure.ReportError ( + SPrintF2 "Negative balance '%s'. Details: %s" (negativeBalance.ToString ()) (GatherDebuggingInfo previousBalance currency address - newCache)) + newCache) + ) member __.ClearAll () = SaveNetworkDataToDisk CachedNetworkData.Empty @@ -441,12 +469,14 @@ module Caching = } sessionCachedNetworkData <- newSessionCachedNetworkData - SaveNetworkDataToDisk newSessionCachedNetworkData) + SaveNetworkDataToDisk newSessionCachedNetworkData + ) member __.GetLastCachedData (): CachedNetworkData = lock cacheFiles.CachedNetworkData - (fun _ -> sessionCachedNetworkData) + (fun _ -> sessionCachedNetworkData + ) member __.RetrieveLastKnownUsdPrice currency: NotFresh = lock @@ -455,10 +485,14 @@ module Caching = try Cached (sessionCachedNetworkData.UsdPrice.Item currency) with :? System.Collections.Generic.KeyNotFoundException -> - NotAvailable) - - member __.StoreLastFiatUsdPrice (currency, lastFiatUsdPrice: decimal) - : unit = + NotAvailable + ) + + member __.StoreLastFiatUsdPrice + ( + currency, + lastFiatUsdPrice: decimal + ): unit = lock cacheFiles.CachedNetworkData (fun _ -> @@ -467,25 +501,30 @@ module Caching = let newCachedValue = { sessionCachedNetworkData with UsdPrice = - sessionCachedNetworkData.UsdPrice.Add - (currency, (lastFiatUsdPrice, time)) + sessionCachedNetworkData.UsdPrice.Add ( + currency, + (lastFiatUsdPrice, time) + ) } sessionCachedNetworkData <- newCachedValue - SaveNetworkDataToDisk newCachedValue) + SaveNetworkDataToDisk newCachedValue + ) - member __.RetrieveLastCompoundBalance (address: PublicAddress) - (currency: Currency) - : NotFresh = + member __.RetrieveLastCompoundBalance + (address: PublicAddress) + (currency: Currency) + : NotFresh = lock cacheFiles.CachedNetworkData (fun _ -> let balance = try - Cached - ((sessionCachedNetworkData.Balances.Item - currency).Item address) + Cached ( + (sessionCachedNetworkData.Balances.Item currency).Item + address + ) with :? System.Collections.Generic.KeyNotFoundException -> NotAvailable @@ -510,11 +549,13 @@ module Caching = Cached (0.0m, time) else - Cached (compoundBalance, time)) + Cached (compoundBalance, time) + ) - member self.TryRetrieveLastCompoundBalance (address: PublicAddress) - (currency: Currency) - : Option = + member self.TryRetrieveLastCompoundBalance + (address: PublicAddress) + (currency: Currency) + : Option = let maybeCachedBalance = self.RetrieveLastCompoundBalance address currency @@ -522,10 +563,11 @@ module Caching = | NotAvailable -> None | Cached (cachedBalance, _) -> Some cachedBalance - member __.RetrieveAndUpdateLastCompoundBalance (address: PublicAddress) - (currency: Currency) - (newBalance: decimal) - : CachedValue = + member __.RetrieveAndUpdateLastCompoundBalance + (address: PublicAddress) + (currency: Currency) + (newBalance: decimal) + : CachedValue = let time = DateTime.UtcNow lock @@ -544,10 +586,13 @@ module Caching = { sessionCachedNetworkData with Balances = - sessionCachedNetworkData.Balances.Add - (currency, - newCurrencyBalances.Add - (address, (newBalance, time))) + sessionCachedNetworkData.Balances.Add ( + currency, + newCurrencyBalances.Add ( + address, + (newBalance, time) + ) + ) }, previousBalance @@ -556,7 +601,8 @@ module Caching = FSharpUtil.option { let! previousCachedBalance, _ = previousBalance - do! if newBalance <> previousCachedBalance + do! + if newBalance <> previousCachedBalance && previousCachedBalance > newBalance then Some () else @@ -578,11 +624,13 @@ module Caching = let txSumAmount = List.sumBy (fun (_, (txAmount, _)) -> - txAmount) + txAmount + ) combination previousCachedBalance - - txSumAmount = newBalance) + - txSumAmount = newBalance + ) allCombinationsOfTransactions with | None -> addressTransactions | Some combination -> @@ -591,10 +639,13 @@ module Caching = combination let newOutgoingTransactions = - newCachedValueWithNewBalance.OutgoingTransactions.Add - (currency, - currencyAddresses.Add - (address, newAddressTransactions)) + newCachedValueWithNewBalance.OutgoingTransactions.Add ( + currency, + currencyAddresses.Add ( + address, + newAddressTransactions + ) + ) return { newCachedValueWithNewBalance with @@ -631,13 +682,15 @@ module Caching = 0.0m, time else - compoundBalance, time) - - member private __.StoreTransactionRecord (address: PublicAddress) - (currency: Currency) - (txId: string) - (amount: decimal) - : unit = + compoundBalance, time + ) + + member private __.StoreTransactionRecord + (address: PublicAddress) + (currency: Currency) + (txId: string) + (amount: decimal) + : unit = let time = DateTime.UtcNow lock @@ -656,10 +709,13 @@ module Caching = addressTransactions.Add (txId, (amount, time)) let newOutgoingTxs = - sessionCachedNetworkData.OutgoingTransactions.Add - (currency, - newCurrencyAddresses.Add - (address, newAddressTransactions)) + sessionCachedNetworkData.OutgoingTransactions.Add ( + currency, + newCurrencyAddresses.Add ( + address, + newAddressTransactions + ) + ) let newCachedValue = { sessionCachedNetworkData with @@ -668,15 +724,17 @@ module Caching = sessionCachedNetworkData <- newCachedValue - SaveNetworkDataToDisk newCachedValue) + SaveNetworkDataToDisk newCachedValue + ) - member self.StoreOutgoingTransaction (address: PublicAddress) - (transactionCurrency: Currency) - (feeCurrency: Currency) - (txId: string) - (amount: decimal) - (feeAmount: decimal) - : unit = + member self.StoreOutgoingTransaction + (address: PublicAddress) + (transactionCurrency: Currency) + (feeCurrency: Currency) + (txId: string) + (amount: decimal) + (feeAmount: decimal) + : unit = self.StoreTransactionRecord address transactionCurrency txId amount @@ -684,9 +742,10 @@ module Caching = && (not Config.EthTokenEstimationCouldBeBuggyAsInNotAccurate) then self.StoreTransactionRecord address feeCurrency txId feeAmount - member __.SaveServerLastStat (serverMatchFunc: ServerDetails -> bool) - (stat: HistoryFact) - : unit = + member __.SaveServerLastStat + (serverMatchFunc: ServerDetails -> bool) + (stat: HistoryFact) + : unit = lock cacheFiles.ServerStats (fun _ -> @@ -751,11 +810,14 @@ module Caching = serversForCurrency let newServerList = - sessionServerRanking.Add - (currency, newServersForCurrency) + sessionServerRanking.Add ( + currency, + newServersForCurrency + ) let newCachedValue = SaveServerRankingsToDisk newServerList - sessionServerRanking <- newCachedValue) + sessionServerRanking <- newCachedValue + ) member __.GetServers (currency: Currency): seq = lock @@ -767,18 +829,20 @@ module Caching = <| SPrintF1 "Initialization of servers' cache failed? currency %A not found" currency - | Some servers -> servers) + | Some servers -> servers + ) member __.ExportServers (): Option = lock cacheFiles.ServerStats - (fun _ -> LoadFromDiskInner cacheFiles.ServerStats) + (fun _ -> LoadFromDiskInner cacheFiles.ServerStats + ) member __.BootstrapServerStatsFromTrustedSource (): Async = let downloadFile url: Async> = let tryDownloadFile url: Async = async { - use httpClient = new HttpClient() + use httpClient = new HttpClient () let uri = Uri url let! response = @@ -793,9 +857,10 @@ module Caching = if isSuccess then return content else - Infrastructure.LogError - ("WARNING: error trying to retrieve server stats: " - + content) + Infrastructure.LogError ( + "WARNING: error trying to retrieve server stats: " + + content + ) return failwith content } @@ -871,7 +936,8 @@ module Caching = let savedServerStats = SaveServerRankingsToDisk lastServerStats - sessionServerRanking <- savedServerStats) + sessionServerRanking <- savedServerStats + ) } member __.FirstRun = firstRun diff --git a/src/GWallet.Backend/Config.fs b/src/GWallet.Backend/Config.fs index cc374bdce..f13cdd4fa 100644 --- a/src/GWallet.Backend/Config.fs +++ b/src/GWallet.Backend/Config.fs @@ -63,9 +63,10 @@ module Config = let! monoRuntime = Type.GetType "Mono.Runtime" |> Option.ofObj // this gives None on Mono Android/iOS/macOS let! displayName = - monoRuntime.GetMethod - ("GetDisplayName", - BindingFlags.NonPublic ||| BindingFlags.Static) + monoRuntime.GetMethod ( + "GetDisplayName", + BindingFlags.NonPublic ||| BindingFlags.Static + ) |> Option.ofObj // example: 5.12.0.309 (2018-02/39d89a335c8 Thu Sep 27 06:54:53 EDT 2018) let fullVersion = displayName.Invoke (null, null) :?> string @@ -85,8 +86,9 @@ module Config = let internal GetConfigDirForThisProgram () = let configPath = - Environment.GetFolderPath - (Environment.SpecialFolder.ApplicationData) + Environment.GetFolderPath ( + Environment.SpecialFolder.ApplicationData + ) let configDir = DirectoryInfo (Path.Combine (configPath, "gwallet")) @@ -136,15 +138,18 @@ module Config = for ethAccountFilePath in Directory.GetFiles ethConfigDir.FullName do let newPath = - ethAccountFilePath.Replace - (ethConfigDir.FullName, tokenConfigDir.FullName) + ethAccountFilePath.Replace ( + ethConfigDir.FullName, + tokenConfigDir.FullName + ) if not (File.Exists newPath) then File.Copy (ethAccountFilePath, newPath) - let GetAccountFiles (currencies: seq) - (accountKind: AccountKind) - : seq = + let GetAccountFiles + (currencies: seq) + (accountKind: AccountKind) + : seq = seq { for currency in currencies do for filePath in Directory.GetFiles @@ -158,22 +163,26 @@ module Config = Path.Combine (configDir.FullName, fileName) |> FileInfo - let AddAccount (conceptAccount: ConceptAccount) - (accountKind: AccountKind) - : FileRepresentation = + let AddAccount + (conceptAccount: ConceptAccount) + (accountKind: AccountKind) + : FileRepresentation = let configDir = GetConfigDir conceptAccount.Currency accountKind let newAccountFile = - Path.Combine - (configDir.FullName, conceptAccount.FileRepresentation.Name) + Path.Combine ( + configDir.FullName, + conceptAccount.FileRepresentation.Name + ) |> FileInfo if newAccountFile.Exists then raise AccountAlreadyAdded - File.WriteAllText - (newAccountFile.FullName, - conceptAccount.FileRepresentation.Content ()) + File.WriteAllText ( + newAccountFile.FullName, + conceptAccount.FileRepresentation.Content () + ) { Name = Path.GetFileName newAccountFile.FullName @@ -209,5 +218,5 @@ module Config = if (stream = null) then failwith <| SPrintF1 "Embedded resource %s not found" resourceName - use reader = new StreamReader(stream) + use reader = new StreamReader (stream) reader.ReadToEnd () diff --git a/src/GWallet.Backend/Currency.fs b/src/GWallet.Backend/Currency.fs index 54429fb40..b57f283fd 100644 --- a/src/GWallet.Backend/Currency.fs +++ b/src/GWallet.Backend/Currency.fs @@ -83,7 +83,7 @@ type Currency = // the reason we have used "and" is because of the circular reference // between StringTypeConverter and Currency and private StringTypeConverter () = - inherit TypeConverter() + inherit TypeConverter () override __.CanConvertFrom (context, sourceType) = sourceType = typeof || base.CanConvertFrom (context, sourceType) @@ -92,7 +92,8 @@ and private StringTypeConverter () = match value with | :? string as stringValue -> Seq.find - (fun cur -> cur.ToString () = stringValue) + (fun cur -> cur.ToString () = stringValue + ) (Currency.GetAll ()) :> obj | _ -> base.ConvertFrom (context, culture, value) diff --git a/src/GWallet.Backend/Ether/EtherAccount.fs b/src/GWallet.Backend/Ether/EtherAccount.fs index c9599803b..c56233bd3 100644 --- a/src/GWallet.Backend/Ether/EtherAccount.fs +++ b/src/GWallet.Backend/Ether/EtherAccount.fs @@ -25,8 +25,9 @@ module internal Account = let GetPublicAddressFromUnencryptedPrivateKey (privateKey: string) = EthECKey(privateKey).GetPublicAddress() - let internal GetPublicAddressFromNormalAccountFile (accountFile: FileRepresentation) - : string = + let internal GetPublicAddressFromNormalAccountFile + (accountFile: FileRepresentation) + : string = let encryptedPrivateKey = accountFile.Content () let rawPublicAddress = @@ -40,10 +41,11 @@ module internal Account = publicAddress - let internal GetAccountFromFile (accountFile: FileRepresentation) - (currency: Currency) - kind - : IAccount = + let internal GetAccountFromFile + (accountFile: FileRepresentation) + (currency: Currency) + kind + : IAccount = if not (currency.IsEtherBased ()) then failwith <| SPrintF1 @@ -52,20 +54,27 @@ module internal Account = match kind with | AccountKind.ReadOnly -> - ReadOnlyAccount - (currency, accountFile, (fun accountFile -> accountFile.Name)) + ReadOnlyAccount ( + currency, + accountFile, + (fun accountFile -> accountFile.Name) + ) :> IAccount | AccountKind.Normal -> - NormalAccount - (currency, accountFile, GetPublicAddressFromNormalAccountFile) + NormalAccount ( + currency, + accountFile, + GetPublicAddressFromNormalAccountFile + ) :> IAccount | _ -> failwith <| SPrintF1 "Kind (%A) not supported for this API" kind - let private GetBalance (account: IAccount) - (mode: ServerSelectionMode) - (balType: BalanceType) - (cancelSourceOption: Option) - = + let private GetBalance + (account: IAccount) + (mode: ServerSelectionMode) + (balType: BalanceType) + (cancelSourceOption: Option) + = async { let! balance = if (account.Currency.IsEther ()) then @@ -91,28 +100,31 @@ module internal Account = return balance } - let private GetBalanceFromServer (account: IAccount) - (balType: BalanceType) - (mode: ServerSelectionMode) - (cancelSourceOption: Option) - : Async> = + let private GetBalanceFromServer + (account: IAccount) + (balType: BalanceType) + (mode: ServerSelectionMode) + (cancelSourceOption: Option) + : Async> = async { try let! balance = GetBalance account mode balType cancelSourceOption return Some balance - with ex when (FSharpUtil.FindException - ex) - .IsSome -> return None + with ex when + (FSharpUtil.FindException ex) + .IsSome -> return None } - let internal GetShowableBalance (account: IAccount) - (mode: ServerSelectionMode) - (cancelSourceOption: Option) - : Async> = - let getBalanceWithoutCaching (maybeUnconfirmedBalanceTaskAlreadyStarted: Option>>) - : Async> = + let internal GetShowableBalance + (account: IAccount) + (mode: ServerSelectionMode) + (cancelSourceOption: Option) + : Async> = + let getBalanceWithoutCaching + (maybeUnconfirmedBalanceTaskAlreadyStarted: Option>>) + : Async> = async { let! confirmed = GetBalanceFromServer @@ -158,9 +170,10 @@ module internal Account = let! cancellationToken = Async.CancellationToken let unconfirmedTask = - Async.StartAsTask - (unconfirmedJob, - ?cancellationToken = Some cancellationToken) + Async.StartAsTask ( + unconfirmedJob, + ?cancellationToken = Some cancellationToken + ) let maybeCachedBalance = Caching.Instance.RetrieveLastCompoundBalance @@ -198,7 +211,8 @@ module internal Account = if (address.Length <> ETHEREUM_ADDRESSES_LENGTH) then raise <| AddressWithInvalidLength [ ETHEREUM_ADDRESSES_LENGTH ] - do! Ether.Server.CheckIfAddressIsAValidPaymentDestination + do! + Ether.Server.CheckIfAddressIsAValidPaymentDestination currency address @@ -209,9 +223,10 @@ module internal Account = raise (AddressWithInvalidChecksum (Some validCheckSumAddress)) } - let private GetTransactionCount (currency: Currency) - (publicAddress: string) - : Async = + let private GetTransactionCount + (currency: Currency) + (publicAddress: string) + : Async = async { let! result = Ether.Server.GetTransactionCount currency publicAddress @@ -246,18 +261,20 @@ module internal Account = let private GAS_COST_FOR_A_NORMAL_ETHER_TRANSACTION: int64 = 21000L - let EstimateEtherTransferFee (account: IAccount) - (amount: TransferAmount) - : Async = + let EstimateEtherTransferFee + (account: IAccount) + (amount: TransferAmount) + : Async = async { let! gasPrice64 = GetGasPrice account.Currency let ethMinerFee = - MinerFee - (GAS_COST_FOR_A_NORMAL_ETHER_TRANSACTION, - gasPrice64, - DateTime.UtcNow, - account.Currency) + MinerFee ( + GAS_COST_FOR_A_NORMAL_ETHER_TRANSACTION, + gasPrice64, + DateTime.UtcNow, + account.Currency + ) let! txCount = GetTransactionCount account.Currency account.PublicAddress @@ -277,10 +294,11 @@ module internal Account = } // FIXME: this should raise InsufficientBalanceForFee - let EstimateTokenTransferFee (account: IAccount) - amount - destination - : Async = + let EstimateTokenTransferFee + (account: IAccount) + amount + destination + : Async = async { let! gasPrice64 = GetGasPrice account.Currency @@ -314,10 +332,11 @@ module internal Account = } } - let EstimateFee (account: IAccount) - (amount: TransferAmount) - destination - : Async = + let EstimateFee + (account: IAccount) + (amount: TransferAmount) + destination + : Async = async { if account.Currency.IsEther () then return! EstimateEtherTransferFee account amount @@ -348,8 +367,10 @@ module internal Account = let privKeyInBytes = try - KeyStoreService.DecryptKeyStoreFromJson - (password, encryptedPrivateKey) + KeyStoreService.DecryptKeyStoreFromJson ( + password, + encryptedPrivateKey + ) with :? DecryptionException -> raise (InvalidPassword) EthECKey (privKeyInBytes, true) @@ -371,12 +392,13 @@ module internal Account = "Assertion failed: Ether currency %A not supported?" currency - let private SignEtherTransaction (currency: Currency) - (txMetadata: TransactionMetadata) - (destination: string) - (amount: TransferAmount) - (privateKey: EthECKey) - = + let private SignEtherTransaction + (currency: Currency) + (txMetadata: TransactionMetadata) + (destination: string) + (amount: TransferAmount) + (privateKey: EthECKey) + = let chain = GetNetwork currency @@ -395,42 +417,48 @@ module internal Account = amount.ValueToSend let amountInWei = - UnitConversion.Convert.ToWei - (amountToSendConsideringMinerFee, UnitConversion.EthUnit.Ether) + UnitConversion.Convert.ToWei ( + amountToSendConsideringMinerFee, + UnitConversion.EthUnit.Ether + ) let privKeyInBytes = privateKey.GetPrivateKeyAsBytes () let trans = - signer.SignTransaction - (privKeyInBytes, - chain, - destination, - amountInWei, - BigInteger (txMetadata.TransactionCount), - - // we use the SignTransaction() overload that has these 2 arguments because if we don't, we depend on - // how well the defaults are of Geth node we're connected to, e.g. with the myEtherWallet server I - // was trying to spend 0.002ETH from an account that had 0.01ETH and it was always failing with the - // "Insufficient Funds" error saying it needed 212,000,000,000,000,000 wei (0.212 ETH)... - BigInteger (txMetadata.Fee.GasPriceInWei), - BigInteger (txMetadata.Fee.GasLimit)) + signer.SignTransaction ( + privKeyInBytes, + chain, + destination, + amountInWei, + BigInteger (txMetadata.TransactionCount), + + // we use the SignTransaction() overload that has these 2 arguments because if we don't, we depend on + // how well the defaults are of Geth node we're connected to, e.g. with the myEtherWallet server I + // was trying to spend 0.002ETH from an account that had 0.01ETH and it was always failing with the + // "Insufficient Funds" error saying it needed 212,000,000,000,000,000 wei (0.212 ETH)... + BigInteger (txMetadata.Fee.GasPriceInWei), + BigInteger (txMetadata.Fee.GasLimit) + ) trans - let private SignEtherTokenTransaction (currency: Currency) - (txMetadata: TransactionMetadata) - (origin: string) - (destination: string) - (amount: TransferAmount) - (privateKey: EthECKey) - = + let private SignEtherTokenTransaction + (currency: Currency) + (txMetadata: TransactionMetadata) + (origin: string) + (destination: string) + (amount: TransferAmount) + (privateKey: EthECKey) + = let chain = GetNetwork currency let privKeyInBytes = privateKey.GetPrivateKeyAsBytes () let amountInWei = - UnitConversion.Convert.ToWei - (amount.ValueToSend, UnitConversion.EthUnit.Ether) + UnitConversion.Convert.ToWei ( + amount.ValueToSend, + UnitConversion.EthUnit.Ether + ) let gasLimit = BigInteger (txMetadata.Fee.GasLimit) @@ -446,22 +474,24 @@ module internal Account = let gasPrice = BigInteger (txMetadata.Fee.GasPriceInWei) let contractAddress = TokenManager.GetTokenContractAddress currency - signer.SignTransaction - (privKeyInBytes, - chain, - contractAddress, - etherValue, - nonce, - gasPrice, - gasLimit, - data) - - let private SignTransactionWithPrivateKey (account: IAccount) - (txMetadata: TransactionMetadata) - (destination: string) - (amount: TransferAmount) - (privateKey: EthECKey) - = + signer.SignTransaction ( + privKeyInBytes, + chain, + contractAddress, + etherValue, + nonce, + gasPrice, + gasLimit, + data + ) + + let private SignTransactionWithPrivateKey + (account: IAccount) + (txMetadata: TransactionMetadata) + (destination: string) + (amount: TransferAmount) + (privateKey: EthECKey) + = let trans = if account.Currency.IsEthToken () then @@ -499,12 +529,13 @@ module internal Account = trans - let SignTransaction (account: NormalAccount) - (txMetadata: TransactionMetadata) - (destination: string) - (amount: TransferAmount) - (password: string) - = + let SignTransaction + (account: NormalAccount) + (txMetadata: TransactionMetadata) + (destination: string) + (amount: TransferAmount) + (password: string) + = let privateKey = GetPrivateKey account password @@ -518,11 +549,12 @@ module internal Account = let CheckValidPassword (account: NormalAccount) (password: string) = GetPrivateKey account password |> ignore - let SweepArchivedFunds (account: ArchivedAccount) - (balance: decimal) - (destination: IAccount) - (txMetadata: TransactionMetadata) - = + let SweepArchivedFunds + (account: ArchivedAccount) + (balance: decimal) + (destination: IAccount) + (txMetadata: TransactionMetadata) + = let accountFrom = (account :> IAccount) let amount = TransferAmount (balance, balance, accountFrom.Currency) let ecPrivKey = EthECKey (account.GetUnencryptedPrivateKey ()) @@ -537,16 +569,19 @@ module internal Account = BroadcastRawTransaction accountFrom.Currency signedTrans - let SendPayment (account: NormalAccount) - (txMetadata: TransactionMetadata) - (destination: string) - (amount: TransferAmount) - (password: string) - = + let SendPayment + (account: NormalAccount) + (txMetadata: TransactionMetadata) + (destination: string) + (amount: TransferAmount) + (password: string) + = let baseAccount = account :> IAccount - if (baseAccount.PublicAddress.Equals - (destination, StringComparison.InvariantCultureIgnoreCase)) then + if (baseAccount.PublicAddress.Equals ( + destination, + StringComparison.InvariantCultureIgnoreCase + )) then raise DestinationEqualToOrigin let currency = baseAccount.Currency @@ -556,20 +591,25 @@ module internal Account = BroadcastRawTransaction currency trans - let private CreateInternal (password: string) - (seed: array) - : FileRepresentation = + let private CreateInternal + (password: string) + (seed: array) + : FileRepresentation = let privateKey = EthECKey (seed, true) let publicAddress = privateKey.GetPublicAddress () if not (addressUtil.IsChecksumAddress (publicAddress)) then - failwith - ("Nethereum's GetPublicAddress gave a non-checksum address: " - + publicAddress) + failwith ( + "Nethereum's GetPublicAddress gave a non-checksum address: " + + publicAddress + ) let accountSerializedJson = - KeyStoreService.EncryptAndGenerateDefaultKeyStoreAsJson - (password, seed, publicAddress) + KeyStoreService.EncryptAndGenerateDefaultKeyStoreAsJson ( + password, + seed, + publicAddress + ) let fileNameForAccount = KeyStoreService.GenerateUTCFileName (publicAddress) @@ -579,18 +619,20 @@ module internal Account = Content = fun _ -> accountSerializedJson } - let Create (password: string) - (seed: array) - : Async = + let Create + (password: string) + (seed: array) + : Async = async { return CreateInternal password seed } let public ExportUnsignedTransactionToJson trans = Marshalling.Serialize trans - let SaveUnsignedTransaction (transProposal: UnsignedTransactionProposal) - (txMetadata: TransactionMetadata) - (readOnlyAccounts: seq) - : string = + let SaveUnsignedTransaction + (transProposal: UnsignedTransactionProposal) + (txMetadata: TransactionMetadata) + (readOnlyAccounts: seq) + : string = let unsignedTransaction = { diff --git a/src/GWallet.Backend/Ether/EtherExceptions.fs b/src/GWallet.Backend/Ether/EtherExceptions.fs index f8ce3e08d..a730d73d2 100644 --- a/src/GWallet.Backend/Ether/EtherExceptions.fs +++ b/src/GWallet.Backend/Ether/EtherExceptions.fs @@ -30,52 +30,52 @@ type RpcErrorCode = type ServerCannotBeResolvedException = inherit CommunicationUnsuccessfulException - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } type ServerUnavailableException = inherit CommunicationUnsuccessfulException - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } type ServerChannelNegotiationException = inherit CommunicationUnsuccessfulException - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } - - new(message: string, - webExStatusCode: WebExceptionStatus, - innerException: Exception) = - { inherit CommunicationUnsuccessfulException(SPrintF2 - "%s (WebErr: %s)" - message - (webExStatusCode.ToString - ()), - innerException) } - - new(message: string, - cloudFlareError: CloudFlareError, - innerException: Exception) = - { inherit CommunicationUnsuccessfulException(SPrintF2 - "%s (CfErr: %s)" - message - (cloudFlareError.ToString - ()), - innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } + + new (message: string, + webExStatusCode: WebExceptionStatus, + innerException: Exception) = + { inherit CommunicationUnsuccessfulException (SPrintF2 + "%s (WebErr: %s)" + message + (webExStatusCode.ToString + ()), + innerException) } + + new (message: string, + cloudFlareError: CloudFlareError, + innerException: Exception) = + { inherit CommunicationUnsuccessfulException (SPrintF2 + "%s (CfErr: %s)" + message + (cloudFlareError.ToString + ()), + innerException) } type ServerRestrictiveException = inherit CommunicationUnsuccessfulException - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } type UnhandledWebException = inherit Exception - new(status: WebExceptionStatus, innerException: Exception) = - { inherit Exception(SPrintF1 - "Backend not prepared for this WebException with Status[%i]" - (int status), - innerException) } + new (status: WebExceptionStatus, innerException: Exception) = + { inherit Exception (SPrintF1 + "Backend not prepared for this WebException with Status[%i]" + (int status), + innerException) } diff --git a/src/GWallet.Backend/Ether/EtherMinerFee.fs b/src/GWallet.Backend/Ether/EtherMinerFee.fs index 33b3ca15a..30ea761fa 100644 --- a/src/GWallet.Backend/Ether/EtherMinerFee.fs +++ b/src/GWallet.Backend/Ether/EtherMinerFee.fs @@ -7,10 +7,13 @@ open GWallet.Backend open Nethereum.Util -type MinerFee (gasLimit: Int64, - gasPriceInWei: Int64, - estimationTime: DateTime, - currency: Currency) = +type MinerFee + ( + gasLimit: Int64, + gasPriceInWei: Int64, + estimationTime: DateTime, + currency: Currency + ) = member val GasLimit = gasLimit member val GasPriceInWei = gasPriceInWei diff --git a/src/GWallet.Backend/Ether/TokenManager.fs b/src/GWallet.Backend/Ether/TokenManager.fs index 677882d86..2980fb320 100644 --- a/src/GWallet.Backend/Ether/TokenManager.fs +++ b/src/GWallet.Backend/Ether/TokenManager.fs @@ -20,13 +20,15 @@ module TokenManager = raise <| invalidOp (SPrintF1 "%A has no contract address" currency) type TokenServiceWrapper (web3, currency: Currency) = - inherit StandardTokenService(web3, GetTokenContractAddress currency) - - member self.ComposeInputDataForTransferTransaction (origin: string, - destination: string, - tokenAmountInWei: BigInteger, - gasLimit: BigInteger) - : string = + inherit StandardTokenService (web3, GetTokenContractAddress currency) + + member self.ComposeInputDataForTransferTransaction + ( + origin: string, + destination: string, + tokenAmountInWei: BigInteger, + gasLimit: BigInteger + ): string = let transferFuncBuilder = self.ContractHandler.GetFunction () @@ -36,11 +38,12 @@ module TokenManager = let tokenValue = HexBigInteger tokenAmountInWei let transactionInput = - transferFuncBuilder.CreateTransactionInput - (transferFunctionMsg, - origin, - HexBigInteger (gasLimit), - tokenValue) + transferFuncBuilder.CreateTransactionInput ( + transferFunctionMsg, + origin, + HexBigInteger (gasLimit), + tokenValue + ) if (transactionInput = null) then failwith @@ -65,4 +68,4 @@ module TokenManager = let private dummyOfflineWeb3 = Web3 () type OfflineTokenServiceWrapper (currency: Currency) = - inherit TokenServiceWrapper(dummyOfflineWeb3, currency) + inherit TokenServiceWrapper (dummyOfflineWeb3, currency) diff --git a/src/GWallet.Backend/FSharpUtil.fs b/src/GWallet.Backend/FSharpUtil.fs index 331850ba8..9e43747c2 100644 --- a/src/GWallet.Backend/FSharpUtil.fs +++ b/src/GWallet.Backend/FSharpUtil.fs @@ -33,18 +33,20 @@ module FSharpUtil = |] let formatsFound = - supportedFormats.Where - (fun format -> innerFmt.IndexOf (format) >= 0) + supportedFormats.Where (fun format -> + innerFmt.IndexOf (format) >= 0 + ) if formatsFound.Any () then let firstIndexWhereFormatFound = - formatsFound.Min - (fun format -> innerFmt.IndexOf (format)) + formatsFound.Min (fun format -> + innerFmt.IndexOf (format) + ) let firstFormat = - formatsFound.First - (fun format -> - innerFmt.IndexOf (format) = firstIndexWhereFormatFound) + formatsFound.First (fun format -> + innerFmt.IndexOf (format) = firstIndexWhereFormatFound + ) let subEnd = innerFmt.IndexOf (firstFormat) + "%x".Length let sub = innerFmt.Substring (0, subEnd) @@ -68,21 +70,23 @@ module FSharpUtil = let SPrintF3 (fmt: string) (a: Object) (b: Object) (c: Object) = String.Format (ToStringFormat fmt, a, b, c) - let SPrintF4 (fmt: string) - (a: Object) - (b: Object) - (c: Object) - (d: Object) - = + let SPrintF4 + (fmt: string) + (a: Object) + (b: Object) + (c: Object) + (d: Object) + = String.Format (ToStringFormat fmt, a, b, c, d) - let SPrintF5 (fmt: string) - (a: Object) - (b: Object) - (c: Object) - (d: Object) - (e: Object) - = + let SPrintF5 + (fmt: string) + (a: Object) + (b: Object) + (c: Object) + (d: Object) + (e: Object) + = String.Format (ToStringFormat fmt, a, b, c, d, e) @@ -112,28 +116,30 @@ module FSharpUtil = let SPrintF3 (fmt: string) (a: Object) (b: Object) (c: Object) = ReflectionlessPrint.SPrintF3 fmt a b c - let SPrintF4 (fmt: string) - (a: Object) - (b: Object) - (c: Object) - (d: Object) - = + let SPrintF4 + (fmt: string) + (a: Object) + (b: Object) + (c: Object) + (d: Object) + = ReflectionlessPrint.SPrintF4 fmt a b c d - let SPrintF5 (fmt: string) - (a: Object) - (b: Object) - (c: Object) - (d: Object) - (e: Object) - = + let SPrintF5 + (fmt: string) + (a: Object) + (b: Object) + (c: Object) + (d: Object) + (e: Object) + = ReflectionlessPrint.SPrintF5 fmt a b c d e #endif type internal ResultWrapper<'T> (value: 'T) = // hack? - inherit Exception() + inherit Exception () member __.Value = value @@ -154,10 +160,11 @@ module FSharpUtil = return aJobResult, bJobResult } - let MixedParallel3 (a: Async<'T1>) - (b: Async<'T2>) - (c: Async<'T3>) - : Async<'T1 * 'T2 * 'T3> = + let MixedParallel3 + (a: Async<'T1>) + (b: Async<'T2>) + (c: Async<'T3>) + : Async<'T1 * 'T2 * 'T3> = async { let aJob = Async.StartChild a let bJob = Async.StartChild b @@ -240,10 +247,11 @@ module FSharpUtil = (head1 :: acc) (currentIndex + 1) - let ListIntersect<'T> (list1: List<'T>) - (list2: List<'T>) - (offset: uint32) - : List<'T> = + let ListIntersect<'T> + (list1: List<'T>) + (list2: List<'T>) + (offset: uint32) + : List<'T> = ListIntersectInternal list1 list2 offset [] 1 let WithTimeout (timeSpan: TimeSpan) (job: Async<'R>): Async> = @@ -280,8 +288,9 @@ module FSharpUtil = failwith "Should be unreachable" ex - let rec public FindException<'T when 'T :> Exception> (ex: Exception) - : Option<'T> = + let rec public FindException<'T when 'T :> Exception> + (ex: Exception) + : Option<'T> = let rec findExInSeq (sq: seq) = match Seq.tryHead sq with | Some head -> diff --git a/src/GWallet.Backend/FiatValueEstimation.fs b/src/GWallet.Backend/FiatValueEstimation.fs index 24dbc0471..59b15aa90 100644 --- a/src/GWallet.Backend/FiatValueEstimation.fs +++ b/src/GWallet.Backend/FiatValueEstimation.fs @@ -28,11 +28,12 @@ module FiatValueEstimation = | CoinCap | CoinGecko - let private QueryOnlineInternal currency - (provider: PriceProvider) - : Async> = + let private QueryOnlineInternal + currency + (provider: PriceProvider) + : Async> = async { - use webClient = new WebClient() + use webClient = new WebClient () let tickerName = match currency, provider with diff --git a/src/GWallet.Backend/Formatting.fs b/src/GWallet.Backend/Formatting.fs index 096db016a..a0ddb66a6 100644 --- a/src/GWallet.Backend/Formatting.fs +++ b/src/GWallet.Backend/Formatting.fs @@ -32,10 +32,11 @@ module Formatting = else rounded.ToString formattingStrategy - let DecimalAmountTruncating (currencyType: CurrencyType) - (amount: decimal) - (maxAmount: decimal) - : string = + let DecimalAmountTruncating + (currencyType: CurrencyType) + (amount: decimal) + (maxAmount: decimal) + : string = let amountOfDecimalsToShow = match currencyType with | CurrencyType.Fiat -> 2 diff --git a/src/GWallet.Backend/Infrastructure.fs b/src/GWallet.Backend/Infrastructure.fs index bc895732e..976e54a41 100644 --- a/src/GWallet.Backend/Infrastructure.fs +++ b/src/GWallet.Backend/Infrastructure.fs @@ -38,13 +38,14 @@ module Infrastructure = if Config.DebugLog then LogInfo <| SPrintF1 "DEBUG: %s" log - let internal ReportMessage (message: string) + let internal ReportMessage + (message: string) #if DEBUG - (_: ErrorLevel) + (_: ErrorLevel) #else - (errorLevel: ErrorLevel) + (errorLevel: ErrorLevel) #endif - = + = #if DEBUG failwith message #else @@ -57,13 +58,14 @@ module Infrastructure = let internal ReportError (errorMessage: string) = ReportMessage errorMessage ErrorLevel.Error - let private Report (ex: Exception) + let private Report + (ex: Exception) #if DEBUG - (_: ErrorLevel) + (_: ErrorLevel) #else - (errorLevel: ErrorLevel) + (errorLevel: ErrorLevel) #endif - = + = // TODO: log this in a file (log4net?), as well as printing to the console, before sending to sentry Console.Error.WriteLine ex @@ -86,11 +88,13 @@ module Infrastructure = let ReportCrash (ex: Exception) = Report ex ErrorLevel.Fatal - let private OnUnhandledException (_: obj) - (args: UnhandledExceptionEventArgs) - = + let private OnUnhandledException + (_: obj) + (args: UnhandledExceptionEventArgs) + = ReportCrash (args.ExceptionObject :?> Exception) let public SetupSentryHook () = - AppDomain.CurrentDomain.UnhandledException.AddHandler - (UnhandledExceptionEventHandler (OnUnhandledException)) + AppDomain.CurrentDomain.UnhandledException.AddHandler ( + UnhandledExceptionEventHandler (OnUnhandledException) + ) diff --git a/src/GWallet.Backend/JsonRpcTcpClient.fs b/src/GWallet.Backend/JsonRpcTcpClient.fs index ea774c190..fcfcd0f9c 100644 --- a/src/GWallet.Backend/JsonRpcTcpClient.fs +++ b/src/GWallet.Backend/JsonRpcTcpClient.fs @@ -9,21 +9,21 @@ open GWallet.Backend.FSharpUtil.UwpHacks type ProtocolGlitchException = inherit CommunicationUnsuccessfulException - new(message) = { inherit CommunicationUnsuccessfulException(message) } + new (message) = { inherit CommunicationUnsuccessfulException (message) } - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } type ServerCannotBeResolvedException = inherit CommunicationUnsuccessfulException - new(message) = { inherit CommunicationUnsuccessfulException(message) } + new (message) = { inherit CommunicationUnsuccessfulException (message) } - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } type ServerNameResolvedToInvalidAddressException (message: string) = - inherit CommunicationUnsuccessfulException(message) + inherit CommunicationUnsuccessfulException (message) type JsonRpcTcpClient (host: string, port: uint32) = @@ -58,22 +58,25 @@ type JsonRpcTcpClient (host: string, port: uint32) = return raise - <| ServerNameResolvedToInvalidAddressException - (msg) + <| ServerNameResolvedToInvalidAddressException ( + msg + ) else return ipAddress | None -> return raise - <| ServerCannotBeResolvedException - (SPrintF1 + <| ServerCannotBeResolvedException ( + SPrintF1 "DNS host entry lookup resulted in no records for %s" - host) + host + ) | None -> return raise - <| TimeoutException - (SPrintF2 "Timed out connecting to %s:%i" host port) + <| TimeoutException ( + SPrintF2 "Timed out connecting to %s:%i" host port + ) with | :? TimeoutException -> return @@ -89,19 +92,26 @@ type JsonRpcTcpClient (host: string, port: uint32) = SocketError.TryAgain then return raise - <| ServerCannotBeResolvedException - (exceptionMsg, ex) + <| ServerCannotBeResolvedException ( + exceptionMsg, + ex + ) return raise - <| UnhandledSocketException - (socketException.ErrorCode, ex) + <| UnhandledSocketException ( + socketException.ErrorCode, + ex + ) } let rpcTcpClientInnerRequest = let tcpClient = - JsonRpcSharp.TcpClient.JsonRpcClient - (ResolveHost, int port, Config.DEFAULT_NETWORK_CONNECT_TIMEOUT) + JsonRpcSharp.TcpClient.JsonRpcClient ( + ResolveHost, + int port, + Config.DEFAULT_NETWORK_CONNECT_TIMEOUT + ) fun jsonRequest -> tcpClient.RequestAsync jsonRequest @@ -119,8 +129,9 @@ type JsonRpcTcpClient (host: string, port: uint32) = | Some s -> s | None -> raise - <| ServerTimedOutException - ("Timeout when trying to communicate with UtxoCoin server") + <| ServerTimedOutException ( + "Timeout when trying to communicate with UtxoCoin server" + ) return str with diff --git a/src/GWallet.Backend/Marshalling.fs b/src/GWallet.Backend/Marshalling.fs index 702a1326e..58ae20754 100644 --- a/src/GWallet.Backend/Marshalling.fs +++ b/src/GWallet.Backend/Marshalling.fs @@ -12,17 +12,20 @@ open GWallet.Backend.FSharpUtil.UwpHacks type DeserializationException = inherit Exception - new(message: string, innerException: Exception) = - { inherit Exception(message, innerException) } + new (message: string, innerException: Exception) = + { inherit Exception (message, innerException) } - new(message: string) = { inherit Exception(message) } + new (message: string) = { inherit Exception (message) } type SerializationException (message: string, innerException: Exception) = - inherit Exception(message, innerException) + inherit Exception (message, innerException) -type VersionMismatchDuringDeserializationException (message: string, - innerException: Exception) = - inherit DeserializationException(message, innerException) +type VersionMismatchDuringDeserializationException + ( + message: string, + innerException: Exception + ) = + inherit DeserializationException (message, innerException) module internal VersionHelper = let internal CURRENT_VERSION = @@ -46,12 +49,14 @@ type MarshallingWrapper<'T> = } type private PascalCase2LowercasePlusUnderscoreContractResolver () = - inherit DefaultContractResolver() + inherit DefaultContractResolver () // https://stackoverflow.com/a/20952003/544947 let pascalToUnderScoreRegex = - Regex - ("((?<=.)[A-Z][a-zA-Z]*)|((?<=[a-zA-Z])\d+)", RegexOptions.Multiline) + Regex ( + "((?<=.)[A-Z][a-zA-Z]*)|((?<=[a-zA-Z])\d+)", + RegexOptions.Multiline + ) let pascalToUnderScoreReplacementExpression = "_$1$2" @@ -63,15 +68,18 @@ type private PascalCase2LowercasePlusUnderscoreContractResolver () = // combine https://stackoverflow.com/a/48330214/544947 with https://stackoverflow.com/a/29660550/544947 // (because null values should map to None values in the case of Option<> types, otherwise tests fail) type RequireAllPropertiesContractResolver () = - inherit DefaultContractResolver() + inherit DefaultContractResolver () override __.CreateObjectContract (objectType: Type) = let contract = base.CreateObjectContract objectType contract.ItemRequired <- Nullable Required.Always contract - override __.CreateProperty (memberInfo: MemberInfo, - memberSerialization: MemberSerialization) = + override __.CreateProperty + ( + memberInfo: MemberInfo, + memberSerialization: MemberSerialization + ) = let property = base.CreateProperty (memberInfo, memberSerialization) // https://stackoverflow.com/questions/20696262/reflection-to-find-out-if-property-is-of-option-type let isOption = @@ -93,15 +101,17 @@ module Marshalling = #endif let internal PascalCase2LowercasePlusUnderscoreConversionSettings = - JsonSerializerSettings - (ContractResolver = - PascalCase2LowercasePlusUnderscoreContractResolver ()) + JsonSerializerSettings ( + ContractResolver = + PascalCase2LowercasePlusUnderscoreContractResolver () + ) let internal DefaultSettings = - JsonSerializerSettings - (MissingMemberHandling = MissingMemberHandling.Error, - ContractResolver = RequireAllPropertiesContractResolver (), - DateTimeZoneHandling = DateTimeZoneHandling.Utc) + JsonSerializerSettings ( + MissingMemberHandling = MissingMemberHandling.Error, + ContractResolver = RequireAllPropertiesContractResolver (), + DateTimeZoneHandling = DateTimeZoneHandling.Utc + ) let private currentVersion = VersionHelper.CURRENT_VERSION @@ -112,8 +122,11 @@ module Marshalling = Type.GetType (fullTypeName) - let DeserializeCustom<'T> (json: string, settings: JsonSerializerSettings) - : 'T = + let DeserializeCustom<'T> + ( + json: string, + settings: JsonSerializerSettings + ): 'T = if (json = null) then raise (ArgumentNullException ("json")) @@ -122,16 +135,19 @@ module Marshalling = let deserialized = try - JsonConvert.DeserializeObject> - (json, settings) + JsonConvert.DeserializeObject> ( + json, + settings + ) with ex -> let versionJsonTag = "\"Version\":\"" if (json.Contains (versionJsonTag)) then let jsonSinceVersion = - json.Substring - (json.IndexOf (versionJsonTag) - + versionJsonTag.Length) + json.Substring ( + json.IndexOf (versionJsonTag) + + versionJsonTag.Length + ) let endVersionIndex = jsonSinceVersion.IndexOf ("\"") @@ -146,52 +162,66 @@ module Marshalling = currentVersion raise - <| VersionMismatchDuringDeserializationException - (msg, ex) + <| VersionMismatchDuringDeserializationException ( + msg, + ex + ) raise - <| DeserializationException - (SPrintF1 "Exception when trying to deserialize '%s'" json, - ex) + <| DeserializationException ( + SPrintF1 "Exception when trying to deserialize '%s'" json, + ex + ) if Object.ReferenceEquals (deserialized, null) then raise - <| DeserializationException - (SPrintF1 + <| DeserializationException ( + SPrintF1 "JsonConvert.DeserializeObject returned null when trying to deserialize '%s'" - json) + json + ) if Object.ReferenceEquals (deserialized.Value, null) then raise - <| DeserializationException - (SPrintF1 + <| DeserializationException ( + SPrintF1 "JsonConvert.DeserializeObject could not deserialize the Value member of '%s'" - json) + json + ) deserialized.Value let Deserialize<'T> (json: string): 'T = DeserializeCustom (json, DefaultSettings) - let private SerializeInternal<'T> (value: 'T) - (settings: JsonSerializerSettings) - : string = - JsonConvert.SerializeObject - (MarshallingWrapper<'T>.New value, DefaultFormatting, settings) - - let SerializeCustom<'T> (value: 'T, settings: JsonSerializerSettings) - : string = + let private SerializeInternal<'T> + (value: 'T) + (settings: JsonSerializerSettings) + : string = + JsonConvert.SerializeObject ( + MarshallingWrapper<'T>.New value, + DefaultFormatting, + settings + ) + + let SerializeCustom<'T> + ( + value: 'T, + settings: JsonSerializerSettings + ): string = try SerializeInternal value settings with exn -> - raise - (SerializationException - (SPrintF2 + raise ( + SerializationException ( + SPrintF2 "Could not serialize object of type '%s' and value '%A'" (typeof<'T>.FullName) value, - exn)) + exn + ) + ) let Serialize<'T> (value: 'T): string = SerializeCustom (value, DefaultSettings) diff --git a/src/GWallet.Backend/Networking.fs b/src/GWallet.Backend/Networking.fs index 4bb950ebe..9a7c498d8 100644 --- a/src/GWallet.Backend/Networking.fs +++ b/src/GWallet.Backend/Networking.fs @@ -16,84 +16,94 @@ type CloudFlareError = type internal UnhandledSocketException = inherit Exception - new(socketErrorCode: int, innerException: Exception) = - { inherit Exception(SPrintF1 - "Backend not prepared for this SocketException with ErrorCode[%i]" - socketErrorCode, - innerException) } + new (socketErrorCode: int, innerException: Exception) = + { inherit Exception (SPrintF1 + "Backend not prepared for this SocketException with ErrorCode[%i]" + socketErrorCode, + innerException) } type CommunicationUnsuccessfulException = inherit Exception - new(message: string, innerException: Exception) = - { inherit Exception(message, innerException) } - - new(message: string) = { inherit Exception(message) } - new() = { inherit Exception() } - -type ServerDiscardedException (message: string, - innerException: CommunicationUnsuccessfulException) = - inherit Exception(message, innerException) - -type BuggyExceptionFromOldMonoVersion (message: string, - innerException: Exception) = - inherit CommunicationUnsuccessfulException(message, innerException) - -type ServerClosedConnectionEarlyException (message: string, - innerException: Exception) = - inherit CommunicationUnsuccessfulException(message, innerException) + new (message: string, innerException: Exception) = + { inherit Exception (message, innerException) } + + new (message: string) = { inherit Exception (message) } + new () = { inherit Exception () } + +type ServerDiscardedException + ( + message: string, + innerException: CommunicationUnsuccessfulException + ) = + inherit Exception (message, innerException) + +type BuggyExceptionFromOldMonoVersion + ( + message: string, + innerException: Exception + ) = + inherit CommunicationUnsuccessfulException (message, innerException) + +type ServerClosedConnectionEarlyException + ( + message: string, + innerException: Exception + ) = + inherit CommunicationUnsuccessfulException (message, innerException) type ServerRefusedException (message: string, innerException: Exception) = - inherit CommunicationUnsuccessfulException(message, innerException) + inherit CommunicationUnsuccessfulException (message, innerException) type ServerTimedOutException = inherit CommunicationUnsuccessfulException - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } - new(message) = { inherit CommunicationUnsuccessfulException(message) } + new (message) = { inherit CommunicationUnsuccessfulException (message) } type ServerUnreachableException = inherit CommunicationUnsuccessfulException - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } - - new(message: string, - httpStatusCode: HttpStatusCode, - innerException: Exception) = - { inherit CommunicationUnsuccessfulException(SPrintF2 - "%s (HttpErr: %s)" - message - (httpStatusCode.ToString - ()), - innerException) } - - new(message: string, - cloudFlareError: CloudFlareError, - innerException: Exception) = - { inherit CommunicationUnsuccessfulException(SPrintF2 - "%s (CfErr: %s)" - message - (cloudFlareError.ToString - ()), - innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } + + new (message: string, + httpStatusCode: HttpStatusCode, + innerException: Exception) = + { inherit CommunicationUnsuccessfulException (SPrintF2 + "%s (HttpErr: %s)" + message + (httpStatusCode.ToString + ()), + innerException) } + + new (message: string, + cloudFlareError: CloudFlareError, + innerException: Exception) = + { inherit CommunicationUnsuccessfulException (SPrintF2 + "%s (CfErr: %s)" + message + (cloudFlareError.ToString + ()), + innerException) } type ServerMisconfiguredException = inherit CommunicationUnsuccessfulException - new(message: string, innerException: Exception) = - { inherit CommunicationUnsuccessfulException(message, innerException) } + new (message: string, innerException: Exception) = + { inherit CommunicationUnsuccessfulException (message, innerException) } - new(message: string) = - { inherit CommunicationUnsuccessfulException(message) } + new (message: string) = + { inherit CommunicationUnsuccessfulException (message) } module Networking = - let FindExceptionToRethrow (ex: Exception) - (newExceptionMsg) - : Option = + let FindExceptionToRethrow + (ex: Exception) + (newExceptionMsg) + : Option = match FSharpUtil.FindException ex with | None -> None | Some socketException -> diff --git a/src/GWallet.Backend/Server.fs b/src/GWallet.Backend/Server.fs index 192a0606e..1ffa08ddd 100644 --- a/src/GWallet.Backend/Server.fs +++ b/src/GWallet.Backend/Server.fs @@ -79,9 +79,10 @@ module ServerRegistry = let ServersEmbeddedResourceFileName = "servers.json" - let internal TryFindValue (map: ServerRanking) - (serverPredicate: ServerDetails -> bool) - : Option = + let internal TryFindValue + (map: ServerRanking) + (serverPredicate: ServerDetails -> bool) + : Option = let rec tryFind currencyAndServers server = match currencyAndServers with | [] -> None @@ -94,9 +95,10 @@ module ServerRegistry = tryFind listMap serverPredicate let internal RemoveDupes (servers: seq) = - let rec removeDupesInternal (servers: seq) - (serversMap: Map) - = + let rec removeDupesInternal + (servers: seq) + (serversMap: Map) + = match Seq.tryHead servers with | None -> Seq.empty | Some server -> @@ -130,8 +132,9 @@ module ServerRegistry = removeDupesInternal servers initialServersMap - let internal RemoveBlackListed (cs: Currency * seq) - : seq = + let internal RemoveBlackListed + (cs: Currency * seq) + : seq = let isBlackListed currency server = // as these servers can only serve very limited set of queries (e.g. only balance?) their stats are skewed and // they create exception when being queried for advanced ones (e.g. latest block) @@ -173,9 +176,9 @@ module ServerRegistry = let rearrangedServers = servers |> Map.toSeq - |> Seq.map - (fun (currency, servers) -> - currency, ((currency, servers) |> RemoveCruft |> Sort)) + |> Seq.map (fun (currency, servers) -> + currency, ((currency, servers) |> RemoveCruft |> Sort) + ) |> Map.ofSeq Marshalling.Serialize rearrangedServers @@ -183,9 +186,10 @@ module ServerRegistry = let Deserialize (json: string): ServerRanking = Marshalling.Deserialize json - let Merge (ranking1: ServerRanking) - (ranking2: ServerRanking) - : ServerRanking = + let Merge + (ranking1: ServerRanking) + (ranking2: ServerRanking) + : ServerRanking = let allKeys = seq { for KeyValue (key, _) in ranking1 do @@ -218,9 +222,10 @@ module ServerRegistry = |> Map.ofSeq let private ServersRankingBaseline = - Deserialize - (Config.ExtractEmbeddedResourceFileContents - ServersEmbeddedResourceFileName) + Deserialize ( + Config.ExtractEmbeddedResourceFileContents + ServersEmbeddedResourceFileName + ) let MergeWithBaseline (ranking: ServerRanking): ServerRanking = Merge ranking ServersRankingBaseline diff --git a/src/GWallet.Backend/ServerManager.fs b/src/GWallet.Backend/ServerManager.fs index b92afbd57..04a37e2d2 100644 --- a/src/GWallet.Backend/ServerManager.fs +++ b/src/GWallet.Backend/ServerManager.fs @@ -16,8 +16,9 @@ module ServerManager = ServerRegistry.ServersEmbeddedResourceFileName |> ServerRegistry.Deserialize - let fromElectrumServerToGenericServerDetails (es: UtxoCoin.ElectrumServer) - = + let fromElectrumServerToGenericServerDetails + (es: UtxoCoin.ElectrumServer) + = match es.UnencryptedPort with | None -> failwith "filtering for non-ssl electrum servers didn't work?" @@ -78,33 +79,38 @@ module ServerManager = |> Seq.append baseLineLtcServers for KeyValue (currency, servers) in baseLineServers do - Infrastructure.LogInfo - (SPrintF2 + Infrastructure.LogInfo ( + SPrintF2 "%i %A servers from baseline JSON file" (servers.Count ()) - currency) + currency + ) match currency with | Currency.BTC -> - Infrastructure.LogInfo - (SPrintF1 + Infrastructure.LogInfo ( + SPrintF1 "%i BTC servers from electrum repository" - (electrumBtcServers.Count ())) + (electrumBtcServers.Count ()) + ) - Infrastructure.LogInfo - (SPrintF1 + Infrastructure.LogInfo ( + SPrintF1 "%i BTC servers from bitcoin-eye" - (eyeBtcServers.Count ())) + (eyeBtcServers.Count ()) + ) | Currency.LTC -> - Infrastructure.LogInfo - (SPrintF1 + Infrastructure.LogInfo ( + SPrintF1 "%i LTC servers from electrum repository" - (electrumLtcServers.Count ())) + (electrumLtcServers.Count ()) + ) - Infrastructure.LogInfo - (SPrintF1 + Infrastructure.LogInfo ( + SPrintF1 "%i LTC servers from bitcoin-eye" - (eyeLtcServers.Count ())) + (eyeLtcServers.Count ()) + ) | _ -> () let allCurrenciesServers = @@ -114,15 +120,18 @@ module ServerManager = let allServersJson = ServerRegistry.Serialize allCurrenciesServers - File.WriteAllText - (ServerRegistry.ServersEmbeddedResourceFileName, allServersJson) + File.WriteAllText ( + ServerRegistry.ServersEmbeddedResourceFileName, + allServersJson + ) Infrastructure.LogInfo "OUTPUT:" let filteredOutServers = ServerRegistry.Deserialize allServersJson for KeyValue (currency, servers) in filteredOutServers do - Infrastructure.LogInfo - (SPrintF2 "%i %A servers total" (servers.Count ()) currency) + Infrastructure.LogInfo ( + SPrintF2 "%i %A servers total" (servers.Count ()) currency + ) let private tester = FaultTolerantParallelClient @@ -184,9 +193,10 @@ module ServerManager = let web3Func (web3: Ether.SomeWeb3): Async = async { let! balance = - Async.AwaitTask - (web3.Eth.GetBalance.SendRequestAsync - ETH_GENESISBLOCK_ADDRESS) + Async.AwaitTask ( + web3.Eth.GetBalance.SendRequestAsync + ETH_GENESISBLOCK_ADDRESS + ) return balance.Value |> decimal } @@ -213,8 +223,10 @@ module ServerManager = match Caching.Instance.ExportServers () with | None -> failwith "After updating servers, cache should not be empty" | Some serversInJson -> - File.WriteAllText - (ServerRegistry.ServersEmbeddedResourceFileName, serversInJson) + File.WriteAllText ( + ServerRegistry.ServersEmbeddedResourceFileName, + serversInJson + ) let UpdateServersStats () = let jobs = diff --git a/src/GWallet.Backend/Shuffler.fs b/src/GWallet.Backend/Shuffler.fs index 038be64e1..04ee867ee 100644 --- a/src/GWallet.Backend/Shuffler.fs +++ b/src/GWallet.Backend/Shuffler.fs @@ -9,19 +9,22 @@ module Shuffler = let Unsort aSeq = aSeq |> Seq.sortBy (fun _ -> random.Next ()) - let private ListRemove<'T when 'T: equality> (list: List<'T>) - (elementToRemove: 'T) - = + let private ListRemove<'T when 'T: equality> + (list: List<'T>) + (elementToRemove: 'T) + = List.filter (fun element -> element <> elementToRemove) list - let RandomizeEveryNthElement<'T when 'T: equality> (list: List<'T>) - (offset: uint32) - = - let rec RandomizeInternal (list: List<'T>) - (offset: uint32) - acc - (currentIndex: uint32) - = + let RandomizeEveryNthElement<'T when 'T: equality> + (list: List<'T>) + (offset: uint32) + = + let rec RandomizeInternal + (list: List<'T>) + (offset: uint32) + acc + (currentIndex: uint32) + = match list with | [] -> List.rev acc | head :: tail -> diff --git a/src/GWallet.Backend/TransferAmount.fs b/src/GWallet.Backend/TransferAmount.fs index 2fdc92fc2..212e7841b 100644 --- a/src/GWallet.Backend/TransferAmount.fs +++ b/src/GWallet.Backend/TransferAmount.fs @@ -2,9 +2,12 @@ open System -type TransferAmount (valueToSend: decimal, - balanceAtTheMomentOfSending: decimal, - currency: Currency) = +type TransferAmount + ( + valueToSend: decimal, + balanceAtTheMomentOfSending: decimal, + currency: Currency + ) = do if valueToSend <= 0m then invalidArg "valueToSend" "Amount has to be above zero" diff --git a/src/GWallet.Backend/UtxoCoin/ElectrumClient.fs b/src/GWallet.Backend/UtxoCoin/ElectrumClient.fs index 04b013862..ff7013e51 100644 --- a/src/GWallet.Backend/UtxoCoin/ElectrumClient.fs +++ b/src/GWallet.Backend/UtxoCoin/ElectrumClient.fs @@ -8,8 +8,8 @@ open GWallet.Backend.FSharpUtil.UwpHacks module ElectrumClient = let private Init (fqdn: string) (port: uint32): Async = - let jsonRpcClient = new JsonRpcTcpClient(fqdn, port) - let stratumClient = new StratumClient(jsonRpcClient) + let jsonRpcClient = new JsonRpcTcpClient (fqdn, port) + let stratumClient = new StratumClient (jsonRpcClient) // this is the last version of Electrum released at the time of writing this module let CLIENT_NAME_SENT_TO_STRATUM_SERVER_WHEN_HELLO = "geewallet" @@ -32,25 +32,29 @@ module ElectrumClient = with :? ElectrumServerReturningErrorException as ex -> if (ex.ErrorCode = 1 && ex.Message.StartsWith "unsupported protocol version" - && ex.Message.EndsWith - (PROTOCOL_VERSION_SUPPORTED.ToString ())) then + && ex.Message.EndsWith ( + PROTOCOL_VERSION_SUPPORTED.ToString () + )) then // FIXME: even if this ex is already handled to ignore the server, we should report to sentry as WARN raise - <| ServerTooNewException - (SPrintF1 + <| ServerTooNewException ( + SPrintF1 "Version of server rejects our client version (%s)" - (PROTOCOL_VERSION_SUPPORTED.ToString ())) + (PROTOCOL_VERSION_SUPPORTED.ToString ()) + ) else reraise () if versionSupportedByServer < PROTOCOL_VERSION_SUPPORTED then - raise - (ServerTooOldException - (SPrintF2 + raise ( + ServerTooOldException ( + SPrintF2 "Version of server is older (%s) than the client (%s)" (versionSupportedByServer.ToString ()) - (PROTOCOL_VERSION_SUPPORTED.ToString ()))) + (PROTOCOL_VERSION_SUPPORTED.ToString ()) + ) + ) return stratumClient } @@ -90,9 +94,10 @@ module ElectrumClient = return balanceResult.Result } - let GetUnspentTransactionOutputs scriptHash - (stratumServer: Async) - = + let GetUnspentTransactionOutputs + scriptHash + (stratumServer: Async) + = async { let! stratumClient = stratumServer @@ -112,9 +117,10 @@ module ElectrumClient = return blockchainTransactionResult.Result } - let EstimateFee (numBlocksTarget: int) - (stratumServer: Async) - : Async = + let EstimateFee + (numBlocksTarget: int) + (stratumServer: Async) + : Async = async { let! stratumClient = stratumServer @@ -124,15 +130,17 @@ module ElectrumClient = if estimateFeeResult.Result = -1m then return raise - <| ServerMisconfiguredException - ("Fee estimation returned a -1 error code") + <| ServerMisconfiguredException ( + "Fee estimation returned a -1 error code" + ) elif estimateFeeResult.Result <= 0m then return raise - <| ServerMisconfiguredException - (SPrintF1 + <| ServerMisconfiguredException ( + SPrintF1 "Fee estimation returned an invalid non-positive value %M" - estimateFeeResult.Result) + estimateFeeResult.Result + ) @@ -140,9 +148,10 @@ module ElectrumClient = return estimateFeeResult.Result } - let BroadcastTransaction (transactionInHex: string) - (stratumServer: Async) - = + let BroadcastTransaction + (transactionInHex: string) + (stratumServer: Async) + = async { let! stratumClient = stratumServer diff --git a/src/GWallet.Backend/UtxoCoin/ElectrumServer.fs b/src/GWallet.Backend/UtxoCoin/ElectrumServer.fs index cd34289b4..b4d9b554c 100644 --- a/src/GWallet.Backend/UtxoCoin/ElectrumServer.fs +++ b/src/GWallet.Backend/UtxoCoin/ElectrumServer.fs @@ -11,22 +11,22 @@ open GWallet.Backend open GWallet.Backend.FSharpUtil.UwpHacks type IncompatibleServerException (message) = - inherit CommunicationUnsuccessfulException(message) + inherit CommunicationUnsuccessfulException (message) type IncompatibleProtocolException (message) = - inherit IncompatibleServerException(message) + inherit IncompatibleServerException (message) type ServerTooNewException (message) = - inherit IncompatibleProtocolException(message) + inherit IncompatibleProtocolException (message) type ServerTooOldException (message) = - inherit IncompatibleProtocolException(message) + inherit IncompatibleProtocolException (message) type TlsNotSupportedYetInGWalletException (message) = - inherit IncompatibleServerException(message) + inherit IncompatibleServerException (message) type TorNotSupportedYetInGWalletException (message) = - inherit IncompatibleServerException(message) + inherit IncompatibleServerException (message) type ElectrumServer = { @@ -37,13 +37,16 @@ type ElectrumServer = member self.CheckCompatibility (): unit = if self.UnencryptedPort.IsNone then - raise - (TlsNotSupportedYetInGWalletException ("TLS not yet supported")) + raise ( + TlsNotSupportedYetInGWalletException ("TLS not yet supported") + ) if self.Fqdn.EndsWith ".onion" then - raise - (TorNotSupportedYetInGWalletException - ("Tor(onion) not yet supported")) + raise ( + TorNotSupportedYetInGWalletException ( + "Tor(onion) not yet supported" + ) + ) module ElectrumServerSeedList = @@ -74,7 +77,7 @@ module ElectrumServerSeedList = let web = HtmlWeb () let doc = web.Load url - let firstTable = (doc.DocumentNode.SelectNodes"//table").[0] + let firstTable = (doc.DocumentNode.SelectNodes "//table").[0] let tableBody = firstTable.SelectSingleNode "tbody" let servers = tableBody.SelectNodes "tr" @@ -184,7 +187,7 @@ module ElectrumServerSeedList = "UTXO currency unknown to this algorithm: %A" currency - use webClient = new WebClient() + use webClient = new WebClient () let serverListInJson = webClient.DownloadString urlToElectrumJsonFile ExtractServerListFromElectrumJsonFile serverListInJson diff --git a/src/GWallet.Backend/UtxoCoin/StratumClient.fs b/src/GWallet.Backend/UtxoCoin/StratumClient.fs index fe7c8368d..e548d480c 100644 --- a/src/GWallet.Backend/UtxoCoin/StratumClient.fs +++ b/src/GWallet.Backend/UtxoCoin/StratumClient.fs @@ -90,38 +90,48 @@ type RpcErrorCode = // see https://gitlab.gnome.org/World/geewallet/issues/112 | UnknownMethod = -32601 -type public ElectrumServerReturningErrorInJsonResponseException (message: string, - code: int) = - inherit CommunicationUnsuccessfulException(message) +type public ElectrumServerReturningErrorInJsonResponseException + ( + message: string, + code: int + ) = + inherit CommunicationUnsuccessfulException (message) member val ErrorCode: int = code -type public ElectrumServerReturningErrorException (message: string, - code: int, - originalRequest: string, - originalResponse: string) = - inherit ElectrumServerReturningErrorInJsonResponseException(message, code) +type public ElectrumServerReturningErrorException + ( + message: string, + code: int, + originalRequest: string, + originalResponse: string + ) = + inherit ElectrumServerReturningErrorInJsonResponseException (message, code) member val OriginalRequest: string = originalRequest member val OriginalResponse: string = originalResponse -type public ElectrumServerReturningInternalErrorException (message: string, - code: int, - originalRequest: string, - originalResponse: string) = - inherit ElectrumServerReturningErrorException(message, - code, - originalRequest, - originalResponse) +type public ElectrumServerReturningInternalErrorException + ( + message: string, + code: int, + originalRequest: string, + originalResponse: string + ) = + inherit ElectrumServerReturningErrorException (message, + code, + originalRequest, + originalResponse) type StratumClient (jsonRpcClient: JsonRpcTcpClient) = let Serialize (req: Request): string = - JsonConvert.SerializeObject - (req, - Formatting.None, - Marshalling.PascalCase2LowercasePlusUnderscoreConversionSettings) + JsonConvert.SerializeObject ( + req, + Formatting.None, + Marshalling.PascalCase2LowercasePlusUnderscoreConversionSettings + ) // TODO: add 'T as incoming request type, leave 'R as outgoing response type member private self.Request<'R> (jsonRequest: string): Async<'R * string> = @@ -132,23 +142,26 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = if String.IsNullOrEmpty rawResponse then return raise - <| ProtocolGlitchException - (SPrintF2 + <| ProtocolGlitchException ( + SPrintF2 "Server '%s' returned a null/empty JSON response to the request '%s'??" jsonRpcClient.Host - jsonRequest) + jsonRequest + ) try return (StratumClient.Deserialize<'R> rawResponse, rawResponse) with :? ElectrumServerReturningErrorInJsonResponseException as ex -> if ex.ErrorCode = int RpcErrorCode.InternalError then return - raise - (ElectrumServerReturningInternalErrorException - (ex.Message, - ex.ErrorCode, - jsonRequest, - rawResponse)) + raise ( + ElectrumServerReturningInternalErrorException ( + ex.Message, + ex.ErrorCode, + jsonRequest, + rawResponse + ) + ) if ex.ErrorCode = int RpcErrorCode.UnknownMethod then return @@ -163,9 +176,14 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = raise <| ServerUnavailabilityException (ex.Message, ex) return - raise - (ElectrumServerReturningErrorException - (ex.Message, ex.ErrorCode, jsonRequest, rawResponse)) + raise ( + ElectrumServerReturningErrorException ( + ex.Message, + ex.ErrorCode, + jsonRequest, + rawResponse + ) + ) } static member public Deserialize<'T> (result: string): 'T = @@ -173,37 +191,44 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = let maybeError = try - JsonConvert.DeserializeObject - (resultTrimmed, - Marshalling.PascalCase2LowercasePlusUnderscoreConversionSettings) + JsonConvert.DeserializeObject ( + resultTrimmed, + Marshalling.PascalCase2LowercasePlusUnderscoreConversionSettings + ) with ex -> raise - <| Exception - (SPrintF2 + <| Exception ( + SPrintF2 "Failed deserializing JSON response (to check for error) '%s' to type '%s'" resultTrimmed typedefof<'T>.FullName, - ex) + ex + ) if (not (Object.ReferenceEquals (maybeError, null))) && (not (Object.ReferenceEquals (maybeError.Error, null))) then - raise - (ElectrumServerReturningErrorInJsonResponseException - (maybeError.Error.Message, maybeError.Error.Code)) + raise ( + ElectrumServerReturningErrorInJsonResponseException ( + maybeError.Error.Message, + maybeError.Error.Code + ) + ) let deserializedValue = try - JsonConvert.DeserializeObject<'T> - (resultTrimmed, - Marshalling.PascalCase2LowercasePlusUnderscoreConversionSettings) + JsonConvert.DeserializeObject<'T> ( + resultTrimmed, + Marshalling.PascalCase2LowercasePlusUnderscoreConversionSettings + ) with ex -> raise - <| Exception - (SPrintF2 + <| Exception ( + SPrintF2 "Failed deserializing JSON response '%s' to type '%s'" resultTrimmed typedefof<'T>.FullName, - ex) + ex + ) if Object.ReferenceEquals (deserializedValue, null) then failwith @@ -214,8 +239,9 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = deserializedValue - member self.BlockchainScriptHashGetBalance address - : Async = + member self.BlockchainScriptHashGetBalance + address + : Async = let obj = { Id = 0 @@ -242,14 +268,18 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = try Version (correctedVersion) with exn -> - raise - (Exception - ("Electrum Server's version disliked by .NET Version class: " - + versionStr, - exn)) - - member self.ServerVersion (clientName: string) (protocolVersion: Version) - : Async = + raise ( + Exception ( + "Electrum Server's version disliked by .NET Version class: " + + versionStr, + exn + ) + ) + + member self.ServerVersion + (clientName: string) + (protocolVersion: Version) + : Async = async { let obj = { @@ -284,8 +314,9 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = return StratumClient.CreateVersion (serverProtocolVersion) } - member self.BlockchainScriptHashListUnspent address - : Async = + member self.BlockchainScriptHashListUnspent + address + : Async = let obj = { Id = 0 @@ -302,8 +333,9 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = return resObj } - member self.BlockchainTransactionGet txHash - : Async = + member self.BlockchainTransactionGet + txHash + : Async = let obj = { Id = 0 @@ -318,8 +350,9 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = return resObj } - member self.BlockchainEstimateFee (numBlocksTarget: int) - : Async = + member self.BlockchainEstimateFee + (numBlocksTarget: int) + : Async = let obj = { Id = 0 @@ -334,8 +367,9 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = return resObj } - member self.BlockchainTransactionBroadcast txInHex - : Async = + member self.BlockchainTransactionBroadcast + txInHex + : Async = let obj = { Id = 0 diff --git a/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs b/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs index c2b82f335..f56b98f90 100644 --- a/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs +++ b/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs @@ -27,35 +27,44 @@ type internal IUtxoAccount = abstract PublicKey: PubKey -type NormalUtxoAccount (currency: Currency, - accountFile: FileRepresentation, - fromAccountFileToPublicAddress: FileRepresentation -> string, - fromAccountFileToPublicKey: FileRepresentation -> PubKey) = - inherit GWallet.Backend.NormalAccount(currency, - accountFile, - fromAccountFileToPublicAddress) +type NormalUtxoAccount + ( + currency: Currency, + accountFile: FileRepresentation, + fromAccountFileToPublicAddress: FileRepresentation -> string, + fromAccountFileToPublicKey: FileRepresentation -> PubKey + ) = + inherit GWallet.Backend.NormalAccount (currency, + accountFile, + fromAccountFileToPublicAddress) interface IUtxoAccount with member val PublicKey = fromAccountFileToPublicKey accountFile -type ReadOnlyUtxoAccount (currency: Currency, - accountFile: FileRepresentation, - fromAccountFileToPublicAddress: FileRepresentation -> string, - fromAccountFileToPublicKey: FileRepresentation -> PubKey) = - inherit GWallet.Backend.ReadOnlyAccount(currency, - accountFile, - fromAccountFileToPublicAddress) +type ReadOnlyUtxoAccount + ( + currency: Currency, + accountFile: FileRepresentation, + fromAccountFileToPublicAddress: FileRepresentation -> string, + fromAccountFileToPublicKey: FileRepresentation -> PubKey + ) = + inherit GWallet.Backend.ReadOnlyAccount (currency, + accountFile, + fromAccountFileToPublicAddress) interface IUtxoAccount with member val PublicKey = fromAccountFileToPublicKey accountFile -type ArchivedUtxoAccount (currency: Currency, - accountFile: FileRepresentation, - fromAccountFileToPublicAddress: FileRepresentation -> string, - fromAccountFileToPublicKey: FileRepresentation -> PubKey) = - inherit GWallet.Backend.ArchivedAccount(currency, - accountFile, - fromAccountFileToPublicAddress) +type ArchivedUtxoAccount + ( + currency: Currency, + accountFile: FileRepresentation, + fromAccountFileToPublicAddress: FileRepresentation -> string, + fromAccountFileToPublicKey: FileRepresentation -> PubKey + ) = + inherit GWallet.Backend.ArchivedAccount (currency, + accountFile, + fromAccountFileToPublicAddress) interface IUtxoAccount with member val PublicKey = fromAccountFileToPublicKey accountFile @@ -79,17 +88,19 @@ module Account = currency // technique taken from https://electrumx.readthedocs.io/en/latest/protocol-basics.html#script-hashes - let private GetElectrumScriptHashFromAddress (address: BitcoinAddress) - : string = + let private GetElectrumScriptHashFromAddress + (address: BitcoinAddress) + : string = let sha = NBitcoin.Crypto.Hashes.SHA256 (address.ScriptPubKey.ToBytes ()) let reversedSha = sha.Reverse().ToArray() NBitcoin.DataEncoders.Encoders.Hex.EncodeData reversedSha - let public GetElectrumScriptHashFromPublicAddress currency - (publicAddress: string) - = + let public GetElectrumScriptHashFromPublicAddress + currency + (publicAddress: string) + = // TODO: measure how long does it take to get the script hash and if it's too long, cache it at app startup? BitcoinAddress.Create (publicAddress, GetNetwork currency) |> GetElectrumScriptHashFromAddress @@ -99,30 +110,35 @@ module Account = .GetScriptAddress() .ToString() - let internal GetPublicAddressFromNormalAccountFile (currency: Currency) - (accountFile: FileRepresentation) - : string = + let internal GetPublicAddressFromNormalAccountFile + (currency: Currency) + (accountFile: FileRepresentation) + : string = let pubKey = PubKey (accountFile.Name) GetPublicAddressFromPublicKey currency pubKey - let internal GetPublicKeyFromNormalAccountFile (accountFile: FileRepresentation) - : PubKey = + let internal GetPublicKeyFromNormalAccountFile + (accountFile: FileRepresentation) + : PubKey = PubKey accountFile.Name - let internal GetPublicKeyFromReadOnlyAccountFile (accountFile: FileRepresentation) - : PubKey = + let internal GetPublicKeyFromReadOnlyAccountFile + (accountFile: FileRepresentation) + : PubKey = accountFile.Content () |> PubKey - let internal GetPublicAddressFromUnencryptedPrivateKey (currency: Currency) - (privateKey: string) - = + let internal GetPublicAddressFromUnencryptedPrivateKey + (currency: Currency) + (privateKey: string) + = let privateKey = Key.Parse (privateKey, GetNetwork currency) GetPublicAddressFromPublicKey currency privateKey.PubKey - let internal GetAccountFromFile (accountFile: FileRepresentation) - (currency: Currency) - kind - : IAccount = + let internal GetAccountFromFile + (accountFile: FileRepresentation) + (currency: Currency) + kind + : IAccount = if not (currency.IsUtxo ()) then failwith <| SPrintF1 @@ -131,11 +147,12 @@ module Account = match kind with | AccountKind.ReadOnly -> - ReadOnlyUtxoAccount - (currency, - accountFile, - (fun accountFile -> accountFile.Name), - GetPublicKeyFromReadOnlyAccountFile) + ReadOnlyUtxoAccount ( + currency, + accountFile, + (fun accountFile -> accountFile.Name), + GetPublicKeyFromReadOnlyAccountFile + ) :> IAccount | AccountKind.Normal -> let fromAccountFileToPublicAddress = @@ -143,16 +160,18 @@ module Account = let fromAccountFileToPublicKey = GetPublicKeyFromNormalAccountFile - NormalUtxoAccount - (currency, - accountFile, - fromAccountFileToPublicAddress, - fromAccountFileToPublicKey) + NormalUtxoAccount ( + currency, + accountFile, + fromAccountFileToPublicAddress, + fromAccountFileToPublicKey + ) :> IAccount | _ -> failwith <| SPrintF1 "Kind (%A) not supported for this API" kind - let private BalanceToShow (balances: BlockchainScriptHashGetBalanceInnerResult) - = + let private BalanceToShow + (balances: BlockchainScriptHashGetBalanceInnerResult) + = let unconfirmedPlusConfirmed = balances.Unconfirmed + balances.Confirmed let amountToShowInSatoshis = @@ -166,10 +185,11 @@ module Account = amountInBtc - let private BalanceMatchWithCacheOrInitialBalance address - currency - (someRetrievedBalance: BlockchainScriptHashGetBalanceInnerResult) - : bool = + let private BalanceMatchWithCacheOrInitialBalance + address + currency + (someRetrievedBalance: BlockchainScriptHashGetBalanceInnerResult) + : bool = if Caching.Instance.FirstRun then BalanceToShow someRetrievedBalance = 0m else @@ -179,21 +199,23 @@ module Account = | None -> false | Some balance -> BalanceToShow someRetrievedBalance = balance - let private GetBalances (account: IUtxoAccount) - (mode: ServerSelectionMode) - (cancelSourceOption: Option) - : Async = + let private GetBalances + (account: IUtxoAccount) + (mode: ServerSelectionMode) + (cancelSourceOption: Option) + : Async = let scriptHashHex = GetElectrumScriptHashFromPublicAddress account.Currency account.PublicAddress let querySettings = - QuerySettings.Balance - (mode, - (BalanceMatchWithCacheOrInitialBalance - account.PublicAddress - account.Currency)) + QuerySettings.Balance ( + mode, + (BalanceMatchWithCacheOrInitialBalance + account.PublicAddress + account.Currency) + ) let balanceJob = ElectrumClient.GetBalance scriptHashHex @@ -203,23 +225,25 @@ module Account = balanceJob cancelSourceOption - let private GetBalancesFromServer (account: IUtxoAccount) - (mode: ServerSelectionMode) - (cancelSourceOption: Option) - : Async> = + let private GetBalancesFromServer + (account: IUtxoAccount) + (mode: ServerSelectionMode) + (cancelSourceOption: Option) + : Async> = async { try let! balances = GetBalances account mode cancelSourceOption return Some balances - with ex when (FSharpUtil.FindException - ex) - .IsSome -> return None + with ex when + (FSharpUtil.FindException ex) + .IsSome -> return None } - let internal GetShowableBalance (account: IUtxoAccount) - (mode: ServerSelectionMode) - (cancelSourceOption: Option) - : Async> = + let internal GetShowableBalance + (account: IUtxoAccount) + (mode: ServerSelectionMode) + (cancelSourceOption: Option) + : Async> = async { let! maybeBalances = GetBalancesFromServer account mode cancelSourceOption @@ -229,9 +253,10 @@ module Account = | None -> return None } - let private ConvertToICoin (account: IUtxoAccount) - (inputOutpointInfo: TransactionInputOutpointInfo) - : ICoin = + let private ConvertToICoin + (account: IUtxoAccount) + (inputOutpointInfo: TransactionInputOutpointInfo) + : ICoin = let txHash = uint256 inputOutpointInfo.TransactionHash let scriptPubKeyInBytes = @@ -241,19 +266,21 @@ module Account = let scriptPubKey = Script (scriptPubKeyInBytes) let coin = - Coin - (txHash, - uint32 inputOutpointInfo.OutputIndex, - Money (inputOutpointInfo.ValueInSatoshis), - scriptPubKey) + Coin ( + txHash, + uint32 inputOutpointInfo.OutputIndex, + Money (inputOutpointInfo.ValueInSatoshis), + scriptPubKey + ) coin.ToScriptCoin account.PublicKey.WitHash.ScriptPubKey :> ICoin - let private CreateTransactionAndCoinsToBeSigned (account: IUtxoAccount) - (transactionInputs: List) - (destination: string) - (amount: TransferAmount) - : TransactionBuilder = + let private CreateTransactionAndCoinsToBeSigned + (account: IUtxoAccount) + (transactionInputs: List) + (destination: string) + (amount: TransferAmount) + : TransactionBuilder = let coins = List.map (ConvertToICoin account) transactionInputs let transactionBuilder = @@ -292,9 +319,10 @@ module Account = Value: Int64 } - let private ConvertToInputOutpointInfo currency - (utxo: UnspentTransactionOutputInfo) - : Async = + let private ConvertToInputOutpointInfo + currency + (utxo: UnspentTransactionOutputInfo) + : Async = async { let job = ElectrumClient.GetBlockchainTransaction utxo.TransactionId @@ -321,12 +349,13 @@ module Account = return ret } - let rec private EstimateFees (txBuilder: TransactionBuilder) - (feeRate: FeeRate) - (account: IUtxoAccount) - (usedInputsSoFar: List) - (unusedUtxos: List) - : Async> = + let rec private EstimateFees + (txBuilder: TransactionBuilder) + (feeRate: FeeRate) + (account: IUtxoAccount) + (usedInputsSoFar: List) + (unusedUtxos: List) + : Async> = async { try let fees = txBuilder.EstimateFees feeRate @@ -348,16 +377,18 @@ module Account = EstimateFees newTxBuilder feeRate account newInputs tail } - let internal EstimateFee (account: IUtxoAccount) - (amount: TransferAmount) - (destination: string) - : Async = + let internal EstimateFee + (account: IUtxoAccount) + (amount: TransferAmount) + (destination: string) + : Async = async { - let rec addInputsUntilAmount (utxos: List) - soFarInSatoshis - amount - (acc: List) - : List * List = + let rec addInputsUntilAmount + (utxos: List) + soFarInSatoshis + amount + (acc: List) + : List * List = match utxos with | [] -> // should `raise InsufficientFunds` instead? @@ -461,11 +492,12 @@ module Account = with ex -> // we need more info in case this bug shows again: https://gitlab.com/knocte/geewallet/issues/43 raise - <| Exception - (SPrintF1 + <| Exception ( + SPrintF1 "Could not create fee rate from %s btc per KB" (btcPerKiloByteForFastTrans.ToString ()), - ex) + ex + ) let transactionBuilder = CreateTransactionAndCoinsToBeSigned @@ -486,10 +518,11 @@ module Account = let estimatedMinerFeeInSatoshis = estimatedMinerFee.Satoshi let minerFee = - MinerFee - (estimatedMinerFeeInSatoshis, - DateTime.UtcNow, - account.Currency) + MinerFee ( + estimatedMinerFeeInSatoshis, + DateTime.UtcNow, + account.Currency + ) return { @@ -500,12 +533,13 @@ module Account = return raise <| InsufficientBalanceForFee None } - let private SignTransactionWithPrivateKey (account: IUtxoAccount) - (txMetadata: TransactionMetadata) - (destination: string) - (amount: TransferAmount) - (privateKey: Key) - = + let private SignTransactionWithPrivateKey + (account: IUtxoAccount) + (txMetadata: TransactionMetadata) + (destination: string) + (amount: TransferAmount) + (privateKey: Key) + = let btcMinerFee = txMetadata.Fee @@ -518,8 +552,9 @@ module Account = finalTransactionBuilder.AddKeys privateKey |> ignore - finalTransactionBuilder.SendFees - (Money.Satoshis (btcMinerFee.EstimatedFeeInSatoshis)) + finalTransactionBuilder.SendFees ( + Money.Satoshis (btcMinerFee.EstimatedFeeInSatoshis) + ) |> ignore let finalTransaction = finalTransactionBuilder.BuildTransaction true @@ -540,19 +575,22 @@ module Account = let encryptedPrivateKey = account.GetEncryptedPrivateKey () let encryptedSecret = - BitcoinEncryptedSecretNoEC - (encryptedPrivateKey, GetNetwork (account :> IAccount).Currency) + BitcoinEncryptedSecretNoEC ( + encryptedPrivateKey, + GetNetwork (account :> IAccount).Currency + ) try encryptedSecret.GetKey (password) with :? SecurityException -> raise (InvalidPassword) - let internal SignTransaction (account: NormalUtxoAccount) - (txMetadata: TransactionMetadata) - (destination: string) - (amount: TransferAmount) - (password: string) - = + let internal SignTransaction + (account: NormalUtxoAccount) + (txMetadata: TransactionMetadata) + (destination: string) + (amount: TransferAmount) + (password: string) + = let privateKey = GetPrivateKey account password @@ -567,34 +605,40 @@ module Account = let rawTransaction = signedTransaction.ToHex () rawTransaction - let internal CheckValidPassword (account: NormalAccount) - (password: string) - = + let internal CheckValidPassword + (account: NormalAccount) + (password: string) + = GetPrivateKey account password |> ignore - let private BroadcastRawTransaction currency - (rawTx: string) - : Async = + let private BroadcastRawTransaction + currency + (rawTx: string) + : Async = let job = ElectrumClient.BroadcastTransaction rawTx Server.Query currency QuerySettings.Broadcast job None - let internal BroadcastTransaction currency - (transaction: SignedTransaction<_>) - = + let internal BroadcastTransaction + currency + (transaction: SignedTransaction<_>) + = // FIXME: stop embedding TransactionInfo element in SignedTransaction // and show the info from the RawTx, using NBitcoin to extract it BroadcastRawTransaction currency transaction.RawTransaction - let internal SendPayment (account: NormalUtxoAccount) - (txMetadata: TransactionMetadata) - (destination: string) - (amount: TransferAmount) - (password: string) - = + let internal SendPayment + (account: NormalUtxoAccount) + (txMetadata: TransactionMetadata) + (destination: string) + (amount: TransferAmount) + (password: string) + = let baseAccount = account :> IAccount - if (baseAccount.PublicAddress.Equals - (destination, StringComparison.InvariantCultureIgnoreCase)) then + if (baseAccount.PublicAddress.Equals ( + destination, + StringComparison.InvariantCultureIgnoreCase + )) then raise DestinationEqualToOrigin let finalTransaction = @@ -606,10 +650,11 @@ module Account = let public ExportUnsignedTransactionToJson trans = Marshalling.Serialize trans - let internal SaveUnsignedTransaction (transProposal: UnsignedTransactionProposal) - (txMetadata: TransactionMetadata) - (readOnlyAccounts: seq) - : string = + let internal SaveUnsignedTransaction + (transProposal: UnsignedTransactionProposal) + (txMetadata: TransactionMetadata) + (readOnlyAccounts: seq) + : string = let unsignedTransaction = { @@ -623,11 +668,12 @@ module Account = ExportUnsignedTransactionToJson unsignedTransaction - let internal SweepArchivedFunds (account: ArchivedUtxoAccount) - (balance: decimal) - (destination: IAccount) - (txMetadata: TransactionMetadata) - = + let internal SweepArchivedFunds + (account: ArchivedUtxoAccount) + (balance: decimal) + (destination: IAccount) + (txMetadata: TransactionMetadata) + = let currency = (account :> IAccount).Currency let network = GetNetwork currency let amount = TransferAmount (balance, balance, currency) @@ -645,10 +691,11 @@ module Account = BroadcastRawTransaction currency (signedTrans.ToHex ()) - let internal Create currency - (password: string) - (seed: array) - : Async = + let internal Create + currency + (password: string) + (seed: array) + : Async = async { let privKey = Key seed let network = GetNetwork currency @@ -694,9 +741,11 @@ module Account = ] | _ -> failwith <| SPrintF1 "Unknown UTXO currency %A" currency - if not - (utxoCoinValidAddressPrefixes.Any - (fun prefix -> address.StartsWith prefix)) then + if (not ( + utxoCoinValidAddressPrefixes.Any (fun prefix -> + address.StartsWith prefix + ) + )) then raise (AddressMissingProperPrefix (utxoCoinValidAddressPrefixes)) let minLength, lenghtInBetweenAllowed, maxLength = diff --git a/src/GWallet.Backend/UtxoCoin/UtxoCoinMinerFee.fs b/src/GWallet.Backend/UtxoCoin/UtxoCoinMinerFee.fs index 70003f71b..538d57fbc 100644 --- a/src/GWallet.Backend/UtxoCoin/UtxoCoinMinerFee.fs +++ b/src/GWallet.Backend/UtxoCoin/UtxoCoinMinerFee.fs @@ -5,9 +5,12 @@ open System open GWallet.Backend //FIXME: convert to record? -type MinerFee (estimatedFeeInSatoshis: int64, - estimationTime: DateTime, - currency: Currency) = +type MinerFee + ( + estimatedFeeInSatoshis: int64, + estimationTime: DateTime, + currency: Currency + ) = member val EstimatedFeeInSatoshis = estimatedFeeInSatoshis diff --git a/src/GWallet.Backend/UtxoCoin/UtxoCoinServer.fs b/src/GWallet.Backend/UtxoCoin/UtxoCoinServer.fs index 479c8157f..16bb1260e 100644 --- a/src/GWallet.Backend/UtxoCoin/UtxoCoinServer.fs +++ b/src/GWallet.Backend/UtxoCoin/UtxoCoinServer.fs @@ -21,9 +21,10 @@ module Server = | ServerSelectionMode.Fast -> 3u | ServerSelectionMode.Analysis -> 2u - let private FaultTolerantParallelClientDefaultSettings (mode: ServerSelectionMode) - maybeConsistencyConfig - = + let private FaultTolerantParallelClientDefaultSettings + (mode: ServerSelectionMode) + maybeConsistencyConfig + = let consistencyConfig = match maybeConsistencyConfig with | None -> SpecificNumberOfConsistentResponsesRequired 2u @@ -49,14 +50,16 @@ module Server = ServerSelectionMode.Fast (Some (SpecificNumberOfConsistentResponsesRequired 1u)) - let private FaultTolerantParallelClientSettingsForBalanceCheck (mode: ServerSelectionMode) - cacheOrInitialBalanceMatchFunc - = + let private FaultTolerantParallelClientSettingsForBalanceCheck + (mode: ServerSelectionMode) + cacheOrInitialBalanceMatchFunc + = let consistencyConfig = if mode = ServerSelectionMode.Fast then - Some - (OneServerConsistentWithCertainValueOrTwoServers - cacheOrInitialBalanceMatchFunc) + Some ( + OneServerConsistentWithCertainValueOrTwoServers + cacheOrInitialBalanceMatchFunc + ) else None @@ -68,13 +71,15 @@ module Server = // FIXME: seems there's some code duplication between this function and EtherServer.fs's GetServerFuncs function // and room for simplification to not pass a new ad-hoc delegate? - let internal GetServerFuncs<'R> (electrumClientFunc: Async -> Async<'R>) - (electrumServers: seq) - : seq> = - - let ElectrumServerToRetrievalFunc (server: ServerDetails) - (electrumClientFunc: Async -> Async<'R>) - : Async<'R> = + let internal GetServerFuncs<'R> + (electrumClientFunc: Async -> Async<'R>) + (electrumServers: seq) + : seq> = + + let ElectrumServerToRetrievalFunc + (server: ServerDetails) + (electrumClientFunc: Async -> Async<'R>) + : Async<'R> = async { try let stratumClient = ElectrumClient.StratumServer server @@ -90,16 +95,18 @@ module Server = | ex -> return raise - <| Exception - (SPrintF1 + <| Exception ( + SPrintF1 "Some problem when connecting to %s" server.ServerInfo.NetworkPath, - ex) + ex + ) } - let ElectrumServerToGenericServer (electrumClientFunc: Async -> Async<'R>) - (electrumServer: ServerDetails) - : Server = + let ElectrumServerToGenericServer + (electrumClientFunc: Async -> Async<'R>) + (electrumServer: ServerDetails) + : Server = { Details = electrumServer Retrieval = @@ -115,18 +122,20 @@ module Server = serverFuncs - let private GetRandomizedFuncs<'R> (currency: Currency) - (electrumClientFunc: Async -> Async<'R>) - : List> = + let private GetRandomizedFuncs<'R> + (currency: Currency) + (electrumClientFunc: Async -> Async<'R>) + : List> = let electrumServers = ElectrumServerSeedList.Randomize currency GetServerFuncs electrumClientFunc electrumServers |> List.ofSeq - let Query<'R when 'R: equality> currency - (settings: QuerySettings<'R>) - (job: Async -> Async<'R>) - (cancelSourceOption: Option) - : Async<'R> = + let Query<'R when 'R: equality> + currency + (settings: QuerySettings<'R>) + (job: Async -> Async<'R>) + (cancelSourceOption: Option) + : Async<'R> = let query = match cancelSourceOption with | None -> faultTolerantElectrumClient.Query @@ -146,9 +155,12 @@ module Server = FaultTolerantParallelClientDefaultSettings ServerSelectionMode.Fast - (Some - (AverageBetweenResponses - (minResponsesRequired, averageFee))) + (Some ( + AverageBetweenResponses ( + minResponsesRequired, + averageFee + ) + )) | Broadcast -> FaultTolerantParallelClientSettingsForBroadcast () query querySettings (GetRandomizedFuncs currency job) diff --git a/src/GWallet.Backend/WarpKey.fs b/src/GWallet.Backend/WarpKey.fs index 83fece92a..47f582412 100644 --- a/src/GWallet.Backend/WarpKey.fs +++ b/src/GWallet.Backend/WarpKey.fs @@ -16,6 +16,7 @@ module WarpKey = raise (ArgumentException ()) else let result = Array.create a.Length (byte 0) + for i = 0 to (a.Length - 1) do result.[i] <- ((a.[i]) ^^^ (b.[i])) @@ -31,14 +32,15 @@ module WarpKey = saltByteList.AddRange (Encoding.UTF8.GetBytes (salt)) saltByteList.Add (byte 1) - NBitcoin.Crypto.SCrypt.ComputeDerivedKey - (passphraseByteList.ToArray (), - saltByteList.ToArray (), - 262144, - 8, - 1, - Nullable (), - 32) + NBitcoin.Crypto.SCrypt.ComputeDerivedKey ( + passphraseByteList.ToArray (), + saltByteList.ToArray (), + 262144, + 8, + 1, + Nullable (), + 32 + ) let PBKDF2 (passphrase: string) (salt: string): array = // FIXME: stop using mutable collections @@ -50,11 +52,15 @@ module WarpKey = saltByteList.AddRange (Encoding.UTF8.GetBytes (salt)) saltByteList.Add (byte 2) - use hashAlgo = new HMACSHA256(passphraseByteList.ToArray ()) + use hashAlgo = new HMACSHA256 (passphraseByteList.ToArray ()) // TODO: remove nowarn when we switch to .NET BCL's impl instead of NBitcoin.Crypto - NBitcoin.Crypto.Pbkdf2.ComputeDerivedKey - (hashAlgo, saltByteList.ToArray (), 65536, 32) + NBitcoin.Crypto.Pbkdf2.ComputeDerivedKey ( + hashAlgo, + saltByteList.ToArray (), + 65536, + 32 + ) let private LENGTH_OF_PRIVATE_KEYS = 32