diff --git a/src/GWallet.Backend.Tests/Deserialization.fs b/src/GWallet.Backend.Tests/Deserialization.fs index a7b7866e6..1d7a1f535 100644 --- a/src/GWallet.Backend.Tests/Deserialization.fs +++ b/src/GWallet.Backend.Tests/Deserialization.fs @@ -10,11 +10,15 @@ open GWallet.Backend.UtxoCoin [] type Deserialization() = + [] + member __.``Versioning works``() = + MarshallingData.AssertAssemblyVersion() + [] member __.``deserialize cache does not fail``() = let deserializedCache: DietCache = Marshalling.Deserialize - MarshallingData.SofisticatedCachingDataExampleInJson + MarshallingData.SophisticatedCachingDataExampleInJson Assert.That(deserializedCache, Is.Not.Null) diff --git a/src/GWallet.Backend.Tests/GWallet.Backend.Tests.fsproj b/src/GWallet.Backend.Tests/GWallet.Backend.Tests.fsproj index 7407d1b20..a61297f78 100644 --- a/src/GWallet.Backend.Tests/GWallet.Backend.Tests.fsproj +++ b/src/GWallet.Backend.Tests/GWallet.Backend.Tests.fsproj @@ -23,6 +23,7 @@ + diff --git a/src/GWallet.Backend.Tests/MarshallingData.fs b/src/GWallet.Backend.Tests/MarshallingData.fs index e8f27c0cf..90e1e6a37 100644 --- a/src/GWallet.Backend.Tests/MarshallingData.fs +++ b/src/GWallet.Backend.Tests/MarshallingData.fs @@ -175,9 +175,9 @@ module MarshallingData = .Add("0xFOOBARBAZ", [Currency.ETC.ToString()]) let private fiatValues = Map.empty.Add(Currency.ETH.ToString(), 161.796m) .Add(Currency.ETC.ToString(), 169.99999999m) - let SofisticatedCachingDataExample = { UsdPrice = fiatValues; Addresses = addresses; Balances = balances; } + let SophisticatedCachingDataExample = { UsdPrice = fiatValues; Addresses = addresses; Balances = balances; } - let SofisticatedCachingDataExampleInJson = + let SophisticatedCachingDataExampleInJson = sprintf """{ "Version": "%s", "TypeName": "%s", @@ -312,7 +312,7 @@ module MarshallingData = let someEtherTransactionInfo = { Proposal = someUnsignedEtherTransactionProposal; - Cache = SofisticatedCachingDataExample; + Cache = SophisticatedCachingDataExample Metadata = someEtherTxMetadata; } let SignedEtherTransactionExample = @@ -325,3 +325,11 @@ module MarshallingData = let UnsignedEtherTransactionExampleInJson = ReadEmbeddedResource "unsignedAndFormattedEtherTransaction.json" + + let AssertAssemblyVersion() = + Assert.That( + VersionHelper.CURRENT_VERSION, + Is.Not.EqualTo "1.0.0.0", + "Proper version was somehow not properly assigned as assembly version" + ) + diff --git a/src/GWallet.Backend.Tests/MetaMarshalling.fs b/src/GWallet.Backend.Tests/MetaMarshalling.fs new file mode 100644 index 000000000..eb60590b8 --- /dev/null +++ b/src/GWallet.Backend.Tests/MetaMarshalling.fs @@ -0,0 +1,23 @@ +namespace GWallet.Backend.Tests + +open NUnit.Framework + +open GWallet.Backend + +[] +type MetaMarshalling() = + + [] + member __.``wrapper's TypeName property doesn't contain assembly-qualified-name``() = + let json = Marshalling.Serialize MarshallingData.SignedBtcTransactionExample + Assert.That(json, Is.Not.Null) + Assert.That(json, Is.Not.Empty) + + let wrapper = Marshalling.ExtractWrapper json + Assert.That(wrapper, Is.Not.Null) + Assert.That(wrapper.TypeName, Is.Not.Null) + Assert.That(wrapper.TypeName, Is.Not.Empty) + Assert.That(wrapper.Version, Is.Not.Null) + Assert.That(wrapper.Version, Is.Not.Empty) + + Assert.That(wrapper.TypeName, Does.Not.Contain "Version=") diff --git a/src/GWallet.Backend.Tests/Serialization.fs b/src/GWallet.Backend.Tests/Serialization.fs index afc048db4..9a4aeb861 100644 --- a/src/GWallet.Backend.Tests/Serialization.fs +++ b/src/GWallet.Backend.Tests/Serialization.fs @@ -8,6 +8,11 @@ open GWallet.Backend [] type Serialization() = + + [] + member __.``Versioning works``() = + MarshallingData.AssertAssemblyVersion() + [] member __.``basic caching export does not fail``() = let json = Marshalling.Serialize MarshallingData.EmptyCachingDataExample @@ -24,12 +29,12 @@ type Serialization() = [] member __.``complex caching export works``() = - let json = Marshalling.Serialize MarshallingData.SofisticatedCachingDataExample + let json = Marshalling.Serialize MarshallingData.SophisticatedCachingDataExample Assert.That(json, Is.Not.Null) Assert.That(json, Is.Not.Empty) Assert.That(json, - Is.EqualTo (MarshallingData.SofisticatedCachingDataExampleInJson)) + Is.EqualTo (MarshallingData.SophisticatedCachingDataExampleInJson)) [] member __.``unsigned BTC transaction export``() = diff --git a/src/GWallet.Backend.Tests/data/signedAndFormattedBtcTransaction.json b/src/GWallet.Backend.Tests/data/signedAndFormattedBtcTransaction.json index d9ad44b3a..05ec34f6b 100644 --- a/src/GWallet.Backend.Tests/data/signedAndFormattedBtcTransaction.json +++ b/src/GWallet.Backend.Tests/data/signedAndFormattedBtcTransaction.json @@ -1,6 +1,6 @@ { "Version": "{version}", - "TypeName": "GWallet.Backend.SignedTransaction`1[[GWallet.Backend.UtxoCoin.TransactionMetadata, GWallet.Backend, Version={version}, Culture=neutral, PublicKeyToken=null]]", + "TypeName": "GWallet.Backend.SignedTransaction`1[GWallet.Backend.UtxoCoin.TransactionMetadata]", "Value": { "TransactionInfo": { "Proposal": { diff --git a/src/GWallet.Backend.Tests/data/signedAndFormattedEtherTransaction.json b/src/GWallet.Backend.Tests/data/signedAndFormattedEtherTransaction.json index 401148db1..68b8e4e3c 100644 --- a/src/GWallet.Backend.Tests/data/signedAndFormattedEtherTransaction.json +++ b/src/GWallet.Backend.Tests/data/signedAndFormattedEtherTransaction.json @@ -1,6 +1,6 @@ { "Version": "{version}", - "TypeName": "GWallet.Backend.SignedTransaction`1[[GWallet.Backend.Ether.TransactionMetadata, GWallet.Backend, Version={version}, Culture=neutral, PublicKeyToken=null]]", + "TypeName": "GWallet.Backend.SignedTransaction`1[GWallet.Backend.Ether.TransactionMetadata]", "Value": { "TransactionInfo": { "Proposal": { diff --git a/src/GWallet.Backend.Tests/data/signedAndFormattedSaiTransaction.json b/src/GWallet.Backend.Tests/data/signedAndFormattedSaiTransaction.json index 0dd6bfab1..70e6e14c1 100644 --- a/src/GWallet.Backend.Tests/data/signedAndFormattedSaiTransaction.json +++ b/src/GWallet.Backend.Tests/data/signedAndFormattedSaiTransaction.json @@ -1,6 +1,6 @@ { "Version": "{version}", - "TypeName": "GWallet.Backend.SignedTransaction`1[[GWallet.Backend.Ether.TransactionMetadata, GWallet.Backend, Version={version}, Culture=neutral, PublicKeyToken=null]]", + "TypeName": "GWallet.Backend.SignedTransaction`1[GWallet.Backend.Ether.TransactionMetadata]", "Value": { "TransactionInfo": { "Proposal": { diff --git a/src/GWallet.Backend.Tests/data/unsignedAndFormattedBtcTransaction.json b/src/GWallet.Backend.Tests/data/unsignedAndFormattedBtcTransaction.json index ded175992..35781105e 100644 --- a/src/GWallet.Backend.Tests/data/unsignedAndFormattedBtcTransaction.json +++ b/src/GWallet.Backend.Tests/data/unsignedAndFormattedBtcTransaction.json @@ -1,6 +1,6 @@ { "Version": "{version}", - "TypeName": "GWallet.Backend.UnsignedTransaction`1[[GWallet.Backend.UtxoCoin.TransactionMetadata, GWallet.Backend, Version={version}, Culture=neutral, PublicKeyToken=null]]", + "TypeName": "GWallet.Backend.UnsignedTransaction`1[GWallet.Backend.UtxoCoin.TransactionMetadata]", "Value": { "Proposal": { "OriginAddress": "16pKBjGGZkUXo1afyBNf5ttFvV9hauS1kR", diff --git a/src/GWallet.Backend.Tests/data/unsignedAndFormattedEtherTransaction.json b/src/GWallet.Backend.Tests/data/unsignedAndFormattedEtherTransaction.json index 983317930..e7ac16878 100644 --- a/src/GWallet.Backend.Tests/data/unsignedAndFormattedEtherTransaction.json +++ b/src/GWallet.Backend.Tests/data/unsignedAndFormattedEtherTransaction.json @@ -1,6 +1,6 @@ { "Version": "{version}", - "TypeName": "GWallet.Backend.UnsignedTransaction`1[[GWallet.Backend.Ether.TransactionMetadata, GWallet.Backend, Version={version}, Culture=neutral, PublicKeyToken=null]]", + "TypeName": "GWallet.Backend.UnsignedTransaction`1[GWallet.Backend.Ether.TransactionMetadata]", "Value": { "Proposal": { "OriginAddress": "0xf3j4m0rjx94sushh03j", diff --git a/src/GWallet.Backend.Tests/data/unsignedAndFormattedSaiTransaction.json b/src/GWallet.Backend.Tests/data/unsignedAndFormattedSaiTransaction.json index b79f0c8ed..3b3e067c2 100644 --- a/src/GWallet.Backend.Tests/data/unsignedAndFormattedSaiTransaction.json +++ b/src/GWallet.Backend.Tests/data/unsignedAndFormattedSaiTransaction.json @@ -1,6 +1,6 @@ { "Version": "{version}", - "TypeName": "GWallet.Backend.UnsignedTransaction`1[[GWallet.Backend.Ether.TransactionMetadata, GWallet.Backend, Version={version}, Culture=neutral, PublicKeyToken=null]]", + "TypeName": "GWallet.Backend.UnsignedTransaction`1[GWallet.Backend.Ether.TransactionMetadata]", "Value": { "Proposal": { "OriginAddress": "0xba766d6d13E2Cc921Bf6e896319D32502af9e37E", diff --git a/src/GWallet.Backend/Account.fs b/src/GWallet.Backend/Account.fs index a2b006f1a..9243bc17a 100644 --- a/src/GWallet.Backend/Account.fs +++ b/src/GWallet.Backend/Account.fs @@ -714,13 +714,13 @@ module Account = match transType with | _ when transType = typeof> -> - let deserializedBtcTransaction: SignedTransaction = + let deserializedTransaction: SignedTransaction = Marshalling.Deserialize json - deserializedBtcTransaction.ToAbstract() + deserializedTransaction.ToAbstract() | _ when transType = typeof> -> - let deserializedBtcTransaction: SignedTransaction = + let deserializedTransaction: SignedTransaction = Marshalling.Deserialize json - deserializedBtcTransaction.ToAbstract() + deserializedTransaction.ToAbstract() | _ when transType.GetGenericTypeDefinition() = typedefof> -> raise TransactionNotSignedYet | unexpectedType -> diff --git a/src/GWallet.Backend/BlockExplorer.fs b/src/GWallet.Backend/BlockExplorer.fs index 81fd08b97..9f63decf4 100644 --- a/src/GWallet.Backend/BlockExplorer.fs +++ b/src/GWallet.Backend/BlockExplorer.fs @@ -14,8 +14,7 @@ module BlockExplorer = | Currency.BTC -> "https://mempool.space/address/" | Currency.LTC -> - // because the more popular https://live.blockcypher.com/ltc/ doesn't seem to have segwit support - "https://chainz.cryptoid.info/ltc/address.dws?" + "https://litecoinspace.org/address/" | Currency.ETH -> // most popular one... "https://etherscan.io/address/" @@ -32,7 +31,7 @@ module BlockExplorer = | Currency.BTC -> "https://mempool.space/tx/" | Currency.LTC -> - "https://chainz.cryptoid.info/ltc/tx.dws?" + "https://litecoinspace.org/tx/" | Currency.ETH -> "https://etherscan.io/tx/" | Currency.ETC -> diff --git a/src/GWallet.Backend/Ether/EtherExceptions.fs b/src/GWallet.Backend/Ether/EtherExceptions.fs index 7bb36b17f..a08d73033 100644 --- a/src/GWallet.Backend/Ether/EtherExceptions.fs +++ b/src/GWallet.Backend/Ether/EtherExceptions.fs @@ -32,6 +32,7 @@ type RpcErrorCode = | DailyRequestCountExceededSoRequestRateLimited = -32005 | CannotFulfillRequest = -32046 | ResourceNotFound = -32001 + | InternalError = -32603 type ServerCannotBeResolvedException = inherit CommunicationUnsuccessfulException diff --git a/src/GWallet.Backend/Ether/EtherServer.fs b/src/GWallet.Backend/Ether/EtherServer.fs index e755a1bb3..a8989d85e 100644 --- a/src/GWallet.Backend/Ether/EtherServer.fs +++ b/src/GWallet.Backend/Ether/EtherServer.fs @@ -231,6 +231,8 @@ module Server = raise <| ServerRefusedException(exMsg, rpcResponseEx) | h when h = int RpcErrorCode.ResourceNotFound -> raise <| ServerMisconfiguredException(exMsg, rpcResponseEx) + | i when i = int RpcErrorCode.InternalError -> + raise <| ServerFaultException(exMsg, rpcResponseEx) | _ -> raise <| Exception (SPrintF3 "RpcResponseException with RpcError Code <%i> and Message '%s' (%s)" diff --git a/src/GWallet.Backend/Marshalling.fs b/src/GWallet.Backend/Marshalling.fs index 17836fc7a..47ab70c10 100644 --- a/src/GWallet.Backend/Marshalling.fs +++ b/src/GWallet.Backend/Marshalling.fs @@ -97,7 +97,7 @@ type MarshallingWrapper<'T> = { Value = value Version = VersionHelper.CURRENT_VERSION - TypeName = typeof<'T>.FullName + TypeName = typeof<'T>.ToString() } type private PascalCase2LowercasePlusUnderscoreContractResolver() = @@ -148,15 +148,46 @@ module Marshalling = let private currentVersion = VersionHelper.CURRENT_VERSION - let ExtractType(json: string): Type = + let ExtractWrapper(json: string): MarshallingWrapper = + if String.IsNullOrEmpty json then + raise <| ArgumentNullException "json" let wrapper = JsonConvert.DeserializeObject> json if Object.ReferenceEquals(wrapper, null) then failwith <| SPrintF1 "Failed to extract type from JSON (null check): %s" json - try - Type.GetType wrapper.TypeName - with - | :? NullReferenceException as _nre -> - failwith <| SPrintF1 "Failed to extract type from JSON (NRE): %s" json + if String.IsNullOrEmpty wrapper.TypeName then + failwith <| SPrintF1 "Failed to extract type from JSON (inner null check 1): %s" json + if String.IsNullOrEmpty wrapper.Version then + failwith <| SPrintF1 "Failed to extract type from JSON (inner null check 2): %s" json + wrapper + + let ExtractType(json: string): Type = + let wrapper = ExtractWrapper json + + let res = + try + // we prefer an ex with innerException than an NRE caused by the + // consumer of this function + let throwOnError = true + + Type.GetType(wrapper.TypeName, throwOnError) + with + | :? NullReferenceException as _nre -> + failwith + <| SPrintF1 "Failed to extract type from JSON (NRE): %s" json + | ex -> + let errMsg = + SPrintF2 "Problem when trying to find type '%s' (version '%s')" + wrapper.TypeName + wrapper.Version + raise <| Exception(errMsg, ex) + if isNull res then + failwith + <| SPrintF2 + "Could not find type '%s' (version '%s')" + wrapper.TypeName + wrapper.Version + res + // FIXME: should we rather use JContainer.Parse? it seems JObject.Parse wouldn't detect error in this: {A:{"B": 1}} // (for more info see replies of https://stackoverflow.com/questions/6903477/need-a-string-json-validator )