diff --git a/.github/workflows/macOS.yml b/.github/workflows/macOS.yml index 7280ab3df..103c3e967 100644 --- a/.github/workflows/macOS.yml +++ b/.github/workflows/macOS.yml @@ -8,7 +8,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: Run a one-line script - run: ./configure.sh && make release + run: ./configure.sh && make sanitycheck && make strict && make release macOS_tests_unit: runs-on: macOS-latest diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 49d2edc4d..f5a89d01f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v1 - name: Run a one-line script shell: cmd - run: configure.bat && make.bat release + run: configure.bat && make.bat sanitycheck && make.bat strict && make.bat release windows_tests_unit: runs-on: windows-latest diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 43cc98c9a..e15ab8a22 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,7 +17,11 @@ stockmono_build: - DEBIAN_FRONTEND=noninteractive apt-get install -y mono-complete mono-xbuild fsharp - mono --version - - time (./configure.sh && make && make install) + - ./configure.sh + - make sanitycheck + - make strict + - make + - make install # so that we log the version of nuget for when it works - make nuget @@ -44,6 +48,8 @@ stocknewmono_build: - apt install -y make git - ./configure.sh + - make sanitycheck + - make strict - make - make install @@ -86,7 +92,11 @@ newmono_build: script: - ./scripts/install_mono_from_microsoft_deb_packages.sh - - time (./configure.sh && make && make install) + - ./configure.sh + - make sanitycheck + - make strict + - make + - make install # so that we log the version of nuget for when it works - make nuget diff --git a/Makefile b/Makefile index d41784aeb..45cf347b2 100644 --- a/Makefile +++ b/Makefile @@ -21,3 +21,9 @@ update-servers: nuget: @./scripts/make.sh nuget + +sanitycheck: + @./scripts/make.sh sanitycheck + +strict: + @./scripts/make.sh strict diff --git a/scripts/find.fsx b/scripts/find.fsx new file mode 100755 index 000000000..57d2b2a7b --- /dev/null +++ b/scripts/find.fsx @@ -0,0 +1,93 @@ +#!/usr/bin/env fsharpi + +open System +open System.IO +open System.Linq + +#r "System.Configuration" +#load "InfraLib/Misc.fs" +#load "InfraLib/Process.fs" +#load "InfraLib/Git.fs" +open FSX.Infrastructure +open Process + +let FindInFile (file: FileInfo) + (maybeExcludeItems: Option>) + (someStrings: seq) + : unit = + let doIt () = + for line in File.ReadLines file.FullName do + for someString in someStrings do + if line.IndexOf someString >= 0 then + printfn "%s: %s" file.FullName line + + match maybeExcludeItems with + | None -> + doIt () + | Some excludeItems -> + if excludeItems.All(fun entryToExclude -> entryToExclude.FullName <> file.FullName) then + doIt () + +let rec FindExcludingDir (dir: DirectoryInfo) + (maybeExcludeItems: Option>) + (someStrings: seq) + : unit = + let doIt () = + for file in dir.GetFiles() do + if file.Extension.ToLower() <> ".dll" && + file.Extension.ToLower() <> ".exe" && + file.Extension.ToLower() <> ".png" then + FindInFile file maybeExcludeItems someStrings + for subFolder in dir.GetDirectories() do + if subFolder.Name <> ".git" && + subFolder.Name <> "obj" && + subFolder.Name <> "bin" && + subFolder.Name <> "packages" then + FindExcludingDir subFolder maybeExcludeItems someStrings + match maybeExcludeItems with + | None -> + doIt () + | Some excludeItems -> + if excludeItems.All(fun entryToExclude -> entryToExclude.FullName <> dir.FullName) then + doIt () + +let args = Misc.FsxArguments() + +let note = "NOTE: by default, some kind of files/folders will be excluded, e.g.: .git/, packages/, bin/, obj/, *.exe, *.dll, *.png, ..." + +if args.Length < 1 then + Console.Error.WriteLine "Please pass at least 1 argument, with optional flag: find.fsx [-x=someDirToExclude,someFileToExclude] someString" + Console.WriteLine note + Environment.Exit 1 + +let firstArg = args.[0] + +let excludeParticularFileSystemEntries = + if firstArg.StartsWith "--exclude=" || firstArg.StartsWith "-x=" then + firstArg.Substring(firstArg.IndexOf("=")+1) |> Some + else + None + +let startDir = Directory.GetCurrentDirectory() |> DirectoryInfo +match excludeParticularFileSystemEntries with +| None -> + let someStrings = args + FindExcludingDir startDir None someStrings +| Some excludeList -> + let someStrings = args.Skip(1) + let entriesToExclude = + excludeList.Split([|Path.PathSeparator|], StringSplitOptions.RemoveEmptyEntries) + let excludeItems = + seq { + for entry in entriesToExclude do + let dir = entry |> DirectoryInfo + let file = entry |> FileInfo + if dir.Exists then + yield dir :> FileSystemInfo + elif file.Exists then + yield file :> FileSystemInfo + else + failwithf "Directory or file '%s' doesn't exist" dir.FullName + } + FindExcludingDir startDir (Some excludeItems) someStrings + diff --git a/scripts/make.fsx b/scripts/make.fsx index 9f0143787..d29ffeefa 100755 --- a/scripts/make.fsx +++ b/scripts/make.fsx @@ -2,6 +2,7 @@ open System open System.IO +open System.Linq open System.Diagnostics #r "System.Configuration" @@ -114,17 +115,28 @@ let PrintNugetVersion () = Console.WriteLine() failwith "nuget process' output contained errors ^" -let JustBuild binaryConfig = +let JustBuild binaryConfig maybeConstant = let buildTool = Map.tryFind "BuildTool" buildConfigContents if buildTool.IsNone then failwith "A BuildTool should have been chosen by the configure script, please report this bug" Console.WriteLine (sprintf "Building in %s mode..." (binaryConfig.ToString())) let configOption = sprintf "/p:Configuration=%s" (binaryConfig.ToString()) - let configOptions = + let defineConstantsFromBuildConfig = match buildConfigContents |> Map.tryFind "DefineConstants" with - | Some constants -> sprintf "%s;DefineConstants=%s" configOption constants - | None -> configOption + | Some constants -> constants.Split([|";"|], StringSplitOptions.RemoveEmptyEntries) |> Seq.ofArray + | None -> Seq.empty + let allDefineConstants = + match maybeConstant with + | Some constant -> Seq.append [constant] defineConstantsFromBuildConfig + | None -> defineConstantsFromBuildConfig + let configOptions = + if allDefineConstants.Any() then + // FIXME: we shouldn't override the project's DefineConstants, but rather set "ExtraDefineConstants" + // from the command line, and merge them later in the project file: see https://stackoverflow.com/a/32326853/544947 + sprintf "%s;DefineConstants=%s" configOption (String.Join(";", allDefineConstants)) + else + configOption let buildProcess = Process.Execute ({ Command = buildTool.Value; Arguments = configOptions }, Echo.All) if (buildProcess.ExitCode <> 0) then Console.Error.WriteLine (sprintf "%s build failed" buildTool.Value) @@ -148,9 +160,9 @@ let GetPathToFrontendBinariesDir (binaryConfig: BinaryConfig) = let GetPathToBackend () = Path.Combine (rootDir.FullName, "src", BACKEND) -let MakeAll() = +let MakeAll maybeConstant = let buildConfig = BinaryConfig.Debug - JustBuild buildConfig + JustBuild buildConfig maybeConstant buildConfig let RunFrontend (buildConfig: BinaryConfig) (maybeArgs: Option) = @@ -186,10 +198,10 @@ let RunFrontend (buildConfig: BinaryConfig) (maybeArgs: Option) = let maybeTarget = GatherTarget (Misc.FsxArguments(), None) match maybeTarget with | None -> - MakeAll() |> ignore + MakeAll None |> ignore | Some("release") -> - JustBuild BinaryConfig.Release + JustBuild BinaryConfig.Release None | Some "nuget" -> Console.WriteLine "This target is for debugging purposes." @@ -205,7 +217,7 @@ match maybeTarget with let version = Misc.GetCurrentVersion(rootDir).ToString() let release = BinaryConfig.Release - JustBuild release + JustBuild release None let binDir = "bin" Directory.CreateDirectory(binDir) |> ignore @@ -258,7 +270,7 @@ match maybeTarget with | _ -> let nunitVersion = "2.7.1" if not nugetExe.Exists then - MakeAll () |> ignore + MakeAll None |> ignore let nugetInstallCommand = { @@ -285,7 +297,7 @@ match maybeTarget with | Some("install") -> let buildConfig = BinaryConfig.Release - JustBuild buildConfig + JustBuild buildConfig None let destDirUpperCase = Environment.GetEnvironmentVariable "DESTDIR" let destDirLowerCase = Environment.GetEnvironmentVariable "DestDir" @@ -313,12 +325,12 @@ match maybeTarget with failwith "Unexpected chmod failure, please report this bug" | Some("run") -> - let buildConfig = MakeAll() + let buildConfig = MakeAll None RunFrontend buildConfig None |> ignore | Some "update-servers" -> - let buildConfig = MakeAll() + let buildConfig = MakeAll None Directory.SetCurrentDirectory (GetPathToBackend()) let proc1 = RunFrontend buildConfig (Some "--update-servers-file") if proc1.ExitCode <> 0 then @@ -327,6 +339,44 @@ match maybeTarget with let proc2 = RunFrontend buildConfig (Some "--update-servers-stats") Environment.Exit proc2.ExitCode +| Some "strict" -> + MakeAll <| Some "STRICTER_COMPILATION_BUT_WITH_REFLECTION_AT_RUNTIME" + |> ignore + +| Some "sanitycheck" -> + let FindOffendingPrintfUsage () = + let findScript = Path.Combine(rootDir.FullName, "scripts", "find.fsx") + let fsxRunner = + match Misc.GuessPlatform() with + | Misc.Platform.Windows -> + Path.Combine(rootDir.FullName, "scripts", "fsi.bat") + | _ -> + let fsxRunnerEnvVar = Environment.GetEnvironmentVariable "FsxRunner" + if String.IsNullOrEmpty fsxRunnerEnvVar then + failwith "FsxRunner env var should have been passed to make.sh" + fsxRunnerEnvVar + let excludeFolders = + String.Format("scripts{0}" + + "src{1}GWallet.Frontend.Console{0}" + + "src{1}GWallet.Backend.Tests{0}" + + "src{1}GWallet.Backend{1}FSharpUtil.fs", + Path.PathSeparator, Path.DirectorySeparatorChar) + + let proc = + { + Command = fsxRunner + Arguments = sprintf "%s --exclude=%s %s" + findScript + excludeFolders + "printf failwithf" + } + let findProc = Process.SafeExecute (proc, Echo.All) + if findProc.Output.StdOut.Trim().Length > 0 then + Console.Error.WriteLine "Illegal usage of printf/printfn/sprintf/sprintfn/failwithf detected" + Environment.Exit 1 + + FindOffendingPrintfUsage() + | Some(someOtherTarget) -> Console.Error.WriteLine("Unrecognized target: " + someOtherTarget) Environment.Exit 2 diff --git a/scripts/make.sh b/scripts/make.sh index ce0da821b..5228a86ef 100755 --- a/scripts/make.sh +++ b/scripts/make.sh @@ -6,4 +6,4 @@ if [ ! -f "$BUILD_CONFIG" ]; then echo "ERROR: configure hasn't been run yet, run ./configure.sh first" >&2 && exit 1 fi source "$BUILD_CONFIG" -$FsxRunner ./scripts/make.fsx "$@" +FsxRunner=$FsxRunner $FsxRunner ./scripts/make.fsx "$@" diff --git a/src/GWallet.Backend.Tests/FSharpUtil.fs b/src/GWallet.Backend.Tests/FSharpUtil.fs index 23965e2db..04b384854 100644 --- a/src/GWallet.Backend.Tests/FSharpUtil.fs +++ b/src/GWallet.Backend.Tests/FSharpUtil.fs @@ -10,6 +10,18 @@ open GWallet.Backend type UnexpectedTaskCanceledException(message: string, innerException) = inherit TaskCanceledException (message, innerException) +type TypeWithStringOverridenManually = + | FOO + | BAR + override self.ToString() = + match self with + | FOO -> "FOO" + | BAR -> "BAR" + +type TypeWithNoToStringOverriden = + | FOO + | BAR + [] type FSharpUtilCoverage() = @@ -50,3 +62,70 @@ type FSharpUtilCoverage() = | None -> failwith "should find sibling 2 too" | Some ex -> Assert.That(Object.ReferenceEquals(ex, innerEx2), Is.True) + + [] + member __.``converts fsharp's print syntax to String-Format (basic)``() = + let basicStr = "%s" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat basicStr, Is.EqualTo "{0}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF1 basicStr "foo", Is.EqualTo "foo") + + let basicInt1 = "%i" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat basicInt1, Is.EqualTo "{0}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF1 basicInt1 1, Is.EqualTo "1") + + let basicInt2 = "%d" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat basicInt2, Is.EqualTo "{0}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF1 basicInt2 2, Is.EqualTo "2") + + let moreChars = "[%s]" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat moreChars, Is.EqualTo "[{0}]") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF1 moreChars "foo", Is.EqualTo "[foo]") + + let twoStrings = "%s-%s" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat twoStrings, Is.EqualTo "{0}-{1}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF2 twoStrings "foo" "bar", Is.EqualTo "foo-bar") + + let twoElementsWithDifferentTypes = "%s-%i" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat twoElementsWithDifferentTypes, Is.EqualTo "{0}-{1}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF2 twoElementsWithDifferentTypes "foo" 1, + Is.EqualTo "foo-1") + + let twoElementsWithDifferentTypesWithInverseOrder = "%i-%s" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat twoElementsWithDifferentTypesWithInverseOrder, + Is.EqualTo "{0}-{1}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF2 twoElementsWithDifferentTypesWithInverseOrder 1 "foo", + Is.EqualTo "1-foo") + + let advancedEscaping = "%f%% done" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat advancedEscaping, Is.EqualTo "{0}% done") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF1 advancedEscaping 0.1, Is.EqualTo "0.1% done") + + [] + member __.``converts fsharp's print syntax to String-Format (advanced I)``() = + let advanced = "%A" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat advanced, Is.EqualTo "{0}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF1 advanced TypeWithStringOverridenManually.FOO, + Is.EqualTo "FOO") + + let advanced2 = "%Ax%A" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat advanced2, Is.EqualTo "{0}x{1}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF2 advanced2 + TypeWithStringOverridenManually.FOO + TypeWithStringOverridenManually.BAR, + Is.EqualTo "FOOxBAR") + + [] + [] + member __.``converts fsharp's print syntax to String-Format (advanced II)``() = + let advanced = "%A" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat advanced, Is.EqualTo "{0}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF1 advanced TypeWithNoToStringOverriden.FOO, + Is.EqualTo "FOO") + + let advanced2 = "%Ax%A" + Assert.That(FSharpUtil.ReflectionlessPrint.ToStringFormat advanced2, Is.EqualTo "{0}x{1}") + Assert.That(FSharpUtil.ReflectionlessPrint.SPrintF2 advanced2 + TypeWithNoToStringOverriden.FOO + TypeWithNoToStringOverriden.BAR, + Is.EqualTo "FOOxBAR") + diff --git a/src/GWallet.Backend/Account.fs b/src/GWallet.Backend/Account.fs index ae05513a4..47da7ab48 100644 --- a/src/GWallet.Backend/Account.fs +++ b/src/GWallet.Backend/Account.fs @@ -5,6 +5,8 @@ open System.Linq open System.IO open System.Threading.Tasks +open GWallet.Backend.FSharpUtil.UwpHacks + module Account = let private GetShowableBalanceInternal (account: IAccount) @@ -14,12 +16,13 @@ module Account = match account with | :? UtxoCoin.IUtxoAccount as utxoAccount -> if not (account.Currency.IsUtxo()) then - failwithf "Currency %A not Utxo-type but account is? report this bug (balance)" account.Currency + failwith <| SPrintF1 "Currency %A not Utxo-type but account is? report this bug (balance)" + account.Currency UtxoCoin.Account.GetShowableBalance utxoAccount mode cancelSourceOption | _ -> if not (account.Currency.IsEtherBased()) then - failwithf "Currency %A not ether based and not UTXO either? not supported, report this bug (balance)" + failwith <| SPrintF1 "Currency %A not ether based and not UTXO either? not supported, report this bug (balance)" account.Currency Ether.Account.GetShowableBalance account mode cancelSourceOption @@ -76,7 +79,7 @@ module Account = Ether.Account.GetPublicAddressFromNormalAccountFile NormalAccount(currency, accountFile, fromAccountFileToPublicAddress) :> IAccount else - failwithf "Unknown currency %A" currency + failwith <| SPrintF1 "Unknown currency %A" currency yield account } @@ -111,7 +114,7 @@ module Account = elif currency.IsEtherBased() then Ether.Account.GetPublicAddressFromUnencryptedPrivateKey else - failwithf "Unknown currency %A" currency + failwith <| SPrintF1 "Unknown currency %A" currency let fromConfigAccountFileToPublicAddressFunc (accountConfigFile: FileRepresentation) = let privateKeyFromConfigFile = accountConfigFile.Content() @@ -152,7 +155,7 @@ module Account = elif currency.IsUtxo() then UtxoCoin.Account.ValidateAddress currency address else - failwithf "Unknown currency %A" currency + failwith <| SPrintF1 "Unknown currency %A" currency } @@ -161,12 +164,13 @@ module Account = match account with | :? UtxoCoin.IUtxoAccount as utxoAccount -> if not (account.Currency.IsUtxo()) then - failwithf "Currency %A not Utxo-type but account is? report this bug (estimatefee)" account.Currency + failwith <| SPrintF1 "Currency %A not Utxo-type but account is? report this bug (estimatefee)" + account.Currency let! fee = UtxoCoin.Account.EstimateFee utxoAccount amount destination return fee :> IBlockchainFeeInfo | _ -> if not (account.Currency.IsEtherBased()) then - failwithf "Currency %A not ether based and not UTXO either? not supported, report this bug (estimatefee)" + failwith <| SPrintF1 "Currency %A not ether based and not UTXO either? not supported, report this bug (estimatefee)" account.Currency let! fee = Ether.Account.EstimateFee account amount destination return fee :> IBlockchainFeeInfo @@ -196,7 +200,7 @@ module Account = | :? Ether.TransactionMetadata as etherTxMetadata -> let! outOfGas = Ether.Server.IsOutOfGas transactionMetadata.Currency txHash etherTxMetadata.Fee.GasLimit if outOfGas then - return failwithf "Transaction ran out of gas: %s" txHash + return failwith <| SPrintF1 "Transaction ran out of gas: %s" txHash | _ -> () } @@ -214,7 +218,7 @@ module Account = elif currency.IsUtxo() then UtxoCoin.Account.BroadcastTransaction currency trans else - failwithf "Unknown currency %A" currency + failwith <| SPrintF1 "Unknown currency %A" currency do! CheckIfOutOfGas trans.TransactionInfo.Metadata txId @@ -282,7 +286,7 @@ module Account = elif currency.IsEther() then Ether.Account.GetPublicAddressFromUnencryptedPrivateKey else - failwithf "Unknown currency %A" currency + failwith <| SPrintF1 "Unknown currency %A" currency let fromConfigFileToPublicAddressFunc (accountConfigFile: FileRepresentation) = // there's no ETH unencrypted standard: https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition @@ -311,7 +315,7 @@ module Account = let privKey = Ether.Account.GetPrivateKey account password privKey.GetPrivateKey() else - failwithf "Unknown currency %A" currency + failwith <| SPrintF1 "Unknown currency %A" currency CreateArchivedAccount currency privateKeyAsString |> ignore Config.RemoveNormalAccount account @@ -327,7 +331,7 @@ module Account = | :? UtxoCoin.ArchivedUtxoAccount as utxoAccount -> UtxoCoin.Account.SweepArchivedFunds utxoAccount balance destination utxoTxMetadata | _ -> - failwithf "If tx metadata is UTXO type, archived account should be too" + failwith "If tx metadata is UTXO type, archived account should be too" | _ -> failwith "tx metadata type unknown" let SendPayment (account: NormalAccount) @@ -349,7 +353,8 @@ module Account = match txMetadata with | :? UtxoCoin.TransactionMetadata as btcTxMetadata -> if not (currency.IsUtxo()) then - failwithf "Currency %A not Utxo-type but tx metadata is? report this bug (sendpayment)" currency + failwith <| SPrintF1 "Currency %A not Utxo-type but tx metadata is? report this bug (sendpayment)" + currency match account with | :? UtxoCoin.NormalUtxoAccount as utxoAccount -> UtxoCoin.Account.SendPayment utxoAccount btcTxMetadata destination amount password @@ -361,7 +366,7 @@ module Account = failwith "Account not ether-type but tx metadata is? report this bug (sendpayment)" Ether.Account.SendPayment account etherTxMetadata destination amount password | _ -> - failwithf "Unknown tx metadata type" + failwith "Unknown tx metadata type" do! CheckIfOutOfGas txMetadata txId @@ -464,7 +469,7 @@ module Account = elif currency.IsEtherBased() then return! CreateConceptEtherAccountInternal password seed else - return failwithf "Unknown currency %A" currency + return failwith <| SPrintF1 "Unknown currency %A" currency } @@ -515,7 +520,7 @@ module Account = (dobPartOfSalt: DateTime) (emailPartOfSalt: string) : Async> = async { - let salt = sprintf "%s+%s" (dobPartOfSalt.Date.ToString("yyyyMMdd")) (emailPartOfSalt.ToLower()) + let salt = SPrintF2 "%s+%s" (dobPartOfSalt.Date.ToString("yyyyMMdd")) (emailPartOfSalt.ToLower()) let privateKeyBytes = WarpKey.CreatePrivateKey passphrase salt return privateKeyBytes } @@ -608,7 +613,7 @@ module Account = Marshalling.Deserialize json deserializedBtcTransaction.ToAbstract() | unexpectedType -> - raise <| Exception(sprintf "Unknown unsignedTransaction subtype: %s" unexpectedType.FullName) + raise <| Exception(SPrintF1 "Unknown unsignedTransaction subtype: %s" unexpectedType.FullName) let public ImportSignedTransactionFromJson (json: string): SignedTransaction = let transType = Marshalling.ExtractType json @@ -623,7 +628,7 @@ module Account = Marshalling.Deserialize json deserializedBtcTransaction.ToAbstract() | unexpectedType -> - raise <| Exception(sprintf "Unknown signedTransaction subtype: %s" unexpectedType.FullName) + raise <| Exception(SPrintF1 "Unknown signedTransaction subtype: %s" unexpectedType.FullName) let LoadSignedTransactionFromFile (filePath: string) = let signedTransInJson = File.ReadAllText(filePath) diff --git a/src/GWallet.Backend/BlockExplorer.fs b/src/GWallet.Backend/BlockExplorer.fs index 7fc7283af..1871460ea 100644 --- a/src/GWallet.Backend/BlockExplorer.fs +++ b/src/GWallet.Backend/BlockExplorer.fs @@ -3,6 +3,7 @@ open System open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks module BlockExplorer = @@ -22,7 +23,7 @@ module BlockExplorer = // the only one? minergate.com seems to only show blocks, not addresses "https://gastracker.io/addr/" | Currency.SAI -> - sprintf "https://etherscan.io/token/%s?a=" Ether.TokenManager.SAI_CONTRACT_ADDRESS + SPrintF1 "https://etherscan.io/token/%s?a=" Ether.TokenManager.SAI_CONTRACT_ADDRESS | Currency.DAI -> raise <| NotImplementedException() Uri(baseUrl + account.PublicAddress) diff --git a/src/GWallet.Backend/Caching.fs b/src/GWallet.Backend/Caching.fs index 84fa9c1f4..e7a912a60 100644 --- a/src/GWallet.Backend/Caching.fs +++ b/src/GWallet.Backend/Caching.fs @@ -5,6 +5,8 @@ open System.IO open System.Linq open System.Net.Http +open GWallet.Backend.FSharpUtil.UwpHacks + type CachedNetworkData = { UsdPrice: Map>; @@ -109,7 +111,7 @@ module Caching = | :? DeserializationException -> // FIXME: report a warning to sentry here... Infrastructure.LogError "Warning: cleaning incompatible cache data found" - Infrastructure.LogDebug (sprintf "JSON content: <<<%s>>>" json) + Infrastructure.LogDebug (SPrintF1 "JSON content: <<<%s>>>" json) None with | :? FileNotFoundException -> None @@ -253,7 +255,7 @@ module Caching = for KeyValue(currency,servers) in mergedAndSaved do for server in servers do if server.CommunicationHistory.IsNone then - Infrastructure.LogError (sprintf "WARNING: no history stats about %A server %s" + Infrastructure.LogError (SPrintF2 "WARNING: no history stats about %A server %s" currency server.ServerInfo.NetworkPath) mergedServers @@ -296,7 +298,7 @@ module Caching = String.Join(Environment.NewLine, json1, json2, json3, json4) let ReportProblem (negativeBalance: decimal) (previousBalance) (currency) (address) (newCache) = - Infrastructure.ReportError (sprintf "Negative balance '%s'. Details: %s" + Infrastructure.ReportError (SPrintF2 "Negative balance '%s'. Details: %s" (negativeBalance.ToString()) (GatherDebuggingInfo previousBalance @@ -554,7 +556,7 @@ module Caching = lock cacheFiles.ServerStats (fun _ -> match sessionServerRanking.TryFind currency with | None -> - failwithf "Initialization of servers' cache failed? currency %A not found" currency + failwith <| SPrintF1 "Initialization of servers' cache failed? currency %A not found" currency | Some servers -> servers ) @@ -595,18 +597,18 @@ module Caching = let projName = "geewallet" let ghBaseUrl,glBaseUrl,gnomeBaseUrl = "https://raw.githubusercontent.com","https://gitlab.com","https://gitlab.gnome.org" - let pathToFile = sprintf "src/GWallet.Backend/%s" ServerRegistry.ServersEmbeddedResourceFileName + let pathToFile = SPrintF1 "src/GWallet.Backend/%s" ServerRegistry.ServersEmbeddedResourceFileName let gitHub = - sprintf "%s/%s/%s/%s/%s" + SPrintF5 "%s/%s/%s/%s/%s" ghBaseUrl orgName1 projName targetBranch pathToFile let gitLab = - sprintf "%s/%s/%s/raw/%s/%s" + SPrintF5 "%s/%s/%s/raw/%s/%s" glBaseUrl orgName1 projName targetBranch pathToFile let gnomeGitLab = - sprintf "%s/%s/%s/raw/%s/%s" + SPrintF5 "%s/%s/%s/raw/%s/%s" gnomeBaseUrl orgName2 projName targetBranch pathToFile let allUrls = [ gitHub; gitLab; gnomeGitLab ] diff --git a/src/GWallet.Backend/Config.fs b/src/GWallet.Backend/Config.fs index d59d608b1..fc3c5bc86 100644 --- a/src/GWallet.Backend/Config.fs +++ b/src/GWallet.Backend/Config.fs @@ -7,6 +7,8 @@ open System.Reflection open Xamarin.Essentials +open GWallet.Backend.FSharpUtil.UwpHacks + // TODO: make internal when tests don't depend on this anymore module Config = @@ -151,7 +153,7 @@ module Config = let private RemoveAccount (account: BaseAccount): unit = let configFile = GetFile (account:>IAccount).Currency account if not configFile.Exists then - failwithf "File %s doesn't exist. Please report this issue." configFile.FullName + failwith <| SPrintF1 "File %s doesn't exist. Please report this issue." configFile.FullName else configFile.Delete() @@ -165,6 +167,6 @@ module Config = let assembly = Assembly.GetExecutingAssembly() use stream = assembly.GetManifestResourceStream resourceName if (stream = null) then - failwithf "Embedded resource %s not found" resourceName + failwith <| SPrintF1 "Embedded resource %s not found" resourceName use reader = new StreamReader(stream) reader.ReadToEnd() diff --git a/src/GWallet.Backend/Currency.fs b/src/GWallet.Backend/Currency.fs index f957eec0b..ff94e44f9 100644 --- a/src/GWallet.Backend/Currency.fs +++ b/src/GWallet.Backend/Currency.fs @@ -3,20 +3,39 @@ open System.Linq open System.ComponentModel +open GWallet.Backend.FSharpUtil.UwpHacks + // this attribute below is for Json.NET (Newtonsoft.Json) to be able to deserialize this as a dict key [)>] type Currency = + // + +#if STRICTER_COMPILATION_BUT_WITH_REFLECTION_AT_RUNTIME static member ToStrings() = Microsoft.FSharp.Reflection.FSharpType.GetUnionCases(typeof) |> Array.map (fun info -> info.Name) +#endif + static member GetAll(): seq = +#if STRICTER_COMPILATION_BUT_WITH_REFLECTION_AT_RUNTIME FSharpUtil.GetAllElementsFromDiscriminatedUnion() +#else + seq { + yield BTC + yield LTC + yield ETH + yield ETC + yield SAI + yield DAI + } +#endif static member Parse(currencyString: string): Currency = Currency.GetAll().First(fun currency -> currencyString = currency.ToString()) @@ -38,10 +57,22 @@ type Currency = elif self = Currency.SAI then 18 else - failwithf "Unable to determine decimal places for %A" self + failwith <| SPrintF1 "Unable to determine decimal places for %A" self override self.ToString() = - sprintf "%A" self +#if STRICTER_COMPILATION_BUT_WITH_REFLECTION_AT_RUNTIME + SPrintF1 "%A" self +#else + // when we can depend on newer versions of F#, we might be able to get rid of this (or ToString() altogther) below + // (see FSharpUtil's test names "converts fsharp's print syntax to String-Format (advanced II)" for more info): + match self with + | BTC -> "BTC" + | LTC -> "LTC" + | ETH -> "ETH" + | ETC -> "ETC" + | SAI -> "SAI" + | DAI -> "DAI" +#endif // the reason we have used "and" is because of the circular reference // between StringTypeConverter and Currency diff --git a/src/GWallet.Backend/Ether/EtherAccount.fs b/src/GWallet.Backend/Ether/EtherAccount.fs index b85b89960..8fd260788 100644 --- a/src/GWallet.Backend/Ether/EtherAccount.fs +++ b/src/GWallet.Backend/Ether/EtherAccount.fs @@ -13,6 +13,7 @@ open Nethereum.Util open Nethereum.KeyStore.Crypto open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks module internal Account = @@ -45,7 +46,7 @@ module internal Account = elif (account.Currency.IsEthToken()) then Server.GetTokenBalance account.Currency account.PublicAddress balType mode cancelSourceOption else - failwithf "Assertion failed: currency %A should be Ether or Ether token" account.Currency + failwith <| SPrintF1 "Assertion failed: currency %A should be Ether or Ether token" account.Currency return balance } @@ -137,7 +138,7 @@ module internal Account = let! result = Ether.Server.GetTransactionCount currency publicAddress let value = result.Value if (value > BigInteger(Int64.MaxValue)) then - failwithf "Serialization doesn't support such a big integer (%s) for the nonce, please report this issue." + failwith <| SPrintF1 "Serialization doesn't support such a big integer (%s) for the nonce, please report this issue." (result.ToString()) let int64result:Int64 = BigInteger.op_Explicit value return int64result @@ -146,7 +147,7 @@ module internal Account = let private GetGasPrice currency: Async = async { let! gasPrice = Ether.Server.GetGasPrice currency if (gasPrice.Value > BigInteger(Int64.MaxValue)) then - failwithf "Serialization doesn't support such a big integer (%s) for the gas, please report this issue." + failwith <| SPrintF1 "Serialization doesn't support such a big integer (%s) for the gas, please report this issue." (gasPrice.Value.ToString()) let gasPrice64: Int64 = BigInteger.op_Explicit gasPrice.Value return gasPrice64 @@ -174,11 +175,11 @@ module internal Account = let baseCurrency = match account.Currency with | DAI | SAI -> ETH - | _ -> failwithf "Unknown token %A" account.Currency + | _ -> failwith <| SPrintF1 "Unknown token %A" account.Currency let! tokenTransferFee = Ether.Server.EstimateTokenTransferFee account amount destination if (tokenTransferFee.Value > BigInteger(Int64.MaxValue)) then - failwithf "Serialization doesn't support such a big integer (%s) for the gas cost of the token transfer, please report this issue." + failwith <| SPrintF1 "Serialization doesn't support such a big integer (%s) for the gas cost of the token transfer, please report this issue." (tokenTransferFee.Value.ToString()) let gasCost64: Int64 = BigInteger.op_Explicit tokenTransferFee.Value @@ -193,7 +194,7 @@ module internal Account = elif account.Currency.IsEthToken() then return! EstimateTokenTransferFee account amount.ValueToSend destination else - return failwithf "Assertion failed: currency %A should be Ether or Ether token" account.Currency + return failwith <| SPrintF1 "Assertion failed: currency %A should be Ether or Ether token" account.Currency } let private BroadcastRawTransaction (currency: Currency) trans = @@ -217,13 +218,13 @@ module internal Account = let private GetNetwork (currency: Currency) = if not (currency.IsEtherBased()) then - failwithf "Assertion failed: currency %A should be Ether-type" currency + failwith <| SPrintF1 "Assertion failed: currency %A should be Ether-type" currency if currency.IsEthToken() || currency = ETH then Config.EthNet elif currency = ETC then Config.EtcNet else - failwithf "Assertion failed: Ether currency %A not supported?" currency + failwith <| SPrintF1 "Assertion failed: Ether currency %A not supported?" currency let private SignEtherTransaction (chain: Chain) (txMetadata: TransactionMetadata) @@ -232,7 +233,7 @@ module internal Account = (privateKey: EthECKey) = if (GetNetwork txMetadata.Fee.Currency <> chain) then - invalidArg "chain" (sprintf "Assertion failed: fee currency (%A) chain doesn't match with passed chain (%A)" + invalidArg "chain" (SPrintF2 "Assertion failed: fee currency (%A) chain doesn't match with passed chain (%A)" txMetadata.Fee.Currency chain) let amountToSendConsideringMinerFee = @@ -301,11 +302,11 @@ module internal Account = SignEtherTokenTransaction chain txMetadata account.PublicAddress destination amount privateKey elif account.Currency.IsEtherBased() then if (txMetadata.Fee.Currency <> account.Currency) then - failwithf "Assertion failed: fee currency (%A) doesn't match with passed chain (%A)" + failwith <| SPrintF2 "Assertion failed: fee currency (%A) doesn't match with passed chain (%A)" txMetadata.Fee.Currency account.Currency SignEtherTransaction chain txMetadata destination amount privateKey else - failwithf "Assertion failed: Ether currency %A not supported?" account.Currency + failwith <| SPrintF1 "Assertion failed: Ether currency %A not supported?" account.Currency if not (signer.VerifyTransaction(trans, chain)) then failwith "Transaction could not be verified?" diff --git a/src/GWallet.Backend/Ether/EtherExceptions.fs b/src/GWallet.Backend/Ether/EtherExceptions.fs index d5acb5304..d68be97fb 100644 --- a/src/GWallet.Backend/Ether/EtherExceptions.fs +++ b/src/GWallet.Backend/Ether/EtherExceptions.fs @@ -4,6 +4,7 @@ open System open System.Net open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks type HttpStatusCodeNotPresentInTheBcl = | TooManyRequests = 429 @@ -51,12 +52,12 @@ type ServerChannelNegotiationException = } new(message: string, webExStatusCode: WebExceptionStatus, innerException: Exception) = { - inherit CommunicationUnsuccessfulException(sprintf "%s (WebErr: %s)" message (webExStatusCode.ToString()), + inherit CommunicationUnsuccessfulException(SPrintF2 "%s (WebErr: %s)" message (webExStatusCode.ToString()), innerException) } new(message: string, cloudFlareError: CloudFlareError, innerException: Exception) = { - inherit CommunicationUnsuccessfulException(sprintf "%s (CfErr: %s)" message (cloudFlareError.ToString()), + inherit CommunicationUnsuccessfulException(SPrintF2 "%s (CfErr: %s)" message (cloudFlareError.ToString()), innerException) } @@ -73,7 +74,7 @@ type UnhandledWebException = new (status: WebExceptionStatus, innerException: Exception) = { - inherit Exception (sprintf "Backend not prepared for this WebException with Status[%d]" + inherit Exception (SPrintF1 "Backend not prepared for this WebException with Status[%i]" (int status), innerException) } diff --git a/src/GWallet.Backend/Ether/EtherServer.fs b/src/GWallet.Backend/Ether/EtherServer.fs index 489871ad6..de3eebe6f 100644 --- a/src/GWallet.Backend/Ether/EtherServer.fs +++ b/src/GWallet.Backend/Ether/EtherServer.fs @@ -13,6 +13,7 @@ open Nethereum.RPC.Eth.DTOs open Nethereum.StandardTokenEIP20.ContractDefinition open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks type BalanceType = | Unconfirmed @@ -55,7 +56,7 @@ module Web3ServerSeedList = elif currency.IsEthToken() then Currency.ETH else - failwithf "Assertion failed: Ether currency %A not supported?" currency + failwith <| SPrintF1 "Assertion failed: Ether currency %A not supported?" currency Caching.Instance.GetServers baseCurrency |> List.ofSeq let Randomize currency = @@ -68,18 +69,18 @@ module Server = let private Web3Server (serverDetails: ServerDetails) = match serverDetails.ServerInfo.ConnectionType with | { Protocol = Tcp _ ; Encrypted = _ } -> - failwithf "Ether server of TCP connection type?: %s" serverDetails.ServerInfo.NetworkPath + failwith <| SPrintF1 "Ether server of TCP connection type?: %s" serverDetails.ServerInfo.NetworkPath | { Protocol = Http ; Encrypted = encrypted } -> let protocol = if encrypted then "https" else "http" - let uri = sprintf "%s://%s" protocol serverDetails.ServerInfo.NetworkPath + let uri = SPrintF2 "%s://%s" protocol serverDetails.ServerInfo.NetworkPath SomeWeb3 uri let HttpRequestExceptionMatchesErrorCode (ex: Http.HttpRequestException) (errorCode: int): bool = - ex.Message.StartsWith(sprintf "%d " errorCode) || ex.Message.Contains(sprintf " %d " errorCode) + ex.Message.StartsWith(SPrintF1 "%i " errorCode) || ex.Message.Contains(SPrintF1 " %i " errorCode) let exMsg = "Could not communicate with EtherServer" let PerformEtherRemoteCallWithTimeout<'T,'R> (job: Async<'R>): Async<'R> = async { @@ -179,7 +180,7 @@ module Server = if (not (rpcResponseEx.RpcError.Message.Contains "pruning=archive")) && (not (rpcResponseEx.RpcError.Message.Contains "missing trie node")) then raise <| Exception( - sprintf "Expecting 'pruning=archive' or 'missing trie node' in message of a %d code" + SPrintF1 "Expecting 'pruning=archive' or 'missing trie node' in message of a %i code" (int RpcErrorCode.StatePruningNodeOrMissingTrieNode), rpcResponseEx) else raise <| ServerMisconfiguredException(exMsg, rpcResponseEx) @@ -189,7 +190,7 @@ module Server = raise <| ServerMisconfiguredException(exMsg, rpcResponseEx) if rpcResponseEx.RpcError.Code = int RpcErrorCode.EmptyResponse then raise <| ServerMisconfiguredException(exMsg, rpcResponseEx) - raise <| Exception(sprintf "RpcResponseException with RpcError Code <%d> and Message '%s' (%s)" + raise <| Exception(SPrintF3 "RpcResponseException with RpcError Code <%i> and Message '%s' (%s)" rpcResponseEx.RpcError.Code rpcResponseEx.RpcError.Message rpcResponseEx.Message, @@ -353,10 +354,10 @@ module Server = // NOTE: try to make this 'with' block be in sync with the one in UtxoCoinAccount:GetRandomizedFuncs() with | :? CommunicationUnsuccessfulException as ex -> - let msg = sprintf "%s: %s" (ex.GetType().FullName) ex.Message + let msg = SPrintF2 "%s: %s" (ex.GetType().FullName) ex.Message return raise <| ServerDiscardedException(msg, ex) | ex -> - return raise <| Exception(sprintf "Some problem when connecting to '%s'" + return raise <| Exception(SPrintF1 "Some problem when connecting to '%s'" server.ServerInfo.NetworkPath, ex) } @@ -416,7 +417,7 @@ module Server = NUMBER_OF_CONFIRMATIONS_TO_CONSIDER_BALANCE_CONFIRMED) if blockToCheck.Sign < 0 then - let errMsg = sprintf + let errMsg = SPrintF2 "Looks like we received a wrong latestBlock(%s) because the substract was negative(%s)" (latestBlock.Value.ToString()) (blockToCheck.ToString()) @@ -430,7 +431,7 @@ module Server = let! blockForConfirmationReference = GetBlockToCheckForConfirmedBalance web3 (* if (Config.DebugLog) then - Infrastructure.LogError (sprintf "Last block number and last confirmed block number: %s: %s" + Infrastructure.LogError (SPrintF2 "Last block number and last confirmed block number: %s: %s" (latestBlock.Value.ToString()) (blockForConfirmationReference.BlockNumber.Value.ToString())) *) @@ -679,7 +680,7 @@ module Server = let emptyContract = "0x" if not (contractCode.StartsWith emptyContract) then - failwithf "GetCode API should always return a string starting with %s, but got: %s" + failwith <| SPrintF2 "GetCode API should always return a string starting with %s, but got: %s" emptyContract contractCode elif contractCode <> emptyContract then return raise <| InvalidDestinationAddress "Sending to contract addresses is not supported yet. Supply a normal address please." diff --git a/src/GWallet.Backend/FSharpUtil.fs b/src/GWallet.Backend/FSharpUtil.fs index 861d96678..2073665d4 100644 --- a/src/GWallet.Backend/FSharpUtil.fs +++ b/src/GWallet.Backend/FSharpUtil.fs @@ -1,9 +1,12 @@ namespace GWallet.Backend open System +open System.Linq open System.Threading.Tasks open System.Runtime.ExceptionServices +#if STRICTER_COMPILATION_BUT_WITH_REFLECTION_AT_RUNTIME open Microsoft.FSharp.Reflection +#endif type Result<'Val, 'Err when 'Err :> Exception> = | Error of 'Err @@ -11,6 +14,69 @@ type Result<'Val, 'Err when 'Err :> Exception> = module FSharpUtil = + module ReflectionlessPrint = + // TODO: support "%.2f" for digits precision, "%0i", and other special things: https://fsharpforfunandprofit.com/posts/printf/ + let ToStringFormat (fmt: string) = + let rec inner (innerFmt: string) (count: uint32) = + // TODO: support %e, %E, %g, %G, %o, %O, %x, %X, etc. see link above + let supportedFormats = [| "%s"; "%d"; "%i"; "%u"; "%M"; "%f"; "%b" ; "%A"; |] + let formatsFound = supportedFormats.Where(fun format -> innerFmt.IndexOf(format) >= 0) + if formatsFound.Any() then + let firstIndexWhereFormatFound = formatsFound.Min(fun format -> innerFmt.IndexOf(format)) + let firstFormat = + formatsFound.First(fun format -> innerFmt.IndexOf(format) = firstIndexWhereFormatFound) + let subEnd = innerFmt.IndexOf(firstFormat) + "%x".Length + let sub = innerFmt.Substring(0, subEnd) + let x = sub.Replace(firstFormat, "{" + count.ToString() + "}") + innerFmt.Substring(subEnd) + inner x (count+1u) + else + innerFmt + (inner fmt 0u).Replace("%%", "%") + + let SPrintF1 (fmt: string) (a: Object) = + String.Format(ToStringFormat fmt, a) + + let SPrintF2 (fmt: string) (a: Object) (b: Object) = + String.Format(ToStringFormat fmt, a, b) + + 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) = + String.Format(ToStringFormat fmt, a, b, c, d) + + let SPrintF5 (fmt: string) (a: Object) (b: Object) (c: Object) (d: Object) (e: Object) = + String.Format(ToStringFormat fmt, a, b, c, d, e) + + + module UwpHacks = +#if STRICTER_COMPILATION_BUT_WITH_REFLECTION_AT_RUNTIME + let SPrintF1 fmt a = sprintf fmt a + + let SPrintF2 fmt a b = sprintf fmt a b + + let SPrintF3 fmt a b c = sprintf fmt a b c + + let SPrintF4 fmt a b c d = sprintf fmt a b c d + + let SPrintF5 fmt a b c d e = sprintf fmt a b c d e +#else + let SPrintF1 (fmt: string) (a: Object) = + ReflectionlessPrint.SPrintF1 fmt a + + let SPrintF2 (fmt: string) (a: Object) (b: Object) = + ReflectionlessPrint.SPrintF2 fmt a b + + 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) = + ReflectionlessPrint.SPrintF4 fmt a b c d + + 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? @@ -159,6 +225,8 @@ module FSharpUtil = findExInSeq aggEx.InnerExceptions | _ -> FindException<'T>(ex.InnerException) + +#if STRICTER_COMPILATION_BUT_WITH_REFLECTION_AT_RUNTIME // http://stackoverflow.com/a/28466431/6503091 // will crash if 'T contains members which aren't only tags let Construct<'T> (caseInfo: UnionCaseInfo) = FSharpValue.MakeUnion(caseInfo, [||]) :?> 'T @@ -168,6 +236,7 @@ module FSharpUtil = let GetAllElementsFromDiscriminatedUnion<'T>() = FSharpType.GetUnionCases(typeof<'T>) |> Seq.map GetUnionCaseInfoAndInstance<'T> +#endif type OptionBuilder() = // see https://github.com/dsyme/fsharp-presentations/blob/master/design-notes/ces-compared.md#overview-of-f-computation-expressions diff --git a/src/GWallet.Backend/FaultTolerantParallelClient.fs b/src/GWallet.Backend/FaultTolerantParallelClient.fs index 0ed6e590f..5b3e1390a 100644 --- a/src/GWallet.Backend/FaultTolerantParallelClient.fs +++ b/src/GWallet.Backend/FaultTolerantParallelClient.fs @@ -6,6 +6,8 @@ open System.Diagnostics open System.Threading open System.Threading.Tasks +open GWallet.Backend.FSharpUtil.UwpHacks + type ResourceUnavailabilityException (message: string, innerOrLastException: Exception) = inherit Exception (message, innerOrLastException) @@ -25,7 +27,7 @@ type ResultInconsistencyException (totalNumberOfSuccesfulResultsObtained: int, maxNumberOfConsistentResultsObtained: int, numberOfConsistentResultsRequired: uint32) = inherit Exception ("Results obtained were not enough to be considered consistent" + - sprintf " (received: %d, consistent: %d, required: %d)" + SPrintF3 " (received: %i, consistent: %i, required: %i)" totalNumberOfSuccesfulResultsObtained maxNumberOfConsistentResultsObtained numberOfConsistentResultsRequired) @@ -155,7 +157,7 @@ type internal Runner<'Resource when 'Resource: equality> = match maybeSpecificEx with | Some specificInnerEx -> if report then - Infrastructure.LogError (sprintf "Cancellation fault warning: %s" + Infrastructure.LogError (SPrintF1 "Cancellation fault warning: %s" (ex.ToString())) return Error (specificInnerEx :> Exception) | None -> @@ -396,7 +398,7 @@ type FaultTolerantParallelClient<'K,'E when 'K: equality and 'K :> ICommunicatio return! returnWithConsistencyOf None None else - Infrastructure.LogDebug (sprintf "%f%% done (for this currency)" + Infrastructure.LogDebug (SPrintF1 "%f%% done (for this currency)" (100.*(float (newFailedFuncs.Length+newResults.Length))/(float initialServerCount))) return! WhenSomeInternal consistencySettings @@ -476,7 +478,7 @@ type FaultTolerantParallelClient<'K,'E when 'K: equality and 'K :> ICommunicatio with | AlreadyCanceled -> raise <| TaskCanceledException( - sprintf "Found canceled when about to subscribe to cancellation" + "Found canceled when about to subscribe to cancellation" ) cancelState.SafeDo (fun state -> match state.Value with diff --git a/src/GWallet.Backend/FiatValueEstimation.fs b/src/GWallet.Backend/FiatValueEstimation.fs index 3eec5b656..3f974fdee 100644 --- a/src/GWallet.Backend/FiatValueEstimation.fs +++ b/src/GWallet.Backend/FiatValueEstimation.fs @@ -5,6 +5,8 @@ open System.Net open FSharp.Data +open GWallet.Backend.FSharpUtil.UwpHacks + module FiatValueEstimation = let private PERIOD_TO_CONSIDER_PRICE_STILL_FRESH = TimeSpan.FromMinutes 2.0 @@ -42,9 +44,9 @@ module FiatValueEstimation = let baseUrl = match provider with | PriceProvider.CoinCap -> - sprintf "https://api.coincap.io/v2/rates/%s" tickerName + SPrintF1 "https://api.coincap.io/v2/rates/%s" tickerName | PriceProvider.CoinGecko -> - sprintf "https://api.coingecko.com/api/v3/simple/price?ids=%s&vs_currencies=usd" tickerName + SPrintF1 "https://api.coingecko.com/api/v3/simple/price?ids=%s&vs_currencies=usd" tickerName let uri = Uri baseUrl let task = webClient.DownloadStringTaskAsync uri let! res = Async.AwaitTask task @@ -80,10 +82,10 @@ module FiatValueEstimation = let parsedJsonObj = FSharp.Data.JsonValue.Parse json let usdPrice = match parsedJsonObj.TryGetProperty ticker with - | None -> failwithf "Could not pre-parse %s" json + | None -> failwith <| SPrintF1 "Could not pre-parse %s" json | Some innerObj -> match innerObj.TryGetProperty "usd" with - | None -> failwithf "Could not parse %s" json + | None -> failwith <| SPrintF1 "Could not parse %s" json | Some value -> value.AsDecimal() return Some usdPrice } diff --git a/src/GWallet.Backend/Formatting.fs b/src/GWallet.Backend/Formatting.fs index 1b504727d..179a31022 100644 --- a/src/GWallet.Backend/Formatting.fs +++ b/src/GWallet.Backend/Formatting.fs @@ -2,6 +2,8 @@ open System +open GWallet.Backend.FSharpUtil.UwpHacks + type CurrencyType = Fiat | Crypto @@ -16,10 +18,10 @@ module Formatting = match currencyType with | CurrencyType.Fiat -> let twoDecimals = 2 - twoDecimals,sprintf "N%d" twoDecimals + twoDecimals,SPrintF1 "N%i" twoDecimals | CurrencyType.Crypto -> let fiveDecimals = 5 - fiveDecimals,sprintf "#,0.%s" (String('#', fiveDecimals)) + fiveDecimals,SPrintF1 "#,0.%s" (String('#', fiveDecimals)) let rounded = Math.Round(amount, amountOfDecimalsToShow) @@ -38,6 +40,6 @@ module Formatting = // https://stackoverflow.com/a/25451689/544947 let truncated = amount - (amount % (1m / decimal (pown 10 amountOfDecimalsToShow))) if (truncated > maxAmount) then - failwithf "how can %s be higher than %s?" (truncated.ToString()) (maxAmount.ToString()) + failwith <| SPrintF2 "how can %s be higher than %s?" (truncated.ToString()) (maxAmount.ToString()) DecimalAmountRounding currencyType truncated diff --git a/src/GWallet.Backend/JsonRpcTcpClient.fs b/src/GWallet.Backend/JsonRpcTcpClient.fs index 88c14022e..7d3588c89 100644 --- a/src/GWallet.Backend/JsonRpcTcpClient.fs +++ b/src/GWallet.Backend/JsonRpcTcpClient.fs @@ -4,6 +4,8 @@ open System open System.Net open System.Net.Sockets +open GWallet.Backend.FSharpUtil.UwpHacks + type ProtocolGlitchException(message: string, innerException: Exception) = inherit CommunicationUnsuccessfulException (message, innerException) @@ -38,13 +40,13 @@ type JsonRpcTcpClient (host: string, port: uint32) = match ipAddressOption with | Some ipAddress -> if ipAddress.ToString().StartsWith("127.0.0.") then - let msg = sprintf "Server '%s' resolved to localhost IP '%s'" host (ipAddress.ToString()) + let msg = SPrintF2 "Server '%s' resolved to localhost IP '%s'" host (ipAddress.ToString()) return raise <| ServerNameResolvedToInvalidAddressException (msg) else return ipAddress | None -> return raise <| ServerCannotBeResolvedException - (sprintf "DNS host entry lookup resulted in no records for %s" host) - | None -> return raise <| TimeoutException (sprintf "Timed out connecting to %s:%i" host port) + (SPrintF1 "DNS host entry lookup resulted in no records for %s" host) + | None -> return raise <| TimeoutException (SPrintF2 "Timed out connecting to %s:%i" host port) with | :? TimeoutException -> return raise(ServerCannotBeResolvedException(exceptionMsg)) diff --git a/src/GWallet.Backend/Marshalling.fs b/src/GWallet.Backend/Marshalling.fs index c52615715..66186166a 100644 --- a/src/GWallet.Backend/Marshalling.fs +++ b/src/GWallet.Backend/Marshalling.fs @@ -7,6 +7,8 @@ open System.Text.RegularExpressions open Newtonsoft.Json open Newtonsoft.Json.Serialization +open GWallet.Backend.FSharpUtil.UwpHacks + type DeserializationException = inherit Exception @@ -105,17 +107,17 @@ module Marshalling = let endVersionIndex = jsonSinceVersion.IndexOf("\"") let version = jsonSinceVersion.Substring(0, endVersionIndex) if (version <> currentVersion) then - let msg = sprintf "Incompatible marshalling version found (%s vs. current %s) while trying to deserialize JSON" + let msg = SPrintF2 "Incompatible marshalling version found (%s vs. current %s) while trying to deserialize JSON" version currentVersion raise <| VersionMismatchDuringDeserializationException(msg, ex) - raise <| DeserializationException(sprintf "Exception when trying to deserialize '%s'" json, ex) + raise <| DeserializationException(SPrintF1 "Exception when trying to deserialize '%s'" json, ex) if Object.ReferenceEquals(deserialized, null) then - raise <| DeserializationException(sprintf "JsonConvert.DeserializeObject returned null when trying to deserialize '%s'" + raise <| DeserializationException(SPrintF1 "JsonConvert.DeserializeObject returned null when trying to deserialize '%s'" json) if Object.ReferenceEquals(deserialized.Value, null) then - raise <| DeserializationException(sprintf "JsonConvert.DeserializeObject could not deserialize the Value member of '%s'" + raise <| DeserializationException(SPrintF1 "JsonConvert.DeserializeObject could not deserialize the Value member of '%s'" json) deserialized.Value @@ -132,7 +134,7 @@ module Marshalling = SerializeInternal value settings with | exn -> - raise(SerializationException(sprintf "Could not serialize object of type '%s' and value '%A'" + raise (SerializationException(SPrintF2 "Could not serialize object of type '%s' and value '%A'" (typeof<'T>.FullName) value, exn)) let Serialize<'T>(value: 'T): string = diff --git a/src/GWallet.Backend/Networking.fs b/src/GWallet.Backend/Networking.fs index 302b33170..b2bbfc22e 100644 --- a/src/GWallet.Backend/Networking.fs +++ b/src/GWallet.Backend/Networking.fs @@ -4,6 +4,8 @@ open System open System.Net open System.Net.Sockets +open GWallet.Backend.FSharpUtil.UwpHacks + // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#Cloudflare type CloudFlareError = | ConnectionTimeOut = 522 @@ -15,7 +17,7 @@ type internal UnhandledSocketException = inherit Exception new(socketErrorCode: int, innerException: Exception) = - { inherit Exception(sprintf "Backend not prepared for this SocketException with ErrorCode[%d]" socketErrorCode, + { inherit Exception(SPrintF1 "Backend not prepared for this SocketException with ErrorCode[%i]" socketErrorCode, innerException) } type CommunicationUnsuccessfulException = @@ -54,12 +56,12 @@ type ServerUnreachableException = } new(message: string, httpStatusCode: HttpStatusCode, innerException: Exception) = { - inherit CommunicationUnsuccessfulException(sprintf "%s (HttpErr: %s)" message (httpStatusCode.ToString()), + inherit CommunicationUnsuccessfulException(SPrintF2 "%s (HttpErr: %s)" message (httpStatusCode.ToString()), innerException) } new(message: string, cloudFlareError: CloudFlareError, innerException: Exception) = { - inherit CommunicationUnsuccessfulException(sprintf "%s (CfErr: %s)" message (cloudFlareError.ToString()), + inherit CommunicationUnsuccessfulException(SPrintF2 "%s (CfErr: %s)" message (cloudFlareError.ToString()), innerException) } diff --git a/src/GWallet.Backend/ServerManager.fs b/src/GWallet.Backend/ServerManager.fs index cf5ee533c..a132da498 100644 --- a/src/GWallet.Backend/ServerManager.fs +++ b/src/GWallet.Backend/ServerManager.fs @@ -4,6 +4,8 @@ open System open System.IO open System.Linq +open GWallet.Backend.FSharpUtil.UwpHacks + module ServerManager = let UpdateServersFile () = @@ -33,7 +35,7 @@ module ServerManager = | true,baseLineBtcServers -> baseLineBtcServers | false,_ -> - failwithf "There should be some %A servers as baseline" btc + failwith <| SPrintF1 "There should be some %A servers as baseline" btc let allBtcServers = Seq.append electrumBtcServers eyeBtcServers |> Seq.map fromElectrumServerToGenericServerDetails @@ -48,22 +50,22 @@ module ServerManager = | true,baseLineLtcServers -> baseLineLtcServers | false,_ -> - failwithf "There should be some %A servers as baseline" ltc + failwith <| SPrintF1 "There should be some %A servers as baseline" ltc let allLtcServers = Seq.append electrumLtcServers eyeLtcServers |> Seq.map fromElectrumServerToGenericServerDetails |> Seq.append baseLineLtcServers for KeyValue(currency,servers) in baseLineServers do - Infrastructure.LogInfo (sprintf "%i %A servers from baseline JSON file" (servers.Count()) currency) + Infrastructure.LogInfo (SPrintF2 "%i %A servers from baseline JSON file" (servers.Count()) currency) match currency with | Currency.BTC -> - Infrastructure.LogInfo (sprintf "%i BTC servers from electrum repository" (electrumBtcServers.Count())) - Infrastructure.LogInfo (sprintf "%i BTC servers from bitcoin-eye" (eyeBtcServers.Count())) + Infrastructure.LogInfo (SPrintF1 "%i BTC servers from electrum repository" (electrumBtcServers.Count())) + Infrastructure.LogInfo (SPrintF1 "%i BTC servers from bitcoin-eye" (eyeBtcServers.Count())) | Currency.LTC -> - Infrastructure.LogInfo (sprintf "%i LTC servers from electrum repository" (electrumLtcServers.Count())) - Infrastructure.LogInfo (sprintf "%i LTC servers from bitcoin-eye" (eyeLtcServers.Count())) + Infrastructure.LogInfo (SPrintF1 "%i LTC servers from electrum repository" (electrumLtcServers.Count())) + Infrastructure.LogInfo (SPrintF1 "%i LTC servers from bitcoin-eye" (eyeLtcServers.Count())) | _ -> () @@ -77,7 +79,7 @@ module ServerManager = Infrastructure.LogInfo "OUTPUT:" let filteredOutServers = ServerRegistry.Deserialize allServersJson for KeyValue(currency,servers) in filteredOutServers do - Infrastructure.LogInfo (sprintf "%i %A servers total" (servers.Count()) currency) + Infrastructure.LogInfo (SPrintF2 "%i %A servers total" (servers.Count()) currency) let private tester = FaultTolerantParallelClient @@ -112,7 +114,7 @@ module ServerManager = let LTC_GENESIS_BLOCK_ADDRESS = "Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2" UtxoCoin.Account.GetElectrumScriptHashFromPublicAddress currency LTC_GENESIS_BLOCK_ADDRESS | _ -> - failwithf "Currency %A not UTXO?" currency + failwith <| SPrintF1 "Currency %A not UTXO?" currency let utxoFunc electrumServer = async { let! bal = UtxoCoin.ElectrumClient.GetBalance scriptHash electrumServer diff --git a/src/GWallet.Backend/UtxoCoin/ElectrumClient.fs b/src/GWallet.Backend/UtxoCoin/ElectrumClient.fs index 57b9b9533..6fc31f3c4 100644 --- a/src/GWallet.Backend/UtxoCoin/ElectrumClient.fs +++ b/src/GWallet.Backend/UtxoCoin/ElectrumClient.fs @@ -3,6 +3,7 @@ open System open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks module ElectrumClient = @@ -32,12 +33,12 @@ module ElectrumClient = 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(sprintf "Version of server rejects our client version (%s)" - (PROTOCOL_VERSION_SUPPORTED.ToString()))) + raise <| ServerTooNewException(SPrintF1 "Version of server rejects our client version (%s)" + (PROTOCOL_VERSION_SUPPORTED.ToString())) else reraise() if versionSupportedByServer < PROTOCOL_VERSION_SUPPORTED then - raise (ServerTooOldException (sprintf "Version of server is older (%s) than the client (%s)" + raise (ServerTooOldException (SPrintF2 "Version of server is older (%s) than the client (%s)" (versionSupportedByServer.ToString()) (PROTOCOL_VERSION_SUPPORTED.ToString()))) return stratumClient diff --git a/src/GWallet.Backend/UtxoCoin/ElectrumServer.fs b/src/GWallet.Backend/UtxoCoin/ElectrumServer.fs index d6bbb6256..5a3700d2d 100644 --- a/src/GWallet.Backend/UtxoCoin/ElectrumServer.fs +++ b/src/GWallet.Backend/UtxoCoin/ElectrumServer.fs @@ -8,6 +8,7 @@ open FSharp.Data.JsonExtensions open HtmlAgilityPack open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks type IncompatibleServerException(message) = inherit CommunicationUnsuccessfulException(message) @@ -56,9 +57,9 @@ module ElectrumServerSeedList = match currency with | Currency.BTC -> "btc" | Currency.LTC -> "ltc" - | _ -> failwithf "UTXO currency unknown to this algorithm: %A" currency + | _ -> failwith <| SPrintF1 "UTXO currency unknown to this algorithm: %A" currency - let url = sprintf "https://1209k.com/bitcoin-eye/ele.php?chain=%s" currencyMnemonic + let url = SPrintF1 "https://1209k.com/bitcoin-eye/ele.php?chain=%s" currencyMnemonic let web = HtmlWeb() let doc = web.Load url let firstTable = doc.DocumentNode.SelectNodes("//table").[0] @@ -74,18 +75,18 @@ module ElectrumServerSeedList = let fqdn = serverProperties.[0].InnerText if serverProperties.Count < 2 then - failwithf "Unexpected property count in server %s: %i" fqdn serverProperties.Count + failwith <| SPrintF2 "Unexpected property count in server %s: %i" fqdn serverProperties.Count let port = UInt32.Parse serverProperties.[1].InnerText if serverProperties.Count < 3 then - failwithf "Unexpected property count in server %s:%i: %i" fqdn port serverProperties.Count + failwith <| SPrintF3 "Unexpected property count in server %s:%i: %i" fqdn port serverProperties.Count let portType = serverProperties.[2].InnerText let encrypted = match portType with | "ssl" -> true | "tcp" -> false - | _ -> failwithf "Got new unexpected port type: %s" portType + | _ -> failwith <| SPrintF1 "Got new unexpected port type: %s" portType let privatePort = if encrypted then Some port @@ -135,7 +136,7 @@ module ElectrumServerSeedList = match currency with | Currency.BTC -> "https://raw.githubusercontent.com/spesmilo/electrum/master/electrum/servers.json" | Currency.LTC -> "https://raw.githubusercontent.com/pooler/electrum-ltc/master/electrum_ltc/servers.json" - | _ -> failwithf "UTXO currency unknown to this algorithm: %A" currency + | _ -> failwith <| SPrintF1 "UTXO currency unknown to this algorithm: %A" currency use webClient = new WebClient() let serverListInJson = webClient.DownloadString urlToElectrumJsonFile @@ -155,5 +156,5 @@ module ElectrumServerSeedList = match currency with | BTC -> DefaultBtcList | LTC -> DefaultLtcList - | _ -> failwithf "Currency %A is not UTXO" currency + | _ -> failwith <| SPrintF1 "Currency %A is not UTXO" currency Shuffler.Unsort serverList diff --git a/src/GWallet.Backend/UtxoCoin/StratumClient.fs b/src/GWallet.Backend/UtxoCoin/StratumClient.fs index cc44d5b03..e4fb8a812 100644 --- a/src/GWallet.Backend/UtxoCoin/StratumClient.fs +++ b/src/GWallet.Backend/UtxoCoin/StratumClient.fs @@ -5,6 +5,7 @@ open System open Newtonsoft.Json open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks // can't make this type below private, or else Newtonsoft.Json will serialize it incorrectly type Request = @@ -119,7 +120,7 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = // FIXME: we should actually fix this bug in JsonRpcSharp (https://github.com/nblockchain/JsonRpcSharp/issues/9) if String.IsNullOrEmpty rawResponse then - return failwithf "Server '%s' returned a null/empty JSON response to the request '%s'??" + return failwith <| SPrintF2 "Server '%s' returned a null/empty JSON response to the request '%s'??" jsonRpcClient.Host jsonRequest try @@ -145,7 +146,7 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = JsonConvert.DeserializeObject(resultTrimmed, Marshalling.PascalCase2LowercasePlusUnderscoreConversionSettings) with - | ex -> raise <| Exception(sprintf "Failed deserializing JSON response (to check for error) '%s' to type '%s'" + | ex -> raise <| Exception(SPrintF2 "Failed deserializing JSON response (to check for error) '%s' to type '%s'" resultTrimmed typedefof<'T>.FullName, ex) if (not (Object.ReferenceEquals(maybeError, null))) && (not (Object.ReferenceEquals(maybeError.Error, null))) then @@ -156,11 +157,11 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = JsonConvert.DeserializeObject<'T>(resultTrimmed, Marshalling.PascalCase2LowercasePlusUnderscoreConversionSettings) with - | ex -> raise <| Exception(sprintf "Failed deserializing JSON response '%s' to type '%s'" + | ex -> raise <| Exception(SPrintF2 "Failed deserializing JSON response '%s' to type '%s'" resultTrimmed typedefof<'T>.FullName, ex) if Object.ReferenceEquals(deserializedValue, null) then - failwithf "Failed deserializing JSON response '%s' to type '%s' (result was null)" + failwith <| SPrintF2 "Failed deserializing JSON response '%s' to type '%s' (result was null)" resultTrimmed typedefof<'T>.FullName deserializedValue @@ -196,16 +197,16 @@ type StratumClient (jsonRpcClient: JsonRpcTcpClient) = Params = [clientName; protocolVersion.ToString()] } // this below serializes to: - // (sprintf "{ \"id\": 0, \"method\": \"server.version\", \"params\": [ \"%s\", \"%s\" ] }" + // (SPrintF2 "{ \"id\": 0, \"method\": \"server.version\", \"params\": [ \"%s\", \"%s\" ] }" // CURRENT_ELECTRUM_FAKED_VERSION PROTOCOL_VERSION) let json = Serialize obj let! resObj, rawResponse = self.Request json if Object.ReferenceEquals (resObj, null) then - failwithf "resObj is null?? raw response was %s" rawResponse + failwith <| SPrintF1 "resObj is null?? raw response was %s" rawResponse if Object.ReferenceEquals (resObj.Result, null) then - failwithf "resObj.Result is null?? raw response was %s" rawResponse + failwith <| SPrintF1 "resObj.Result is null?? raw response was %s" rawResponse // resObj.Result.[0] is e.g. "ElectrumX 1.4.3" // e.g. "1.1" diff --git a/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs b/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs index 48357fa1d..8aa3bc82e 100644 --- a/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs +++ b/src/GWallet.Backend/UtxoCoin/UtxoCoinAccount.fs @@ -10,6 +10,7 @@ open System.Linq open NBitcoin open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks type internal TransactionOutpoint = { @@ -53,11 +54,11 @@ module Account = let internal GetNetwork (currency: Currency) = if not (currency.IsUtxo()) then - failwithf "Assertion failed: currency %A should be UTXO-type" currency + failwith <| SPrintF1 "Assertion failed: currency %A should be UTXO-type" currency match currency with | BTC -> Config.BitcoinNet | LTC -> Config.LitecoinNet - | _ -> failwithf "Assertion failed: UTXO currency %A not supported?" currency + | _ -> failwith <| SPrintF1 "Assertion failed: UTXO currency %A not supported?" currency // technique taken from https://electrumx.readthedocs.io/en/latest/protocol-basics.html#script-hashes let private GetElectrumScriptHashFromAddress (address: BitcoinAddress): string = @@ -239,7 +240,7 @@ module Account = match utxos with | [] -> // should `raise InsufficientFunds` instead? - failwithf "Not enough funds (needed: %s, got so far: %s)" + failwith <| SPrintF2 "Not enough funds (needed: %s, got so far: %s)" (amount.ToString()) (soFarInSatoshis.ToString()) | utxoInfo::tail -> let newAcc = @@ -300,8 +301,8 @@ module Account = Money(btcPerKiloByteForFastTrans, MoneyUnit.BTC) |> FeeRate with | ex -> - // we need more info in case this bug shows again: https://gitlab.com/DiginexGlobal/geewallet/issues/43 - raise <| Exception(sprintf "Could not create fee rate from %s btc per KB" + // we need more info in case this bug shows again: https://gitlab.com/knocte/geewallet/issues/43 + raise <| Exception(SPrintF1 "Could not create fee rate from %s btc per KB" (btcPerKiloByteForFastTrans.ToString()), ex) let transactionBuilder = CreateTransactionAndCoinsToBeSigned account @@ -338,7 +339,7 @@ module Account = let finalTransaction = finalTransactionBuilder.BuildTransaction true let transCheckResultAfterSigning = finalTransaction.Check() if (transCheckResultAfterSigning <> TransactionCheckResult.Success) then - failwithf "Transaction check failed after signing with %A" transCheckResultAfterSigning + failwith <| SPrintF1 "Transaction check failed after signing with %A" transCheckResultAfterSigning if not (finalTransactionBuilder.Verify finalTransaction) then failwith "Something went wrong when verifying transaction" @@ -458,7 +459,7 @@ module Account = let LITECOIN_ADDRESS_PUBKEYHASH_PREFIX = "L" let LITECOIN_ADDRESS_SCRIPTHASH_PREFIX = "M" [ LITECOIN_ADDRESS_PUBKEYHASH_PREFIX; LITECOIN_ADDRESS_SCRIPTHASH_PREFIX ] - | _ -> failwithf "Unknown UTXO currency %A" currency + | _ -> failwith <| SPrintF1 "Unknown UTXO currency %A" currency if not (utxoCoinValidAddressPrefixes.Any(fun prefix -> address.StartsWith prefix)) then raise (AddressMissingProperPrefix(utxoCoinValidAddressPrefixes)) diff --git a/src/GWallet.Backend/UtxoCoin/UtxoCoinServer.fs b/src/GWallet.Backend/UtxoCoin/UtxoCoinServer.fs index 6951bc2db..f75b9ed47 100644 --- a/src/GWallet.Backend/UtxoCoin/UtxoCoinServer.fs +++ b/src/GWallet.Backend/UtxoCoin/UtxoCoinServer.fs @@ -6,6 +6,7 @@ open System open GWallet.Backend +open GWallet.Backend.FSharpUtil.UwpHacks type QuerySettings<'R> = | Default of mode: ServerSelectionMode @@ -73,10 +74,11 @@ module Server = // NOTE: try to make this 'with' block be in sync with the one in EtherServer:GetWeb3Funcs() with | :? CommunicationUnsuccessfulException as ex -> - let msg = sprintf "%s: %s" (ex.GetType().FullName) ex.Message + let msg = SPrintF2 "%s: %s" (ex.GetType().FullName) ex.Message return raise <| ServerDiscardedException(msg, ex) | ex -> - return raise <| Exception(sprintf "Some problem when connecting to %s" server.ServerInfo.NetworkPath, ex) + return raise <| Exception(SPrintF1 "Some problem when connecting to %s" server.ServerInfo.NetworkPath, + ex) } let ElectrumServerToGenericServer (electrumClientFunc: Async->Async<'R>) (electrumServer: ServerDetails) diff --git a/src/GWallet.Backend/WarpKey.fs b/src/GWallet.Backend/WarpKey.fs index a30ee9c86..7786aa71c 100644 --- a/src/GWallet.Backend/WarpKey.fs +++ b/src/GWallet.Backend/WarpKey.fs @@ -7,6 +7,8 @@ open System open System.Text open System.Security.Cryptography +open GWallet.Backend.FSharpUtil.UwpHacks + // .NET implementation for WarpWallet: https://keybase.io/warp/ module WarpKey = @@ -54,7 +56,7 @@ module WarpKey = let pbkdf2 = PBKDF2 passphrase salt let privKeyBytes = XOR scrypt pbkdf2 if (privKeyBytes.Length <> LENGTH_OF_PRIVATE_KEYS) then - failwithf "Something went horribly wrong because length of privKey was not %d but %d" + failwith <| SPrintF2 "Something went horribly wrong because length of privKey was not %i but %i" LENGTH_OF_PRIVATE_KEYS privKeyBytes.Length privKeyBytes