From dea6c39a58a04f866c054fc58ee8c899f44db18b Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 22 Jun 2021 20:58:13 -0700 Subject: [PATCH 01/53] update to my fork --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 379ec5f2..2db2f5a5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "Vendor/libmobilecoin-ios-artifacts"] path = Vendor/libmobilecoin-ios-artifacts - url = https://github.com/mobilecoinofficial/libmobilecoin-ios-artifacts.git + url = git@github.com:the-real-adammork/libmobilecoin-ios-artifacts.git shallow = true From fd82edb68897353ba6b931d945d60bd9627c4ea8 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 22 Jun 2021 21:09:13 -0700 Subject: [PATCH 02/53] use fork --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 2fc988be..933d01fe 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 2fc988beaf2cf51efb8bcf1bef99ce12e2a6e9b9 +Subproject commit 933d01fef2c39f639c9b0fa53f5f622a7f888eb2 From 87a78ca5c16e2a5b11a8e46863e50556b98baef1 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 22 Jun 2021 21:54:57 -0700 Subject: [PATCH 03/53] update MrEnclave values --- Tests/Common/Fixtures/Network/NetworkPreset.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/Common/Fixtures/Network/NetworkPreset.swift b/Tests/Common/Fixtures/Network/NetworkPreset.swift index dd486cfc..87bb4f05 100644 --- a/Tests/Common/Fixtures/Network/NetworkPreset.swift +++ b/Tests/Common/Fixtures/Network/NetworkPreset.swift @@ -133,13 +133,13 @@ extension NetworkPreset { "709ab90621e3a8d9eb26ed9e2830e091beceebd55fb01c5d7c31d27e83b9b0d1" private static let testNetConsensusMrEnclaveHex = - "9268c3220a5260e51e4b586f00e4677fed2b80380f1eeaf775af60f8e880fde8" + "9659ea738275b3999bf1700398b60281be03af5cb399738a89b49ea2496595af" private static let testNetFogViewMrEnclaveHex = - "4e598799faa4bb08a3bd55c0bcda7e1d22e41151d0c591f6c2a48b3562b0881e" + "e154f108c7758b5aa7161c3824c176f0c20f63012463bf3cc5651e678f02fb9e" private static let testNetFogLedgerMrEnclaveHex = - "7330c9987f21b91313b39dcdeaa7da8da5ca101c929f5740c207742c762e6dcd" + "768f7bea6171fb83d775ee8485e4b5fcebf5f664ca7e8b9ceef9c7c21e9d9bf3" private static let testNetFogReportMrEnclaveHex = - "185875464ccd67a879d58181055383505a719b364b12d56d9bef90a40bed07ca" + "a4764346f91979b4906d4ce26102228efe3aba39216dec1e7d22e6b06f919f11" private static let devMrSignerHex = "7ee5e29d74623fdbc6fbf1454be6f3bb0b86c12366b7b478ad13353e44de8411" From f199ada7b46ad2c1486d2c7f6d676010e61a2c4f Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Wed, 23 Jun 2021 12:52:45 -0700 Subject: [PATCH 04/53] update gitmodules to my forks, update mrEnclave values --- .gitmodules | 2 +- Tests/Common/Fixtures/Network/NetworkPreset.swift | 8 ++++---- Vendor/libmobilecoin-ios-artifacts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitmodules b/.gitmodules index 379ec5f2..2db2f5a5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "Vendor/libmobilecoin-ios-artifacts"] path = Vendor/libmobilecoin-ios-artifacts - url = https://github.com/mobilecoinofficial/libmobilecoin-ios-artifacts.git + url = git@github.com:the-real-adammork/libmobilecoin-ios-artifacts.git shallow = true diff --git a/Tests/Common/Fixtures/Network/NetworkPreset.swift b/Tests/Common/Fixtures/Network/NetworkPreset.swift index dd486cfc..87bb4f05 100644 --- a/Tests/Common/Fixtures/Network/NetworkPreset.swift +++ b/Tests/Common/Fixtures/Network/NetworkPreset.swift @@ -133,13 +133,13 @@ extension NetworkPreset { "709ab90621e3a8d9eb26ed9e2830e091beceebd55fb01c5d7c31d27e83b9b0d1" private static let testNetConsensusMrEnclaveHex = - "9268c3220a5260e51e4b586f00e4677fed2b80380f1eeaf775af60f8e880fde8" + "9659ea738275b3999bf1700398b60281be03af5cb399738a89b49ea2496595af" private static let testNetFogViewMrEnclaveHex = - "4e598799faa4bb08a3bd55c0bcda7e1d22e41151d0c591f6c2a48b3562b0881e" + "e154f108c7758b5aa7161c3824c176f0c20f63012463bf3cc5651e678f02fb9e" private static let testNetFogLedgerMrEnclaveHex = - "7330c9987f21b91313b39dcdeaa7da8da5ca101c929f5740c207742c762e6dcd" + "768f7bea6171fb83d775ee8485e4b5fcebf5f664ca7e8b9ceef9c7c21e9d9bf3" private static let testNetFogReportMrEnclaveHex = - "185875464ccd67a879d58181055383505a719b364b12d56d9bef90a40bed07ca" + "a4764346f91979b4906d4ce26102228efe3aba39216dec1e7d22e6b06f919f11" private static let devMrSignerHex = "7ee5e29d74623fdbc6fbf1454be6f3bb0b86c12366b7b478ad13353e44de8411" diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 2fc988be..9955882c 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 2fc988beaf2cf51efb8bcf1bef99ce12e2a6e9b9 +Subproject commit 9955882c8dc73404019098820bd190ccf3ebf935 From 20324aa036aae1fe58af5e4534775e9c34b82a85 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 13:15:25 -0700 Subject: [PATCH 05/53] change to m1 branch --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 9955882c..05906311 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 9955882c8dc73404019098820bd190ccf3ebf935 +Subproject commit 05906311b0d38ce79d4ed9df585121c5f18aa1b9 From 56f86ff59f2ec7a6877d8b6dbe5145fa386fbf45 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 13:16:38 -0700 Subject: [PATCH 06/53] Change podfile in Example Project --- Example/Podfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index 15377630..273ce568 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -26,8 +26,8 @@ target 'Example' do # pod 'MobileCoin', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git' # pod 'MobileCoin/Core', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git', testspecs: ['Tests', 'IntegrationTests'] - pod 'LibMobileCoin', binary: true - # pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' +# pod 'LibMobileCoin', binary: true + pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' # pod 'LibMobileCoin', podspec: '../Vendor/libmobilecoin-ios-artifacts/LibMobileCoin.podspec' # pod 'LibMobileCoin', git: 'https://github.com/mobilecoinofficial/libmobilecoin-ios-artifacts.git' From 57a6b43ef4314509526c685df6af0894ab425393 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 13:18:53 -0700 Subject: [PATCH 07/53] change tag value --- MobileCoin.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MobileCoin.podspec b/MobileCoin.podspec index 827c2fe5..6751caef 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -28,7 +28,7 @@ Pod::Spec.new do |s| "Sources/**/*.{h,m,swift}", ] - subspec.dependency "LibMobileCoin", "~> 1.1" + subspec.dependency "LibMobileCoin", "~> 1.1.2" subspec.dependency "gRPC-Swift", "~> 1.0" subspec.dependency "Logging", "~> 1.4" From 63e5600fd6c7b6c855d9ff0362cd117c6e09506b Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 13:22:00 -0700 Subject: [PATCH 08/53] update submodule commit hash --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 05906311..6621a49b 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 05906311b0d38ce79d4ed9df585121c5f18aa1b9 +Subproject commit 6621a49b7075602ad0a196f11afa32bb3c42221a From 8e201de47b7337f55fc37dc8f107cfbb39f49102 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 13:29:11 -0700 Subject: [PATCH 09/53] update submodule --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 6621a49b..64f3b2c7 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 6621a49b7075602ad0a196f11afa32bb3c42221a +Subproject commit 64f3b2c7c93b747fbe27a770ea8aafd83e7787c7 From 7d689b41a480f20c68eadc617cd368dcc3fa4a39 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 13:53:34 -0700 Subject: [PATCH 10/53] update sub --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 64f3b2c7..f7f995d2 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 64f3b2c7c93b747fbe27a770ea8aafd83e7787c7 +Subproject commit f7f995d29af62828d43e2dcadcb8a1799d4c9645 From 7608023da64c2bf23eb63b8c521bc7377ac3ac09 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 15:02:25 -0700 Subject: [PATCH 11/53] change name of proto type to match changes in fog commit 18f8cab4d535ebd99658471bdce1e78d74fb8a5a#diff-dc9a7b966113437e2c1ffafd1b1e18c73f5a74b36dc25706dc8ae686d188b492 --- Sources/LibMobileCoin/ProtoExtensions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/LibMobileCoin/ProtoExtensions.swift b/Sources/LibMobileCoin/ProtoExtensions.swift index b640ee50..5eeaa2c2 100644 --- a/Sources/LibMobileCoin/ProtoExtensions.swift +++ b/Sources/LibMobileCoin/ProtoExtensions.swift @@ -150,7 +150,7 @@ extension FogLedger_BlockRequest { } } -extension FogLedger_Block { +extension FogLedger_BlockData { var timestampDate: Date { get { Date(timeIntervalSince1970: TimeInterval(timestamp)) } set { timestamp = UInt64(newValue.timeIntervalSince1970) } From 4fdaf13d249fd727c3006d51e4e130a8bad20093 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 16:08:40 -0700 Subject: [PATCH 12/53] new comit --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index f7f995d2..a2169bb0 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit f7f995d29af62828d43e2dcadcb8a1799d4c9645 +Subproject commit a2169bb0c65fe5ef18be39e55848272628b6d111 From 9ed4308d2d3b3694feb48023a98fc94cb2969828 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 16:18:29 -0700 Subject: [PATCH 13/53] only active arch --- Example/Example.xcodeproj/project.pbxproj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index bea58e5b..76200921 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -298,7 +298,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.4; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; + ONLY_ACTIVE_ARCH = NO; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -368,6 +368,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\""; DEVELOPMENT_TEAM = 8JT9JJD9Y5; + ENABLE_ONLY_ACTIVE_RESOURCES = NO; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = Example/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -375,6 +376,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.mobilecoin.Example; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -390,6 +392,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\""; DEVELOPMENT_TEAM = 8JT9JJD9Y5; + ENABLE_ONLY_ACTIVE_RESOURCES = NO; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = Example/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -467,6 +470,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\""; DEVELOPMENT_TEAM = 8JT9JJD9Y5; + ENABLE_ONLY_ACTIVE_RESOURCES = NO; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = Example/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; From 5b413eda8d47d7b193d46f1182278c6b4c47e171 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 19 Aug 2021 16:23:12 -0700 Subject: [PATCH 14/53] comit --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index a2169bb0..3d11d8e2 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit a2169bb0c65fe5ef18be39e55848272628b6d111 +Subproject commit 3d11d8e278f387c944ab5086703942ad3840abfb From 34d517b400a9143d5d4707e87f8574e811756fad Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 24 Aug 2021 23:30:57 -0700 Subject: [PATCH 15/53] based of alx/nr, WIP --- Example/Gemfile.lock | 5 +- Example/Podfile | 4 +- Example/Podfile.lock | 7 +- Gemfile.lock | 5 +- Sources/Fog/Report/FogReportManager.swift | 26 +- Sources/Fog/Report/FogResolverManager.swift | 5 +- Sources/MobileCoinClient.swift | 197 ++++----- .../Network/AttestedConnectionConfig.swift | 6 +- .../Connection/ArbitraryConnection.swift | 81 +--- .../Connection/AttestedConnection.swift | 406 +++--------------- Sources/Network/Connection/Connection.swift | 116 ++--- .../Connection/ConnectionOptionWrapper.swift | 10 + .../Connection/ConnectionProtocol.swift | 9 + .../Connection/ConnectionSession.swift | 42 +- .../Connections/BlockchainConnection.swift | 51 ++- .../Connections/ConsensusConnection.swift | 67 +-- .../Connections/FogBlockConnection.swift | 50 ++- .../Connections/FogKeyImageConnection.swift | 67 +-- .../FogMerkleProofConnection.swift | 67 +-- .../Connections/FogReportConnection.swift | 57 ++- .../FogUntrustedTxOutConnection.swift | 51 ++- .../Connections/FogViewConnection.swift | 78 ++-- Sources/Network/ConnectionConfig.swift | 10 +- .../ArbitraryGrpcConnection.swift | 80 ++++ .../AttestedGrpcConnection.swift | 364 ++++++++++++++++ .../GrpcCallable/AttestedGrpcCallable.swift | 14 +- .../GrpcCallable/AuthGrpcCallable.swift | 0 .../GrpcCallable/GrpcCallable.swift | 0 .../GrpcClient/AttestableGrpcClient.swift | 0 .../GrpcClient/AuthGrpcCallableClient.swift | 0 .../GrpcClient/GrpcCallableClient.swift | 0 .../GrpcConnection/GrpcConnection.swift | 102 +++++ .../BlockchainGrpcConnection.swift | 45 ++ .../ConsensusGrpcConnection.swift | 58 +++ .../FogBlockGrpcConnection.swift | 43 ++ .../FogKeyImageGrpcConnection.swift | 58 +++ .../FogMerkleProofGrpcConnection.swift | 58 +++ .../FogReportGrpcConnection.swift | 39 ++ .../FogUntrustedTxOutGrpcConnection.swift | 43 ++ .../FogViewGrpcConnection.swift | 61 +++ .../AttestedHttpConnection.swift | 358 +++++++++++++++ .../HttpConnection/HTTPInterface/HTTP.swift | 11 + .../HTTPInterface/HTTPCallOptions.swift | 18 + .../HTTPInterface/HTTPClient.swift | 19 + .../HTTPInterface/HTTPClientCall.swift | 69 +++ .../HTTPInterface/HTTPUnaryCall.swift | 37 ++ .../HttpCallable/AttestedHttpCallable.swift | 162 +++++++ .../HttpCallable/AuthHttpCallable.swift | 29 ++ .../HttpCallable/HttpCallable.swift | 22 + .../HttpClient/AttestableHttpClient.swift | 9 + .../HttpClient/AuthHttpCallableClient.swift | 28 ++ .../HttpClient/HttpCallableClient.swift | 20 + .../HttpConnection/HttpClientWrapper.swift | 56 +++ .../HttpConnection/HttpConnection.swift | 98 +++++ .../BlockchainHttpConnection.swift | 54 +++ .../ConsensusHttpConnection.swift | 19 + .../FogBlockHttpConnection.swift | 56 +++ .../FogKeyImageHttpConnection.swift | 18 + .../FogMerkleProofHttpConnection.swift | 18 + .../FogReportHttpConnection.swift | 14 + .../FogUntrustedTxOutHttpConnection.swift | 18 + .../FogViewHttpConnection.swift | 28 ++ .../consensus_client.http.swift | 65 +++ .../consensus_common.http.swift | 84 ++++ .../Http Proto Generated/ledger.http.swift | 323 ++++++++++++++ .../HttpConnection/HttpRequester.swift | 240 +++++++++++ Sources/Network/NetworkConfig.swift | 11 + .../Service/DefaultServiceProvider.swift | 82 +++- Sources/Network/Service/ServiceProvider.swift | 8 +- Sources/Network/TransportProtocol.swift | 19 + Sources/Utils/HTTP/HttpCallResult.swift | 185 ++++++++ TERMS-OF-USE.md | 170 +++++--- .../Fixtures/Network/NetworkPreset.swift | 27 ++ .../Integration/IntegrationTestFixtures.swift | 2 +- .../FogReportConnectionIntTests.swift | 1 + .../FogViewConnectionIntTests.swift | 1 + 76 files changed, 3844 insertions(+), 917 deletions(-) create mode 100644 Sources/Network/Connection/ConnectionOptionWrapper.swift create mode 100644 Sources/Network/Connection/ConnectionProtocol.swift create mode 100644 Sources/Network/GrpcConnection/ArbitraryGrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/AttestedGrpcConnection.swift rename Sources/Network/{Connection => GrpcConnection}/GrpcCallable/AttestedGrpcCallable.swift (95%) rename Sources/Network/{Connection => GrpcConnection}/GrpcCallable/AuthGrpcCallable.swift (100%) rename Sources/Network/{Connection => GrpcConnection}/GrpcCallable/GrpcCallable.swift (100%) rename Sources/Network/{Connection => GrpcConnection}/GrpcClient/AttestableGrpcClient.swift (100%) rename Sources/Network/{Connection => GrpcConnection}/GrpcClient/AuthGrpcCallableClient.swift (100%) rename Sources/Network/{Connection => GrpcConnection}/GrpcClient/GrpcCallableClient.swift (100%) create mode 100644 Sources/Network/GrpcConnection/GrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/GrpcConnections/BlockchainGrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/GrpcConnections/ConsensusGrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/GrpcConnections/FogBlockGrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/GrpcConnections/FogKeyImageGrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/GrpcConnections/FogMerkleProofGrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/GrpcConnections/FogReportGrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/GrpcConnections/FogUntrustedTxOutGrpcConnection.swift create mode 100644 Sources/Network/GrpcConnection/GrpcConnections/FogViewGrpcConnection.swift create mode 100644 Sources/Network/HttpConnection/AttestedHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTP.swift create mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift create mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift create mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift create mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift create mode 100644 Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift create mode 100644 Sources/Network/HttpConnection/HttpCallable/AuthHttpCallable.swift create mode 100644 Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift create mode 100644 Sources/Network/HttpConnection/HttpClient/AttestableHttpClient.swift create mode 100644 Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift create mode 100644 Sources/Network/HttpConnection/HttpClient/HttpCallableClient.swift create mode 100644 Sources/Network/HttpConnection/HttpClientWrapper.swift create mode 100644 Sources/Network/HttpConnection/HttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift create mode 100644 Sources/Network/HttpConnection/HttpRequester.swift create mode 100644 Sources/Network/TransportProtocol.swift create mode 100644 Sources/Utils/HTTP/HttpCallResult.swift diff --git a/Example/Gemfile.lock b/Example/Gemfile.lock index 5866446b..780721a6 100644 --- a/Example/Gemfile.lock +++ b/Example/Gemfile.lock @@ -8,6 +8,9 @@ GIT fourflusher (~> 2.0) xcpretty (~> 0.3.0) +GEM + specs: + GEM remote: https://rubygems.org/ specs: @@ -290,4 +293,4 @@ DEPENDENCIES fastlane! BUNDLED WITH - 2.1.4 + 2.2.24 diff --git a/Example/Podfile b/Example/Podfile index 15377630..2d624adf 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -26,8 +26,8 @@ target 'Example' do # pod 'MobileCoin', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git' # pod 'MobileCoin/Core', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git', testspecs: ['Tests', 'IntegrationTests'] - pod 'LibMobileCoin', binary: true - # pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' + # pod 'LibMobileCoin', binary: true + pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' # pod 'LibMobileCoin', podspec: '../Vendor/libmobilecoin-ios-artifacts/LibMobileCoin.podspec' # pod 'LibMobileCoin', git: 'https://github.com/mobilecoinofficial/libmobilecoin-ios-artifacts.git' diff --git a/Example/Podfile.lock b/Example/Podfile.lock index dfa58766..bfb811b9 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -104,7 +104,7 @@ PODS: DEPENDENCIES: - gRPC-Swift - Keys (from `Pods/CocoaPodsKeys`) - - LibMobileCoin + - LibMobileCoin (from `../Vendor/libmobilecoin-ios-artifacts`) - MobileCoin (from `..`) - MobileCoin/Core (from `..`) - MobileCoin/Core/IntegrationTests (from `..`) @@ -124,7 +124,6 @@ SPEC REPOS: - CNIOLinux - CNIOWindows - gRPC-Swift - - LibMobileCoin - Logging - SwiftLint - SwiftNIO @@ -142,6 +141,8 @@ SPEC REPOS: EXTERNAL SOURCES: Keys: :path: Pods/CocoaPodsKeys + LibMobileCoin: + :path: "../Vendor/libmobilecoin-ios-artifacts" MobileCoin: :path: ".." @@ -172,6 +173,6 @@ SPEC CHECKSUMS: SwiftNIOTransportServices: 896c9a4ac98698d32aa2feea7657ade219ae80bb SwiftProtobuf: 3320217e9d8fb75f36b40282e78c482640fd75dd -PODFILE CHECKSUM: 004d4412cc1559f32bc126f553599fcfcaac859f +PODFILE CHECKSUM: a0d081de36bb0e26c2f240e65e5e63f9f111ec19 COCOAPODS: 1.9.3 diff --git a/Gemfile.lock b/Gemfile.lock index 5c3118c5..d30837d2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,6 @@ +GEM + specs: + GEM remote: https://rubygems.org/ specs: @@ -107,4 +110,4 @@ DEPENDENCIES jazzy! BUNDLED WITH - 2.1.4 + 2.2.24 diff --git a/Sources/Fog/Report/FogReportManager.swift b/Sources/Fog/Report/FogReportManager.swift index 5abb98c5..afa86e12 100644 --- a/Sources/Fog/Report/FogReportManager.swift +++ b/Sources/Fog/Report/FogReportManager.swift @@ -22,11 +22,11 @@ final class FogReportManager { completion: @escaping (Result) -> Void ) { logger.info("reportUrl: \(reportUrl.url)") - let reportService = serviceProvider.fogReportService(for: reportUrl) - - self.inner.accessAsync { - let reportServer = $0.reportServer(for: reportUrl) - reportServer.reports(reportService: reportService, completion: completion) + serviceProvider.fogReportService(for: reportUrl) { reportService in + self.inner.accessAsync { + let reportServer = $0.reportServer(for: reportUrl) + reportServer.reports(reportService: reportService, completion: completion) + } } } @@ -36,14 +36,14 @@ final class FogReportManager { completion: @escaping (Result) -> Void ) { logger.info("reportUrl: \(reportUrl.url), reportParams: \(reportParams)") - let reportService = serviceProvider.fogReportService(for: reportUrl) - - self.inner.accessAsync { - let reportServer = $0.reportServer(for: reportUrl) - reportServer.reports( - reportService: reportService, - reportParams: reportParams, - completion: completion) + serviceProvider.fogReportService(for: reportUrl) { reportService in + self.inner.accessAsync { + let reportServer = $0.reportServer(for: reportUrl) + reportServer.reports( + reportService: reportService, + reportParams: reportParams, + completion: completion) + } } } } diff --git a/Sources/Fog/Report/FogResolverManager.swift b/Sources/Fog/Report/FogResolverManager.swift index ea9336fe..b837f6a5 100644 --- a/Sources/Fog/Report/FogResolverManager.swift +++ b/Sources/Fog/Report/FogResolverManager.swift @@ -19,9 +19,8 @@ final class FogResolverManager { ) { self.serialQueue = DispatchQueue(label: "com.mobilecoin.\(Self.self)", target: targetQueue) self.reportAttestation = fogReportAttestation - self.reportManager = FogReportManager( - serviceProvider: serviceProvider, - targetQueue: targetQueue) + self.reportManager = + FogReportManager(serviceProvider: serviceProvider, targetQueue: targetQueue) } func fogResolver( diff --git a/Sources/MobileCoinClient.swift b/Sources/MobileCoinClient.swift index 3adc776f..cdbfb817 100644 --- a/Sources/MobileCoinClient.swift +++ b/Sources/MobileCoinClient.swift @@ -22,7 +22,6 @@ public final class MobileCoinClient { } private let accountLock: ReadWriteDispatchLock - private let inner: SerialDispatchLock private let serialQueue: DispatchQueue private let callbackQueue: DispatchQueue @@ -30,6 +29,8 @@ public final class MobileCoinClient { private let mixinSelectionStrategy: MixinSelectionStrategy private let fogQueryScalingStrategy: FogQueryScalingStrategy + private let serviceProvider: ServiceProvider + private let fogResolverManager: FogResolverManager private let feeFetcher: BlockchainFeeFetcher init(accountKey: AccountKeyWithFog, config: Config) { @@ -45,16 +46,12 @@ public final class MobileCoinClient { self.mixinSelectionStrategy = config.mixinSelectionStrategy self.fogQueryScalingStrategy = config.fogQueryScalingStrategy - let serviceProvider = + self.serviceProvider = DefaultServiceProvider(networkConfig: config.networkConfig, targetQueue: serialQueue) - let fogResolverManager = FogResolverManager( + self.fogResolverManager = FogResolverManager( fogReportAttestation: config.networkConfig.fogReportAttestation, serviceProvider: serviceProvider, targetQueue: serialQueue) - - let inner = Inner(serviceProvider: serviceProvider, fogResolverManager: fogResolverManager) - self.inner = .init(inner, targetQueue: serialQueue) - self.feeFetcher = BlockchainFeeFetcher( blockchainService: serviceProvider.blockchainService, minimumFeeCacheTTL: config.minimumFeeCacheTTL, @@ -69,29 +66,31 @@ public final class MobileCoinClient { accountLock.readSync { $0.cachedAccountActivity } } + public func setTransportProtocol(_ transportProtocol: TransportProtocol) { + serviceProvider.setTransportProtocolOption(transportProtocol.option) + } + public func setConsensusBasicAuthorization(username: String, password: String) { let credentials = BasicCredentials(username: username, password: password) - inner.accessAsync { $0.serviceProvider.setConsensusAuthorization(credentials: credentials) } + serviceProvider.setConsensusAuthorization(credentials: credentials) } public func setFogBasicAuthorization(username: String, password: String) { let credentials = BasicCredentials(username: username, password: password) - inner.accessAsync { $0.serviceProvider.setFogUserAuthorization(credentials: credentials) } + serviceProvider.setFogUserAuthorization(credentials: credentials) } public func updateBalance(completion: @escaping (Result) -> Void) { - inner.accessAsync { - Account.BalanceUpdater( - account: self.accountLock, - fogViewService: $0.serviceProvider.fogViewService, - fogKeyImageService: $0.serviceProvider.fogKeyImageService, - fogBlockService: $0.serviceProvider.fogBlockService, - fogQueryScalingStrategy: self.fogQueryScalingStrategy, - targetQueue: self.serialQueue - ).updateBalance { result in - self.callbackQueue.async { - completion(result) - } + Account.BalanceUpdater( + account: accountLock, + fogViewService: serviceProvider.fogViewService, + fogKeyImageService: serviceProvider.fogKeyImageService, + fogBlockService: serviceProvider.fogBlockService, + fogQueryScalingStrategy: fogQueryScalingStrategy, + targetQueue: serialQueue + ).updateBalance { result in + self.callbackQueue.async { + completion(result) } } } @@ -142,19 +141,17 @@ public final class MobileCoinClient { Result<(transaction: Transaction, receipt: Receipt), TransactionPreparationError> ) -> Void ) { - inner.accessAsync { - Account.TransactionOperations( - account: self.accountLock, - fogMerkleProofService: $0.serviceProvider.fogMerkleProofService, - fogResolverManager: $0.fogResolverManager, - feeFetcher: self.feeFetcher, - txOutSelectionStrategy: self.txOutSelectionStrategy, - mixinSelectionStrategy: self.mixinSelectionStrategy, - targetQueue: self.serialQueue - ).prepareTransaction(to: recipient, amount: amount, fee: fee) { result in - self.callbackQueue.async { - completion(result) - } + Account.TransactionOperations( + account: accountLock, + fogMerkleProofService: serviceProvider.fogMerkleProofService, + fogResolverManager: fogResolverManager, + feeFetcher: feeFetcher, + txOutSelectionStrategy: txOutSelectionStrategy, + mixinSelectionStrategy: mixinSelectionStrategy, + targetQueue: serialQueue + ).prepareTransaction(to: recipient, amount: amount, fee: fee) { result in + self.callbackQueue.async { + completion(result) } } } @@ -167,19 +164,17 @@ public final class MobileCoinClient { Result<(transaction: Transaction, receipt: Receipt), TransactionPreparationError> ) -> Void ) { - inner.accessAsync { - Account.TransactionOperations( - account: self.accountLock, - fogMerkleProofService: $0.serviceProvider.fogMerkleProofService, - fogResolverManager: $0.fogResolverManager, - feeFetcher: self.feeFetcher, - txOutSelectionStrategy: self.txOutSelectionStrategy, - mixinSelectionStrategy: self.mixinSelectionStrategy, - targetQueue: self.serialQueue - ).prepareTransaction(to: recipient, amount: amount, feeLevel: feeLevel) { result in - self.callbackQueue.async { - completion(result) - } + Account.TransactionOperations( + account: accountLock, + fogMerkleProofService: serviceProvider.fogMerkleProofService, + fogResolverManager: fogResolverManager, + feeFetcher: feeFetcher, + txOutSelectionStrategy: txOutSelectionStrategy, + mixinSelectionStrategy: mixinSelectionStrategy, + targetQueue: serialQueue + ).prepareTransaction(to: recipient, amount: amount, feeLevel: feeLevel) { result in + self.callbackQueue.async { + completion(result) } } } @@ -189,20 +184,18 @@ public final class MobileCoinClient { feeLevel: FeeLevel = .minimum, completion: @escaping (Result<[Transaction], DefragTransactionPreparationError>) -> Void ) { - inner.accessAsync { - Account.TransactionOperations( - account: self.accountLock, - fogMerkleProofService: $0.serviceProvider.fogMerkleProofService, - fogResolverManager: $0.fogResolverManager, - feeFetcher: self.feeFetcher, - txOutSelectionStrategy: self.txOutSelectionStrategy, - mixinSelectionStrategy: self.mixinSelectionStrategy, - targetQueue: self.serialQueue - ).prepareDefragmentationStepTransactions(toSendAmount: amount, feeLevel: feeLevel) - { result in - self.callbackQueue.async { - completion(result) - } + Account.TransactionOperations( + account: accountLock, + fogMerkleProofService: serviceProvider.fogMerkleProofService, + fogResolverManager: fogResolverManager, + feeFetcher: feeFetcher, + txOutSelectionStrategy: txOutSelectionStrategy, + mixinSelectionStrategy: mixinSelectionStrategy, + targetQueue: serialQueue + ).prepareDefragmentationStepTransactions(toSendAmount: amount, feeLevel: feeLevel) + { result in + self.callbackQueue.async { + completion(result) } } } @@ -211,14 +204,12 @@ public final class MobileCoinClient { _ transaction: Transaction, completion: @escaping (Result<(), TransactionSubmissionError>) -> Void ) { - inner.accessAsync { - TransactionSubmitter( - consensusService: $0.serviceProvider.consensusService, - feeFetcher: self.feeFetcher - ).submitTransaction(transaction) { result in - self.callbackQueue.async { - completion(result) - } + TransactionSubmitter( + consensusService: serviceProvider.consensusService, + feeFetcher: feeFetcher + ).submitTransaction(transaction) { result in + self.callbackQueue.async { + completion(result) } } } @@ -227,16 +218,14 @@ public final class MobileCoinClient { of transaction: Transaction, completion: @escaping (Result) -> Void ) { - inner.accessAsync { - TransactionStatusChecker( - account: self.accountLock, - fogUntrustedTxOutService: $0.serviceProvider.fogUntrustedTxOutService, - fogKeyImageService: $0.serviceProvider.fogKeyImageService, - targetQueue: self.serialQueue - ).checkStatus(transaction) { result in - self.callbackQueue.async { - completion(result) - } + TransactionStatusChecker( + account: accountLock, + fogUntrustedTxOutService: serviceProvider.fogUntrustedTxOutService, + fogKeyImageService: serviceProvider.fogKeyImageService, + targetQueue: serialQueue + ).checkStatus(transaction) { result in + self.callbackQueue.async { + completion(result) } } } @@ -307,18 +296,6 @@ extension MobileCoinClient { } } -extension MobileCoinClient { - private struct Inner { - let serviceProvider: ServiceProvider - let fogResolverManager: FogResolverManager - - init(serviceProvider: ServiceProvider, fogResolverManager: FogResolverManager) { - self.serviceProvider = serviceProvider - self.fogResolverManager = fogResolverManager - } - } -} - extension MobileCoinClient { public struct Config { /// - Returns: `InvalidInputError` when `consensusUrl` or `fogUrl` are not well-formed URLs @@ -368,21 +345,41 @@ extension MobileCoinClient { self.networkConfig = networkConfig } + public var transportProtocol: TransportProtocol { + get { networkConfig.transportProtocol } + set { networkConfig.transportProtocol = newValue } + } + public mutating func setConsensusTrustRoots(_ trustRoots: [Data]) -> Result<(), InvalidInputError> { - Self.parseTrustRoots(trustRootsBytes: trustRoots).map { trustRoots in - networkConfig.consensusTrustRoots = trustRoots + Self.parseTrustRoots(trustRootsBytes: trustRoots).map { + networkConfig.consensusTrustRoots = $0 } } public mutating func setFogTrustRoots(_ trustRoots: [Data]) -> Result<(), InvalidInputError> { - Self.parseTrustRoots(trustRootsBytes: trustRoots).map { trustRoots in - networkConfig.fogTrustRoots = trustRoots + Self.parseTrustRoots(trustRootsBytes: trustRoots).map { + networkConfig.fogTrustRoots = $0 } } + public mutating func setConsensusBasicAuthorization(username: String, password: String) { + networkConfig.consensusAuthorization = + BasicCredentials(username: username, password: password) + } + + public mutating func setFogBasicAuthorization(username: String, password: String) { + networkConfig.fogUserAuthorization = + BasicCredentials(username: username, password: password) + } + + public var httpRequester: HttpRequester? { + get { networkConfig.httpRequester } + set { networkConfig.httpRequester = newValue } + } + private static func parseTrustRoots(trustRootsBytes: [Data]) -> Result<[NIOSSLCertificate], InvalidInputError> { @@ -400,15 +397,5 @@ extension MobileCoinClient { } return .success(trustRoots) } - - public mutating func setConsensusBasicAuthorization(username: String, password: String) { - networkConfig.consensusAuthorization = - BasicCredentials(username: username, password: password) - } - - public mutating func setFogBasicAuthorization(username: String, password: String) { - networkConfig.fogUserAuthorization = - BasicCredentials(username: username, password: password) - } } } diff --git a/Sources/Network/AttestedConnectionConfig.swift b/Sources/Network/AttestedConnectionConfig.swift index 9dab224a..c0871c79 100644 --- a/Sources/Network/AttestedConnectionConfig.swift +++ b/Sources/Network/AttestedConnectionConfig.swift @@ -6,25 +6,25 @@ import Foundation import NIOSSL protocol AttestedConnectionConfigProtocol: ConnectionConfigProtocol { - var url: MobileCoinUrlProtocol { get } var attestation: Attestation { get } - var trustRoots: [NIOSSLCertificate]? { get } - var authorization: BasicCredentials? { get } } struct AttestedConnectionConfig: AttestedConnectionConfigProtocol { let urlTyped: Url + let transportProtocolOption: TransportProtocol.Option let attestation: Attestation let trustRoots: [NIOSSLCertificate]? let authorization: BasicCredentials? init( url: Url, + transportProtocolOption: TransportProtocol.Option, attestation: Attestation, trustRoots: [NIOSSLCertificate]?, authorization: BasicCredentials? ) { self.urlTyped = url + self.transportProtocolOption = transportProtocolOption self.attestation = attestation self.trustRoots = trustRoots self.authorization = authorization diff --git a/Sources/Network/Connection/ArbitraryConnection.swift b/Sources/Network/Connection/ArbitraryConnection.swift index f04dceb8..388dbeae 100644 --- a/Sources/Network/Connection/ArbitraryConnection.swift +++ b/Sources/Network/Connection/ArbitraryConnection.swift @@ -3,78 +3,41 @@ // import Foundation -import GRPC -class ArbitraryConnection { +class ArbitraryConnection { private let inner: SerialDispatchLock - init(url: MobileCoinUrlProtocol, targetQueue: DispatchQueue?) { - let inner = Inner(url: url) + private let connectionOptionWrapperFactory: (TransportProtocol.Option) + -> ConnectionOptionWrapper + + init( + connectionOptionWrapperFactory: @escaping (TransportProtocol.Option) + -> ConnectionOptionWrapper, + transportProtocolOption: TransportProtocol.Option, + targetQueue: DispatchQueue? + ) { + self.connectionOptionWrapperFactory = connectionOptionWrapperFactory + let connectionOptionWrapper = connectionOptionWrapperFactory(transportProtocolOption) + let inner = Inner(connectionOptionWrapper: connectionOptionWrapper) self.inner = .init(inner, targetQueue: targetQueue) } - func performCall( - _ call: Call, - request: Call.Request, - completion: @escaping (Result) -> Void - ) { - func performCallCallback(callResult: UnaryCallResult) { - inner.accessAsync { - let result = $0.processResponse(callResult: callResult) - switch result { - case .success: - logger.info("Call complete. url: \($0.url)", logFunction: false) - case .failure(let connectionError): - let errorMessage = - "Connection failure. url: \($0.url), error: \(connectionError)" - switch connectionError { - case .connectionFailure, .serverRateLimited: - logger.warning(errorMessage, logFunction: false) - case .authorizationFailure, .invalidServerResponse, - .attestationVerificationFailed, .outdatedClient: - logger.error(errorMessage, logFunction: false) - } - } - completion(result) - } - } - inner.accessAsync { - logger.info("Performing call... url: \($0.url)", logFunction: false) + func setTransportProtocolOption(_ transportProtocolOption: TransportProtocol.Option) { + let connectionOptionWrapper = connectionOptionWrapperFactory(transportProtocolOption) + inner.accessAsync { $0.connectionOptionWrapper = connectionOptionWrapper } + } - let callOptions = $0.requestCallOptions() - call.call(request: request, callOptions: callOptions, completion: performCallCallback) - } + var connectionOptionWrapper: ConnectionOptionWrapper { + inner.accessWithoutLocking.connectionOptionWrapper } } extension ArbitraryConnection { private struct Inner { - let url: MobileCoinUrlProtocol - private let session: ConnectionSession - - init(url: MobileCoinUrlProtocol) { - self.url = url - self.session = ConnectionSession(url: url) - } - - func requestCallOptions() -> CallOptions { - var callOptions = CallOptions() - session.addRequestHeaders(to: &callOptions.customMetadata) - return callOptions - } - - func processResponse(callResult: UnaryCallResult) - -> Result - { - guard callResult.status.isOk, let response = callResult.response else { - return .failure(.connectionFailure(String(describing: callResult.status))) - } - - if let initialMetadata = callResult.initialMetadata { - session.processResponse(headers: initialMetadata) - } + var connectionOptionWrapper: ConnectionOptionWrapper - return .success(response) + init(connectionOptionWrapper: ConnectionOptionWrapper) { + self.connectionOptionWrapper = connectionOptionWrapper } } } diff --git a/Sources/Network/Connection/AttestedConnection.swift b/Sources/Network/Connection/AttestedConnection.swift index d3b7a9a6..6c7dd5a1 100644 --- a/Sources/Network/Connection/AttestedConnection.swift +++ b/Sources/Network/Connection/AttestedConnection.swift @@ -2,363 +2,53 @@ // Copyright (c) 2020-2021 MobileCoin. All rights reserved. // -// swiftlint:disable closure_body_length cyclomatic_complexity function_body_length -// swiftlint:disable multiline_function_chains operator_usage_whitespace - import Foundation -import GRPC -import LibMobileCoin - -enum AttestedConnectionError: Error { - case connectionError(ConnectionError) - case attestationFailure(String = String()) -} - -extension AttestedConnectionError: CustomStringConvertible { - var description: String { - "Attested connection error: " + { - switch self { - case .connectionError(let connectionError): - return "\(connectionError)" - case .attestationFailure(let reason): - return "Attestation failure\(!reason.isEmpty ? ": \(reason)" : "")" - } - }() - } -} - -class AttestedConnection { - private let inner: SerialCallbackLock - - init( - client: AttestableGrpcClient, - config: AttestedConnectionConfigProtocol, - targetQueue: DispatchQueue?, - rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, - rngContext: Any? = nil - ) { - let inner = Inner(client: client, config: config, rng: rng, rngContext: rngContext) - self.inner = .init(inner, targetQueue: targetQueue) - } - - func setAuthorization(credentials: BasicCredentials) { - inner.priorityAccessAsync { - $0.setAuthorization(credentials: credentials) - } - } - - func performAttestedCall( - _ call: Call, - request: Call.InnerRequest, - completion: @escaping (Result) -> Void - ) where Call.InnerRequestAad == (), Call.InnerResponseAad == () { - performAttestedCall(call, requestAad: (), request: request, completion: completion) - } - - func performAttestedCall( - _ call: Call, - requestAad: Call.InnerRequestAad, - request: Call.InnerRequest, - completion: @escaping (Result) -> Void - ) where Call.InnerResponseAad == () { - performAttestedCall(call, requestAad: requestAad, request: request) { - completion($0.map { $0.response }) - } - } - - func performAttestedCall( - _ call: Call, - request: Call.InnerRequest, - completion: @escaping ( - Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), - ConnectionError> - ) -> Void - ) where Call.InnerRequestAad == () { - performAttestedCall(call, requestAad: (), request: request, completion: completion) - } - - func performAttestedCall( - _ call: Call, - requestAad: Call.InnerRequestAad, - request: Call.InnerRequest, - completion: @escaping ( - Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), - ConnectionError> - ) -> Void - ) { - inner.accessAsync(block: { inner, callback in - inner.performAttestedCallWithAuth( - call, - requestAad: requestAad, - request: request, - completion: callback) - }, completion: completion) - } -} - -extension AttestedConnection { - // Note: Because `SerialCallbackLock` is being used to wrap `AttestedConnection.Inner`, calls - // to `AttestedConnection.Inner` have exclusive access (other calls will be queued up) until the - // executing call invokes the completion handler that returns control back to - // `AttestedConnection`, at which point the block passed to the async `SerialCallbackLock` - // method that invoked the call to inner will complete and the next async `SerialCallbackLock` - // access block will execute. - // - // This means that calls to `AttestedConnection.Inner` can assume thread-safety until the call - // invokes the completion handler. - private struct Inner { - private let url: MobileCoinUrlProtocol - private let session: ConnectionSession - private let client: AttestableGrpcClient - private let attestAke: AttestAke - - private let responderId: String - private let attestationVerifier: AttestationVerifier - private let rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? - private let rngContext: Any? - - init( - client: AttestableGrpcClient, - config: AttestedConnectionConfigProtocol, - rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, - rngContext: Any? = nil - ) { - self.url = config.url - self.session = ConnectionSession(config: config) - self.client = client - self.attestAke = AttestAke() - self.responderId = config.url.responderId - self.attestationVerifier = AttestationVerifier(attestation: config.attestation) - self.rng = rng - self.rngContext = rngContext - } - - func setAuthorization(credentials: BasicCredentials) { - session.authorizationCredentials = credentials - } - - func performAttestedCallWithAuth( - _ call: Call, - requestAad: Call.InnerRequestAad, - request: Call.InnerRequest, - completion: @escaping ( - Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), - ConnectionError> - ) -> Void - ) { - doPerformAttestedCallWithAuth( - call, - requestAad: requestAad, - request: request, - attestAkeCipher: attestAke.cipher.map { ($0, freshCipher: false) }, - completion: completion) - } - - private func doPerformAttestedCallWithAuth( - _ call: Call, - requestAad: Call.InnerRequestAad, - request: Call.InnerRequest, - attestAkeCipher: (AttestAke.Cipher, freshCipher: Bool)?, - completion: @escaping ( - Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), - ConnectionError> - ) -> Void - ) { - if let (attestAkeCipher, freshCipher) = attestAkeCipher { - logger.info( - "Performing attested call... url: \(self.url)", - logFunction: false) - - doPerformAttestedCall( - call, - requestAad: requestAad, - request: request, - attestAkeCipher: attestAkeCipher - ) { - switch $0 { - case .success(let response): - logger.info( - "Attested call successful. url: \(self.url)", - logFunction: false) - - completion(.success(response)) - case .failure(.connectionError(let connectionError)): - let errorMessage = "Connection failure while performing attested call. " + - "url: \(self.url), error: \(connectionError)" - switch connectionError { - case .connectionFailure, .serverRateLimited: - logger.warning(errorMessage, logFunction: false) - case .authorizationFailure, .invalidServerResponse, - .attestationVerificationFailed, .outdatedClient: - logger.error(errorMessage, logFunction: false) - } - - completion(.failure(connectionError)) - case .failure(.attestationFailure): - self.attestAke.deattest() - - if freshCipher { - let errorMessage = - "Attestation failure with fresh auth. url: \(self.url)" - logger.warning(errorMessage, logFunction: false) - - completion(.failure(.invalidServerResponse(errorMessage))) - } else { - logger.info( - "Attestation failure using cached auth, reattesting... url: " + - "\(self.url)", - logFunction: false) - - self.doPerformAttestedCallWithAuth( - call, - requestAad: requestAad, - request: request, - attestAkeCipher: nil, - completion: completion) - } - } - } - } else { - logger.info( - "Peforming attestation... url: \(url)", - logFunction: false) - doPerformAuthCall { - switch $0 { - case .success(let attestAkeCipher): - logger.info( - "Attestation successful. url: \(self.url)", - logFunction: false) - - self.doPerformAttestedCallWithAuth( - call, - requestAad: requestAad, - request: request, - attestAkeCipher: (attestAkeCipher, freshCipher: true), - completion: completion) - case .failure(let connectionError): - let errorMessage = "Connection failure while performing attestation. " + - "url: \(self.url), error: \(connectionError)" - switch connectionError { - case .connectionFailure, .serverRateLimited: - logger.warning(errorMessage, logFunction: false) - case .authorizationFailure, .invalidServerResponse, - .attestationVerificationFailed, .outdatedClient: - logger.error(errorMessage, logFunction: false) - } - - completion(.failure(connectionError)) - } - } - } - } - - private func doPerformAuthCall( - completion: @escaping (Result) -> Void - ) { - let request = attestAke.authBeginRequest( - responderId: responderId, - rng: rng, - rngContext: rngContext) - - doPerformCall( - AuthGrpcCallableWrapper(authCallable: client.authCallable), - request: request - ) { - completion( - $0.mapError { - switch $0 { - case .connectionError(let connectionError): - return connectionError - case .attestationFailure: - self.attestAke.deattest() - - return .invalidServerResponse( - "Attestation failure during auth. url: \(self.url)") - } - }.flatMap { response in - self.attestAke.authEnd( - authResponse: response, - attestationVerifier: self.attestationVerifier - ).mapError { - switch $0 { - case .invalidInput(let reason): - return .invalidServerResponse(reason) - case .attestationVerificationFailed(let reason): - return .attestationVerificationFailed(reason) - } - } - }) - } - } - - private func doPerformAttestedCall( - _ call: Call, - requestAad: Call.InnerRequestAad, - request: Call.InnerRequest, - attestAkeCipher: AttestAke.Cipher, - completion: @escaping ( - Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), - AttestedConnectionError> - ) -> Void - ) { - guard let processedRequest = - call.processRequest( - requestAad: requestAad, - request: request, - attestAkeCipher: attestAkeCipher) - .mapError({ _ in .attestationFailure() }) - .successOr(completion: completion) - else { return } - - doPerformCall(call, request: processedRequest) { - completion($0.flatMap { response in - call.processResponse(response: response, attestAkeCipher: attestAkeCipher) - }) - } - } - - private func doPerformCall( - _ call: Call, - request: Call.Request, - completion: @escaping (Result) -> Void - ) { - let callOptions = requestCallOptions() - - call.call(request: request, callOptions: callOptions) { - completion(self.processResponse(callResult: $0)) - } - } - - private func requestCallOptions() -> CallOptions { - var callOptions = CallOptions() - session.addRequestHeaders(to: &callOptions.customMetadata) - return callOptions - } - - private func processResponse(callResult: UnaryCallResult) - -> Result - { - // Basic credential authorization failure - guard callResult.status.code != .unauthenticated else { - return .failure(.connectionError(.authorizationFailure("url: \(url)"))) - } - - // Attestation failure, reattest - guard callResult.status.code != .permissionDenied else { - return .failure(.attestationFailure()) - } - - guard callResult.status.isOk, let response = callResult.response else { - return .failure(.connectionError( - .connectionFailure("url: \(url), status: \(callResult.status)"))) - } - - if let initialMetadata = callResult.initialMetadata { - session.processResponse(headers: initialMetadata) - } - - return .success(response) - } - } -} +//class AttestedConnection { +// private let inner: SerialDispatchLock +// +// init(connectionOptionWrapper: ConnectionOptionWrapper, targetQueue: DispatchQueue?) { +// let inner = Inner(connectionOptionWrapper: connectionOptionWrapper) +// self.inner = .init(inner, targetQueue: targetQueue) +// } +// +// func setConnectionOptionWrapper(_ connectionOptionWrapper: ConnectionOptionWrapper) { +// inner.accessAsync { $0.connectionOptionWrapper = connectionOptionWrapper } +// } +// +// func setAuthorization(credentials: BasicCredentials) { +// inner.accessAsync { $0.setAuthorization(credentials: credentials) } +// } +//} +// +//extension AttestedConnection { +// private struct Inner { +// var connectionOptionWrapper: ConnectionOptionWrapper { +// didSet { +// if let credentials = authorizationCredentials { +// switch connectionOptionWrapper { +// case .grpc(grpcService: let grpcService): +// grpcService.setAuthorization(credentials: credentials) +// case .http(httpService: let httpService): +// httpService.setAuthorization(credentials: credentials) +// } +// } +// } +// } +// private var authorizationCredentials: BasicCredentials? +// +// init(connectionOptionWrapper: ConnectionOptionWrapper) { +// self.connectionOptionWrapper = connectionOptionWrapper +// } +// +// mutating func setAuthorization(credentials: BasicCredentials) { +// self.authorizationCredentials = credentials +// switch connectionOptionWrapper { +// case .grpc(grpcService: let grpcService): +// grpcService.setAuthorization(credentials: credentials) +// case .http(httpService: let httpService): +// httpService.setAuthorization(credentials: credentials) +// } +// } +// } +//} diff --git a/Sources/Network/Connection/Connection.swift b/Sources/Network/Connection/Connection.swift index 39a1d067..26993234 100644 --- a/Sources/Network/Connection/Connection.swift +++ b/Sources/Network/Connection/Connection.swift @@ -3,100 +3,68 @@ // import Foundation -import GRPC -class Connection { +class Connection { private let inner: SerialDispatchLock - init(config: ConnectionConfigProtocol, targetQueue: DispatchQueue?) { - let inner = Inner(config: config) - self.inner = .init(inner, targetQueue: targetQueue) - } - - func setAuthorization(credentials: BasicCredentials) { - inner.accessAsync { - $0.setAuthorization(credentials: credentials) - } - } + private let connectionOptionWrapperFactory: (TransportProtocol.Option) + -> ConnectionOptionWrapper - func performCall( - _ call: Call, - request: Call.Request, - completion: @escaping (Result) -> Void + init( + connectionOptionWrapperFactory: @escaping (TransportProtocol.Option) + -> ConnectionOptionWrapper, + transportProtocolOption: TransportProtocol.Option, + targetQueue: DispatchQueue? ) { - func performCallCallback(callResult: UnaryCallResult) { - inner.accessAsync { - let result = $0.processResponse(callResult: callResult) - switch result { - case .success: - logger.info("Call complete. url: \($0.url)", logFunction: false) - case .failure(let connectionError): - let errorMessage = - "Connection failure. url: \($0.url), error: \(connectionError)" - switch connectionError { - case .connectionFailure, .serverRateLimited: - logger.warning(errorMessage, logFunction: false) - case .authorizationFailure, .invalidServerResponse, - .attestationVerificationFailed, .outdatedClient: - logger.error(errorMessage, logFunction: false) - } - } - completion(result) - } - } + self.connectionOptionWrapperFactory = connectionOptionWrapperFactory + let connectionOptionWrapper = connectionOptionWrapperFactory(transportProtocolOption) + let inner = Inner(connectionOptionWrapper: connectionOptionWrapper) + self.inner = .init(inner, targetQueue: targetQueue) + } - inner.accessAsync { - logger.info("Performing call... url: \($0.url)", logFunction: false) + func setTransportProtocolOption(_ transportProtocolOption: TransportProtocol.Option) { + let connectionOptionWrapper = connectionOptionWrapperFactory(transportProtocolOption) + inner.accessAsync { $0.connectionOptionWrapper = connectionOptionWrapper } + } - let callOptions = $0.requestCallOptions() - call.call(request: request, callOptions: callOptions, completion: performCallCallback) - } + func setAuthorization(credentials: BasicCredentials) { + inner.accessAsync { $0.setAuthorization(credentials: credentials) } } - func performCall( - _ call: Call, - completion: @escaping (Result) -> Void - ) where Call.Request == () { - performCall(call, request: (), completion: completion) + var connectionOptionWrapper: ConnectionOptionWrapper { + inner.accessWithoutLocking.connectionOptionWrapper } } extension Connection { private struct Inner { - let url: MobileCoinUrlProtocol - private let session: ConnectionSession - - init(config: ConnectionConfigProtocol) { - self.url = config.url - self.session = ConnectionSession(config: config) + var connectionOptionWrapper: ConnectionOptionWrapper { + didSet { + if let credentials = authorizationCredentials { + switch connectionOptionWrapper { + case .grpc(grpcService: let grpcService): + grpcService.setAuthorization(credentials: credentials) + case .http(httpService: let httpService): + httpService.setAuthorization(credentials: credentials) + } + } + } } - func setAuthorization(credentials: BasicCredentials) { - session.authorizationCredentials = credentials - } + private var authorizationCredentials: BasicCredentials? - func requestCallOptions() -> CallOptions { - var callOptions = CallOptions() - session.addRequestHeaders(to: &callOptions.customMetadata) - return callOptions + init(connectionOptionWrapper: ConnectionOptionWrapper) { + self.connectionOptionWrapper = connectionOptionWrapper } - func processResponse(callResult: UnaryCallResult) - -> Result - { - guard callResult.status.code != .unauthenticated else { - return .failure(.authorizationFailure("url: \(url)")) - } - - guard callResult.status.isOk, let response = callResult.response else { - return .failure(.connectionFailure("url: \(url), status: \(callResult.status)")) + mutating func setAuthorization(credentials: BasicCredentials) { + self.authorizationCredentials = credentials + switch connectionOptionWrapper { + case .grpc(grpcService: let grpcService): + grpcService.setAuthorization(credentials: credentials) + case .http(httpService: let httpService): + httpService.setAuthorization(credentials: credentials) } - - if let initialMetadata = callResult.initialMetadata { - session.processResponse(headers: initialMetadata) - } - - return .success(response) } } } diff --git a/Sources/Network/Connection/ConnectionOptionWrapper.swift b/Sources/Network/Connection/ConnectionOptionWrapper.swift new file mode 100644 index 00000000..a85ac24b --- /dev/null +++ b/Sources/Network/Connection/ConnectionOptionWrapper.swift @@ -0,0 +1,10 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + +enum ConnectionOptionWrapper { + case grpc(grpcService: GrpcService) + case http(httpService: HttpService) +} diff --git a/Sources/Network/Connection/ConnectionProtocol.swift b/Sources/Network/Connection/ConnectionProtocol.swift new file mode 100644 index 00000000..9235e8cf --- /dev/null +++ b/Sources/Network/Connection/ConnectionProtocol.swift @@ -0,0 +1,9 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + +protocol ConnectionProtocol { + func setAuthorization(credentials: BasicCredentials) +} diff --git a/Sources/Network/Connection/ConnectionSession.swift b/Sources/Network/Connection/ConnectionSession.swift index 567943ea..8ba2609e 100644 --- a/Sources/Network/Connection/ConnectionSession.swift +++ b/Sources/Network/Connection/ConnectionSession.swift @@ -21,6 +21,22 @@ final class ConnectionSession { private let cookieStorage: HTTPCookieStorage var authorizationCredentials: BasicCredentials? + private var cookieHeaders : [String:String] { + guard let cookies = cookieStorage.cookies(for: url) else { return [:] } + return HTTPCookie.requestHeaderFields(with: cookies) + } + + private var authorizationHeades : [String: String] { + guard let credentials = authorizationCredentials else { return [:] } + return ["Authorization" : credentials.authorizationHeaderValue] + } + var requestHeaders: [String : String] { + var headers : [String: String] = [:] + headers.merge(cookieHeaders) { (_, new) in new } + headers.merge(authorizationHeades) { (_, new) in new } + return headers + } + convenience init(config: ConnectionConfigProtocol) { self.init(url: config.url, authorization: config.authorization) } @@ -39,6 +55,10 @@ final class ConnectionSession { func processResponse(headers: HPACKHeaders) { processCookieHeader(headers: headers) } + + func processResponse(headers: [AnyHashable : Any]) { + processCookieHeader(headers: headers) + } } extension ConnectionSession { @@ -47,18 +67,35 @@ extension ConnectionSession { hpackHeaders.add(httpHeaders: ["Authorization": credentials.authorizationHeaderValue]) } } + } +// GRPC extension ConnectionSession { + private func processCookieHeader(headers: HPACKHeaders) { + let http1Headers = Dictionary( + headers.map { ($0.name.capitalized, $0.value) }, + uniquingKeysWith: { k, _ in k }) + + let receivedCookies = HTTPCookie.cookies( + withResponseHeaderFields: http1Headers, + for: url) + receivedCookies.forEach(cookieStorage.setCookie) + } + private func addCookieHeader(to hpackHeaders: inout HPACKHeaders) { if let cookies = cookieStorage.cookies(for: url) { hpackHeaders.add(httpHeaders: HTTPCookie.requestHeaderFields(with: cookies)) } } - private func processCookieHeader(headers: HPACKHeaders) { + private func processCookieHeader(headers: [AnyHashable: Any]) { let http1Headers = Dictionary( - headers.map { ($0.name.capitalized, $0.value) }, + headers.compactMap({ (key: AnyHashable, value: Any) -> (name: String, value: String)? in + guard let name = key as? String else { return nil } + guard let value = value as? String else { return nil } + return (name:name, value:value) + }).map { ($0.name.capitalized, $0.value) }, uniquingKeysWith: { k, _ in k }) let receivedCookies = HTTPCookie.cookies( @@ -66,6 +103,7 @@ extension ConnectionSession { for: url) receivedCookies.forEach(cookieStorage.setCookie) } + } extension HPACKHeaders { diff --git a/Sources/Network/Connection/Connections/BlockchainConnection.swift b/Sources/Network/Connection/Connections/BlockchainConnection.swift index 06c4af2c..f7fcfbf9 100644 --- a/Sources/Network/Connection/Connections/BlockchainConnection.swift +++ b/Sources/Network/Connection/Connections/BlockchainConnection.swift @@ -7,39 +7,48 @@ import GRPC import LibMobileCoin import SwiftProtobuf -final class BlockchainConnection: Connection, BlockchainService { - private let client: ConsensusCommon_BlockchainAPIClient +final class BlockchainConnection: + Connection, BlockchainService +{ + private let config: ConnectionConfig + private let channelManager: GrpcChannelManager + private let targetQueue: DispatchQueue? init( config: ConnectionConfig, channelManager: GrpcChannelManager, targetQueue: DispatchQueue? ) { - let channel = channelManager.channel(for: config) - self.client = ConsensusCommon_BlockchainAPIClient(channel: channel) - super.init(config: config, targetQueue: targetQueue) + self.config = config + self.channelManager = channelManager + self.targetQueue = targetQueue + + super.init( + connectionOptionWrapperFactory: { transportProtocolOption in + switch transportProtocolOption { + case .grpc: + return .grpc( + grpcService: BlockchainGrpcConnection( + config: config, + channelManager: channelManager, + targetQueue: targetQueue)) + case .http: + return .http(httpService: BlockchainHttpConnection(config: config, targetQueue: targetQueue)) + } + }, + transportProtocolOption: config.transportProtocolOption, + targetQueue: targetQueue) } func getLastBlockInfo( completion: @escaping (Result) -> Void ) { - performCall(GetLastBlockInfoCall(client: client), completion: completion) - } -} - -extension BlockchainConnection { - private struct GetLastBlockInfoCall: GrpcCallable { - let client: ConsensusCommon_BlockchainAPIClient - - func call( - request: (), - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void - ) { - let unaryCall = - client.getLastBlockInfo(Google_Protobuf_Empty(), callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + switch connectionOptionWrapper { + case .grpc(let grpcConnection): + grpcConnection.getLastBlockInfo(completion: completion) + case .http(let httpConnection): + httpConnection.getLastBlockInfo(completion: completion) } } } diff --git a/Sources/Network/Connection/Connections/ConsensusConnection.swift b/Sources/Network/Connection/Connections/ConsensusConnection.swift index 3c73fe6e..bacda281 100644 --- a/Sources/Network/Connection/Connections/ConsensusConnection.swift +++ b/Sources/Network/Connection/Connections/ConsensusConnection.swift @@ -6,8 +6,14 @@ import Foundation import GRPC import LibMobileCoin -final class ConsensusConnection: AttestedConnection, ConsensusService { - private let client: ConsensusClient_ConsensusClientAPIClient +final class ConsensusConnection: + Connection, ConsensusService +{ + private let config: AttestedConnectionConfig + private let channelManager: GrpcChannelManager + private let targetQueue: DispatchQueue? + private let rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? + private let rngContext: Any? init( config: AttestedConnectionConfig, @@ -16,43 +22,40 @@ final class ConsensusConnection: AttestedConnection, ConsensusService { rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil ) { - let channel = channelManager.channel(for: config) - self.client = ConsensusClient_ConsensusClientAPIClient(channel: channel) + self.config = config + self.channelManager = channelManager + self.targetQueue = targetQueue + self.rng = rng + self.rngContext = rngContext + super.init( - client: Attest_AttestedApiClient(channel: channel), - config: config, - targetQueue: targetQueue, - rng: rng, - rngContext: rngContext) + connectionOptionWrapperFactory: { transportProtocolOption in + switch transportProtocolOption { + case .grpc: + return .grpc( + grpcService: ConsensusGrpcConnection( + config: config, + channelManager: channelManager, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext)) + case .http: + return .http(httpService: ConsensusHttpConnection()) + } + }, + transportProtocolOption: config.transportProtocolOption, + targetQueue: targetQueue) } func proposeTx( _ tx: External_Tx, completion: @escaping (Result) -> Void ) { - performAttestedCall( - ProposeTxCall(client: client), - request: tx, - completion: completion) - } -} - -extension ConsensusConnection { - private struct ProposeTxCall: AttestedGrpcCallable { - typealias InnerRequest = External_Tx - typealias InnerResponse = ConsensusCommon_ProposeTxResponse - - let client: ConsensusClient_ConsensusClientAPIClient - - func call( - request: Attest_Message, - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void - ) { - let unaryCall = client.clientTxPropose(request, callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + switch connectionOptionWrapper { + case .grpc(let grpcConnection): + grpcConnection.proposeTx(tx, completion: completion) + case .http(let httpConnection): + httpConnection.proposeTx(tx, completion: completion) } } } - -extension Attest_AttestedApiClient: AuthGrpcCallableClient {} diff --git a/Sources/Network/Connection/Connections/FogBlockConnection.swift b/Sources/Network/Connection/Connections/FogBlockConnection.swift index be36ae54..88d66316 100644 --- a/Sources/Network/Connection/Connections/FogBlockConnection.swift +++ b/Sources/Network/Connection/Connections/FogBlockConnection.swift @@ -6,38 +6,48 @@ import Foundation import GRPC import LibMobileCoin -final class FogBlockConnection: Connection, FogBlockService { - private let client: FogLedger_FogBlockAPIClient +final class FogBlockConnection: + Connection, FogBlockService +{ + private let config: ConnectionConfig + private let channelManager: GrpcChannelManager + private let targetQueue: DispatchQueue? init( config: ConnectionConfig, channelManager: GrpcChannelManager, targetQueue: DispatchQueue? ) { - let channel = channelManager.channel(for: config) - self.client = FogLedger_FogBlockAPIClient(channel: channel) - super.init(config: config, targetQueue: targetQueue) + self.config = config + self.channelManager = channelManager + self.targetQueue = targetQueue + + super.init( + connectionOptionWrapperFactory: { transportProtocolOption in + switch transportProtocolOption { + case .grpc: + return .grpc( + grpcService: FogBlockGrpcConnection( + config: config, + channelManager: channelManager, + targetQueue: targetQueue)) + case .http: + return .http(httpService: FogBlockHttpConnection()) + } + }, + transportProtocolOption: config.transportProtocolOption, + targetQueue: targetQueue) } func getBlocks( request: FogLedger_BlockRequest, completion: @escaping (Result) -> Void ) { - performCall(GetBlocksCall(client: client), request: request, completion: completion) - } -} - -extension FogBlockConnection { - private struct GetBlocksCall: GrpcCallable { - let client: FogLedger_FogBlockAPIClient - - func call( - request: FogLedger_BlockRequest, - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void - ) { - let unaryCall = client.getBlocks(request, callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + switch connectionOptionWrapper { + case .grpc(let grpcConnection): + grpcConnection.getBlocks(request: request, completion: completion) + case .http(let httpConnection): + httpConnection.getBlocks(request: request, completion: completion) } } } diff --git a/Sources/Network/Connection/Connections/FogKeyImageConnection.swift b/Sources/Network/Connection/Connections/FogKeyImageConnection.swift index d9de00f0..93f8567a 100644 --- a/Sources/Network/Connection/Connections/FogKeyImageConnection.swift +++ b/Sources/Network/Connection/Connections/FogKeyImageConnection.swift @@ -6,8 +6,14 @@ import Foundation import GRPC import LibMobileCoin -final class FogKeyImageConnection: AttestedConnection, FogKeyImageService { - private let client: FogLedger_FogKeyImageAPIClient +final class FogKeyImageConnection: + Connection, FogKeyImageService +{ + private let config: AttestedConnectionConfig + private let channelManager: GrpcChannelManager + private let targetQueue: DispatchQueue? + private let rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? + private let rngContext: Any? init( config: AttestedConnectionConfig, @@ -16,43 +22,40 @@ final class FogKeyImageConnection: AttestedConnection, FogKeyImageService { rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil ) { - let channel = channelManager.channel(for: config) - self.client = FogLedger_FogKeyImageAPIClient(channel: channel) + self.config = config + self.channelManager = channelManager + self.targetQueue = targetQueue + self.rng = rng + self.rngContext = rngContext + super.init( - client: self.client, - config: config, - targetQueue: targetQueue, - rng: rng, - rngContext: rngContext) + connectionOptionWrapperFactory: { transportProtocolOption in + switch transportProtocolOption { + case .grpc: + return .grpc( + grpcService: FogKeyImageGrpcConnection( + config: config, + channelManager: channelManager, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext)) + case .http: + return .http(httpService: FogKeyImageHttpConnection()) + } + }, + transportProtocolOption: config.transportProtocolOption, + targetQueue: targetQueue) } func checkKeyImages( request: FogLedger_CheckKeyImagesRequest, completion: @escaping (Result) -> Void ) { - performAttestedCall( - CheckKeyImagesCall(client: client), - request: request, - completion: completion) - } -} - -extension FogKeyImageConnection { - private struct CheckKeyImagesCall: AttestedGrpcCallable { - typealias InnerRequest = FogLedger_CheckKeyImagesRequest - typealias InnerResponse = FogLedger_CheckKeyImagesResponse - - let client: FogLedger_FogKeyImageAPIClient - - func call( - request: Attest_Message, - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void - ) { - let unaryCall = client.checkKeyImages(request, callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + switch connectionOptionWrapper { + case .grpc(let grpcConnection): + grpcConnection.checkKeyImages(request: request, completion: completion) + case .http(let httpConnection): + httpConnection.checkKeyImages(request: request, completion: completion) } } } - -extension FogLedger_FogKeyImageAPIClient: AuthGrpcCallableClient {} diff --git a/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift b/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift index a224f520..1ac45250 100644 --- a/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift +++ b/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift @@ -6,8 +6,14 @@ import Foundation import GRPC import LibMobileCoin -final class FogMerkleProofConnection: AttestedConnection, FogMerkleProofService { - private let client: FogLedger_FogMerkleProofAPIClient +final class FogMerkleProofConnection: + Connection, FogMerkleProofService +{ + private let config: AttestedConnectionConfig + private let channelManager: GrpcChannelManager + private let targetQueue: DispatchQueue? + private let rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? + private let rngContext: Any? init( config: AttestedConnectionConfig, @@ -16,43 +22,40 @@ final class FogMerkleProofConnection: AttestedConnection, FogMerkleProofService rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil ) { - let channel = channelManager.channel(for: config) - self.client = FogLedger_FogMerkleProofAPIClient(channel: channel) + self.config = config + self.channelManager = channelManager + self.targetQueue = targetQueue + self.rng = rng + self.rngContext = rngContext + super.init( - client: self.client, - config: config, - targetQueue: targetQueue, - rng: rng, - rngContext: rngContext) + connectionOptionWrapperFactory: { transportProtocolOption in + switch transportProtocolOption { + case .grpc: + return .grpc( + grpcService: FogMerkleProofGrpcConnection( + config: config, + channelManager: channelManager, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext)) + case .http: + return .http(httpService: FogMerkleProofHttpConnection()) + } + }, + transportProtocolOption: config.transportProtocolOption, + targetQueue: targetQueue) } func getOutputs( request: FogLedger_GetOutputsRequest, completion: @escaping (Result) -> Void ) { - performAttestedCall( - GetOutputsCall(client: client), - request: request, - completion: completion) - } -} - -extension FogMerkleProofConnection { - private struct GetOutputsCall: AttestedGrpcCallable { - typealias InnerRequest = FogLedger_GetOutputsRequest - typealias InnerResponse = FogLedger_GetOutputsResponse - - let client: FogLedger_FogMerkleProofAPIClient - - func call( - request: Attest_Message, - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void - ) { - let unaryCall = client.getOutputs(request, callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + switch connectionOptionWrapper { + case .grpc(let grpcConnection): + grpcConnection.getOutputs(request: request, completion: completion) + case .http(let httpConnection): + httpConnection.getOutputs(request: request, completion: completion) } } } - -extension FogLedger_FogMerkleProofAPIClient: AuthGrpcCallableClient {} diff --git a/Sources/Network/Connection/Connections/FogReportConnection.swift b/Sources/Network/Connection/Connections/FogReportConnection.swift index 3cffeb0f..51573d9d 100644 --- a/Sources/Network/Connection/Connections/FogReportConnection.swift +++ b/Sources/Network/Connection/Connections/FogReportConnection.swift @@ -6,34 +6,49 @@ import Foundation import GRPC import LibMobileCoin -final class FogReportConnection: ArbitraryConnection, FogReportService { - private let client: Report_ReportAPIClient +final class FogReportConnection: + ArbitraryConnection, FogReportService +{ + private let url: FogUrl + private let channelManager: GrpcChannelManager + private let targetQueue: DispatchQueue? - init(url: FogUrl, channelManager: GrpcChannelManager, targetQueue: DispatchQueue?) { - let channel = channelManager.channel(for: url) - self.client = Report_ReportAPIClient(channel: channel) - super.init(url: url, targetQueue: targetQueue) + init( + url: FogUrl, + transportProtocolOption: TransportProtocol.Option, + channelManager: GrpcChannelManager, + targetQueue: DispatchQueue? + ) { + self.url = url + self.channelManager = channelManager + self.targetQueue = targetQueue + + super.init( + connectionOptionWrapperFactory: { transportProtocolOption in + switch transportProtocolOption { + case .grpc: + return .grpc( + grpcService: FogReportGrpcConnection( + url: url, + channelManager: channelManager, + targetQueue: targetQueue)) + case .http: + return .http(httpService: FogReportHttpConnection()) + } + }, + transportProtocolOption: transportProtocolOption, + targetQueue: targetQueue) } func getReports( request: Report_ReportRequest, completion: @escaping (Result) -> Void ) { - performCall(GetReportsCall(client: client), request: request, completion: completion) - } -} - -extension FogReportConnection { - private struct GetReportsCall: GrpcCallable { - let client: Report_ReportAPIClient - - func call( - request: Report_ReportRequest, - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void - ) { - let unaryCall = client.getReports(request, callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + switch connectionOptionWrapper { + case .grpc(let grpcConnection): + grpcConnection.getReports(request: request, completion: completion) + case .http(let httpConnection): + httpConnection.getReports(request: request, completion: completion) } } } diff --git a/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift b/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift index 00067430..94048326 100644 --- a/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift +++ b/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift @@ -6,38 +6,49 @@ import Foundation import GRPC import LibMobileCoin -final class FogUntrustedTxOutConnection: Connection, FogUntrustedTxOutService { - private let client: FogLedger_FogUntrustedTxOutApiClient +final class FogUntrustedTxOutConnection: + Connection, + FogUntrustedTxOutService +{ + private let config: ConnectionConfig + private let channelManager: GrpcChannelManager + private let targetQueue: DispatchQueue? init( config: ConnectionConfig, channelManager: GrpcChannelManager, targetQueue: DispatchQueue? ) { - let channel = channelManager.channel(for: config) - self.client = FogLedger_FogUntrustedTxOutApiClient(channel: channel) - super.init(config: config, targetQueue: targetQueue) + self.config = config + self.channelManager = channelManager + self.targetQueue = targetQueue + + super.init( + connectionOptionWrapperFactory: { transportProtocolOption in + switch transportProtocolOption { + case .grpc: + return .grpc( + grpcService: FogUntrustedTxOutGrpcConnection( + config: config, + channelManager: channelManager, + targetQueue: targetQueue)) + case .http: + return .http(httpService: FogUntrustedTxOutHttpConnection()) + } + }, + transportProtocolOption: config.transportProtocolOption, + targetQueue: targetQueue) } func getTxOuts( request: FogLedger_TxOutRequest, completion: @escaping (Result) -> Void ) { - performCall(GetTxOutsCall(client: client), request: request, completion: completion) - } -} - -extension FogUntrustedTxOutConnection { - private struct GetTxOutsCall: GrpcCallable { - let client: FogLedger_FogUntrustedTxOutApiClient - - func call( - request: FogLedger_TxOutRequest, - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void - ) { - let unaryCall = client.getTxOuts(request, callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + switch connectionOptionWrapper { + case .grpc(let grpcConnection): + grpcConnection.getTxOuts(request: request, completion: completion) + case .http(let httpConnection): + httpConnection.getTxOuts(request: request, completion: completion) } } } diff --git a/Sources/Network/Connection/Connections/FogViewConnection.swift b/Sources/Network/Connection/Connections/FogViewConnection.swift index 9b2f60bf..7a72ca50 100644 --- a/Sources/Network/Connection/Connections/FogViewConnection.swift +++ b/Sources/Network/Connection/Connections/FogViewConnection.swift @@ -6,24 +6,54 @@ import Foundation import GRPC import LibMobileCoin -final class FogViewConnection: AttestedConnection, FogViewService { - private let client: FogView_FogViewAPIClient +final class FogViewConnection: + Connection, FogViewService +{ + private let config: AttestedConnectionConfig + // private let channelManager: GrpcChannelManager + private let targetQueue: DispatchQueue? + private let rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? + private let rngContext: Any? init( config: AttestedConnectionConfig, channelManager: GrpcChannelManager, + httpRequester: HttpRequester?, targetQueue: DispatchQueue?, rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil ) { - let channel = channelManager.channel(for: config) - self.client = FogView_FogViewAPIClient(channel: channel) + self.config = config + // self.channelManager = channelManager + self.targetQueue = targetQueue + self.rng = rng + self.rngContext = rngContext super.init( - client: self.client, - config: config, - targetQueue: targetQueue, - rng: rng, - rngContext: rngContext) + connectionOptionWrapperFactory: { transportProtocolOption in + switch transportProtocolOption { + case .grpc: + return .grpc( + grpcService: FogViewGrpcConnection( + config: config, + channelManager: channelManager, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext)) + case .http: + let httpClientWrapper = HttpClientWrapper( + config: config, + httpRequester: httpRequester) + return .http( + httpService: FogViewHttpConnection( + config: config, + client: httpClientWrapper, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext)) + } + }, + transportProtocolOption: config.transportProtocolOption, + targetQueue: targetQueue) } func query( @@ -31,31 +61,11 @@ final class FogViewConnection: AttestedConnection, FogViewService { request: FogView_QueryRequest, completion: @escaping (Result) -> Void ) { - performAttestedCall( - EnclaveRequestCall(client: client), - requestAad: requestAad, - request: request, - completion: completion) - } -} - -extension FogViewConnection { - private struct EnclaveRequestCall: AttestedGrpcCallable { - typealias InnerRequestAad = FogView_QueryRequestAAD - typealias InnerRequest = FogView_QueryRequest - typealias InnerResponse = FogView_QueryResponse - - let client: FogView_FogViewAPIClient - - func call( - request: Attest_Message, - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void - ) { - let unaryCall = client.query(request, callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + switch connectionOptionWrapper { + case .grpc(let grpcConnection): + grpcConnection.query(requestAad: requestAad, request: request, completion: completion) + case .http(let httpConnection): + httpConnection.query(requestAad: requestAad, request: request, completion: completion) } } } - -extension FogView_FogViewAPIClient: AuthGrpcCallableClient {} diff --git a/Sources/Network/ConnectionConfig.swift b/Sources/Network/ConnectionConfig.swift index ffa9b6e0..e97c1676 100644 --- a/Sources/Network/ConnectionConfig.swift +++ b/Sources/Network/ConnectionConfig.swift @@ -7,17 +7,25 @@ import NIOSSL protocol ConnectionConfigProtocol { var url: MobileCoinUrlProtocol { get } + var transportProtocolOption: TransportProtocol.Option { get } var trustRoots: [NIOSSLCertificate]? { get } var authorization: BasicCredentials? { get } } struct ConnectionConfig: ConnectionConfigProtocol { let urlTyped: Url + let transportProtocolOption: TransportProtocol.Option let trustRoots: [NIOSSLCertificate]? let authorization: BasicCredentials? - init(url: Url, trustRoots: [NIOSSLCertificate]?, authorization: BasicCredentials?) { + init( + url: Url, + transportProtocolOption: TransportProtocol.Option, + trustRoots: [NIOSSLCertificate]?, + authorization: BasicCredentials? + ) { self.urlTyped = url + self.transportProtocolOption = transportProtocolOption self.trustRoots = trustRoots self.authorization = authorization } diff --git a/Sources/Network/GrpcConnection/ArbitraryGrpcConnection.swift b/Sources/Network/GrpcConnection/ArbitraryGrpcConnection.swift new file mode 100644 index 00000000..75a7fccb --- /dev/null +++ b/Sources/Network/GrpcConnection/ArbitraryGrpcConnection.swift @@ -0,0 +1,80 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC + +class ArbitraryGrpcConnection { + private let inner: SerialDispatchLock + + init(url: MobileCoinUrlProtocol, targetQueue: DispatchQueue?) { + let inner = Inner(url: url) + self.inner = .init(inner, targetQueue: targetQueue) + } + + func performCall( + _ call: Call, + request: Call.Request, + completion: @escaping (Result) -> Void + ) { + func performCallCallback(callResult: UnaryCallResult) { + inner.accessAsync { + let result = $0.processResponse(callResult: callResult) + switch result { + case .success: + logger.info("Call complete. url: \($0.url)", logFunction: false) + case .failure(let connectionError): + let errorMessage = + "Connection failure. url: \($0.url), error: \(connectionError)" + switch connectionError { + case .connectionFailure, .serverRateLimited: + logger.warning(errorMessage, logFunction: false) + case .authorizationFailure, .invalidServerResponse, + .attestationVerificationFailed, .outdatedClient: + logger.error(errorMessage, logFunction: false) + } + } + completion(result) + } + } + inner.accessAsync { + logger.info("Performing call... url: \($0.url)", logFunction: false) + + let callOptions = $0.requestCallOptions() + call.call(request: request, callOptions: callOptions, completion: performCallCallback) + } + } +} + +extension ArbitraryGrpcConnection { + private struct Inner { + let url: MobileCoinUrlProtocol + private let session: ConnectionSession + + init(url: MobileCoinUrlProtocol) { + self.url = url + self.session = ConnectionSession(url: url) + } + + func requestCallOptions() -> CallOptions { + var callOptions = CallOptions() + session.addRequestHeaders(to: &callOptions.customMetadata) + return callOptions + } + + func processResponse(callResult: UnaryCallResult) + -> Result + { + guard callResult.status.isOk, let response = callResult.response else { + return .failure(.connectionFailure(String(describing: callResult.status))) + } + + if let initialMetadata = callResult.initialMetadata { + session.processResponse(headers: initialMetadata) + } + + return .success(response) + } + } +} diff --git a/Sources/Network/GrpcConnection/AttestedGrpcConnection.swift b/Sources/Network/GrpcConnection/AttestedGrpcConnection.swift new file mode 100644 index 00000000..db9c6474 --- /dev/null +++ b/Sources/Network/GrpcConnection/AttestedGrpcConnection.swift @@ -0,0 +1,364 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +// swiftlint:disable closure_body_length cyclomatic_complexity function_body_length +// swiftlint:disable multiline_function_chains operator_usage_whitespace + +import Foundation +import GRPC +import LibMobileCoin + +enum AttestedGrpcConnectionError: Error { + case connectionError(ConnectionError) + case attestationFailure(String = String()) +} + +extension AttestedGrpcConnectionError: CustomStringConvertible { + var description: String { + "Attested connection error: " + { + switch self { + case .connectionError(let connectionError): + return "\(connectionError)" + case .attestationFailure(let reason): + return "Attestation failure\(!reason.isEmpty ? ": \(reason)" : "")" + } + }() + } +} + +class AttestedGrpcConnection: ConnectionProtocol { + private let inner: SerialCallbackLock + + init( + client: AttestableGrpcClient, + config: AttestedConnectionConfigProtocol, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + let inner = Inner(client: client, config: config, rng: rng, rngContext: rngContext) + self.inner = .init(inner, targetQueue: targetQueue) + } + + func setAuthorization(credentials: BasicCredentials) { + inner.priorityAccessAsync { + $0.setAuthorization(credentials: credentials) + } + } + + func performAttestedCall( + _ call: Call, + request: Call.InnerRequest, + completion: @escaping (Result) -> Void + ) where Call.InnerRequestAad == (), Call.InnerResponseAad == () { + performAttestedCall(call, requestAad: (), request: request, completion: completion) + } + + func performAttestedCall( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + completion: @escaping (Result) -> Void + ) where Call.InnerResponseAad == () { + performAttestedCall(call, requestAad: requestAad, request: request) { + completion($0.map { $0.response }) + } + } + + func performAttestedCall( + _ call: Call, + request: Call.InnerRequest, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + ConnectionError> + ) -> Void + ) where Call.InnerRequestAad == () { + performAttestedCall(call, requestAad: (), request: request, completion: completion) + } + + func performAttestedCall( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + ConnectionError> + ) -> Void + ) { + inner.accessAsync(block: { inner, callback in + inner.performAttestedCallWithAuth( + call, + requestAad: requestAad, + request: request, + completion: callback) + }, completion: completion) + } +} + +extension AttestedGrpcConnection { + // Note: Because `SerialCallbackLock` is being used to wrap `AttestedConnection.Inner`, calls + // to `AttestedConnection.Inner` have exclusive access (other calls will be queued up) until the + // executing call invokes the completion handler that returns control back to + // `AttestedConnection`, at which point the block passed to the async `SerialCallbackLock` + // method that invoked the call to inner will complete and the next async `SerialCallbackLock` + // access block will execute. + // + // This means that calls to `AttestedConnection.Inner` can assume thread-safety until the call + // invokes the completion handler. + private struct Inner { + private let url: MobileCoinUrlProtocol + private let session: ConnectionSession + private let client: AttestableGrpcClient + private let attestAke: AttestAke + + private let responderId: String + private let attestationVerifier: AttestationVerifier + private let rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? + private let rngContext: Any? + + init( + client: AttestableGrpcClient, + config: AttestedConnectionConfigProtocol, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + self.url = config.url + self.session = ConnectionSession(config: config) + self.client = client + self.attestAke = AttestAke() + self.responderId = config.url.responderId + self.attestationVerifier = AttestationVerifier(attestation: config.attestation) + self.rng = rng + self.rngContext = rngContext + } + + func setAuthorization(credentials: BasicCredentials) { + session.authorizationCredentials = credentials + } + + func performAttestedCallWithAuth( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + ConnectionError> + ) -> Void + ) { + doPerformAttestedCallWithAuth( + call, + requestAad: requestAad, + request: request, + attestAkeCipher: attestAke.cipher.map { ($0, freshCipher: false) }, + completion: completion) + } + + private func doPerformAttestedCallWithAuth( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + attestAkeCipher: (AttestAke.Cipher, freshCipher: Bool)?, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + ConnectionError> + ) -> Void + ) { + if let (attestAkeCipher, freshCipher) = attestAkeCipher { + logger.info( + "Performing attested call... url: \(self.url)", + logFunction: false) + + doPerformAttestedCall( + call, + requestAad: requestAad, + request: request, + attestAkeCipher: attestAkeCipher + ) { + switch $0 { + case .success(let response): + logger.info( + "Attested call successful. url: \(self.url)", + logFunction: false) + + completion(.success(response)) + case .failure(.connectionError(let connectionError)): + let errorMessage = "Connection failure while performing attested call. " + + "url: \(self.url), error: \(connectionError)" + switch connectionError { + case .connectionFailure, .serverRateLimited: + logger.warning(errorMessage, logFunction: false) + case .authorizationFailure, .invalidServerResponse, + .attestationVerificationFailed, .outdatedClient: + logger.error(errorMessage, logFunction: false) + } + + completion(.failure(connectionError)) + case .failure(.attestationFailure): + self.attestAke.deattest() + + if freshCipher { + let errorMessage = + "Attestation failure with fresh auth. url: \(self.url)" + logger.warning(errorMessage, logFunction: false) + + completion(.failure(.invalidServerResponse(errorMessage))) + } else { + logger.info( + "Attestation failure using cached auth, reattesting... url: " + + "\(self.url)", + logFunction: false) + + self.doPerformAttestedCallWithAuth( + call, + requestAad: requestAad, + request: request, + attestAkeCipher: nil, + completion: completion) + } + } + } + } else { + logger.info( + "Peforming attestation... url: \(url)", + logFunction: false) + + doPerformAuthCall { + switch $0 { + case .success(let attestAkeCipher): + logger.info( + "Attestation successful. url: \(self.url)", + logFunction: false) + + self.doPerformAttestedCallWithAuth( + call, + requestAad: requestAad, + request: request, + attestAkeCipher: (attestAkeCipher, freshCipher: true), + completion: completion) + case .failure(let connectionError): + let errorMessage = "Connection failure while performing attestation. " + + "url: \(self.url), error: \(connectionError)" + switch connectionError { + case .connectionFailure, .serverRateLimited: + logger.warning(errorMessage, logFunction: false) + case .authorizationFailure, .invalidServerResponse, + .attestationVerificationFailed, .outdatedClient: + logger.error(errorMessage, logFunction: false) + } + + completion(.failure(connectionError)) + } + } + } + } + + private func doPerformAuthCall( + completion: @escaping (Result) -> Void + ) { + let request = attestAke.authBeginRequest( + responderId: responderId, + rng: rng, + rngContext: rngContext) + + doPerformCall( + AuthGrpcCallableWrapper(authCallable: client.authCallable), + request: request + ) { + completion( + $0.mapError { + switch $0 { + case .connectionError(let connectionError): + return connectionError + case .attestationFailure: + self.attestAke.deattest() + + return .invalidServerResponse( + "Attestation failure during auth. url: \(self.url)") + } + }.flatMap { response in + self.attestAke.authEnd( + authResponse: response, + attestationVerifier: self.attestationVerifier + ).mapError { + switch $0 { + case .invalidInput(let reason): + return .invalidServerResponse(reason) + case .attestationVerificationFailed(let reason): + return .attestationVerificationFailed(reason) + } + } + }) + } + } + + private func doPerformAttestedCall( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + attestAkeCipher: AttestAke.Cipher, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + AttestedGrpcConnectionError> + ) -> Void + ) { + guard let processedRequest = + call.processRequest( + requestAad: requestAad, + request: request, + attestAkeCipher: attestAkeCipher) + .mapError({ _ in .attestationFailure() }) + .successOr(completion: completion) + else { return } + + doPerformCall(call, request: processedRequest) { + completion($0.flatMap { response in + call.processResponse(response: response, attestAkeCipher: attestAkeCipher) + }) + } + } + + private func doPerformCall( + _ call: Call, + request: Call.Request, + completion: @escaping (Result) -> Void + ) { + let callOptions = requestCallOptions() + + call.call(request: request, callOptions: callOptions) { + completion(self.processResponse(callResult: $0)) + } + } + + private func requestCallOptions() -> CallOptions { + var callOptions = CallOptions() + session.addRequestHeaders(to: &callOptions.customMetadata) + return callOptions + } + + private func processResponse(callResult: UnaryCallResult) + -> Result + { + // Basic credential authorization failure + guard callResult.status.code != .unauthenticated else { + return .failure(.connectionError(.authorizationFailure("url: \(url)"))) + } + + // Attestation failure, reattest + guard callResult.status.code != .permissionDenied else { + return .failure(.attestationFailure()) + } + + guard callResult.status.isOk, let response = callResult.response else { + return .failure(.connectionError( + .connectionFailure("url: \(url), status: \(callResult.status)"))) + } + + if let initialMetadata = callResult.initialMetadata { + session.processResponse(headers: initialMetadata) + } + + return .success(response) + } + } +} diff --git a/Sources/Network/Connection/GrpcCallable/AttestedGrpcCallable.swift b/Sources/Network/GrpcConnection/GrpcCallable/AttestedGrpcCallable.swift similarity index 95% rename from Sources/Network/Connection/GrpcCallable/AttestedGrpcCallable.swift rename to Sources/Network/GrpcConnection/GrpcCallable/AttestedGrpcCallable.swift index ba564ce8..dbee7797 100644 --- a/Sources/Network/Connection/GrpcCallable/AttestedGrpcCallable.swift +++ b/Sources/Network/GrpcConnection/GrpcCallable/AttestedGrpcCallable.swift @@ -39,7 +39,8 @@ protocol AttestedGrpcCallable: GrpcCallable { func processResponse( response: Response, attestAkeCipher: AttestAke.Cipher - ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), AttestedConnectionError> + ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), + AttestedGrpcConnectionError> } extension AttestedGrpcCallable where InnerRequestAad == (), InnerRequest == Request { @@ -54,7 +55,8 @@ extension AttestedGrpcCallable where InnerRequestAad == (), InnerRequest == Requ extension AttestedGrpcCallable where InnerResponseAad == (), InnerResponse == Response { func processResponse(response: Response, attestAkeCipher: AttestAke.Cipher) - -> Result<(responseAad: InnerResponseAad, response: InnerResponse), AttestedConnectionError> + -> Result<(responseAad: InnerResponseAad, response: InnerResponse), + AttestedGrpcConnectionError> { .success((responseAad: (), response: response)) } @@ -85,7 +87,9 @@ extension AttestedGrpcCallable func processResponse( response: Attest_Message, attestAkeCipher: AttestAke.Cipher - ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), AttestedConnectionError> { + ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), + AttestedGrpcConnectionError> + { guard response.aad == Data() else { return .failure(.connectionError(.invalidServerResponse( "\(Self.self) received unexpected aad: " + @@ -133,7 +137,9 @@ extension AttestedGrpcCallable func processResponse( response: Attest_Message, attestAkeCipher: AttestAke.Cipher - ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), AttestedConnectionError> { + ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), + AttestedGrpcConnectionError> + { guard let responseAad = try? InnerResponseAad(serializedData: response.aad) else { return .failure(.connectionError(.invalidServerResponse( "Failed to deserialized attested message aad into \(InnerResponseAad.self). aad: " + diff --git a/Sources/Network/Connection/GrpcCallable/AuthGrpcCallable.swift b/Sources/Network/GrpcConnection/GrpcCallable/AuthGrpcCallable.swift similarity index 100% rename from Sources/Network/Connection/GrpcCallable/AuthGrpcCallable.swift rename to Sources/Network/GrpcConnection/GrpcCallable/AuthGrpcCallable.swift diff --git a/Sources/Network/Connection/GrpcCallable/GrpcCallable.swift b/Sources/Network/GrpcConnection/GrpcCallable/GrpcCallable.swift similarity index 100% rename from Sources/Network/Connection/GrpcCallable/GrpcCallable.swift rename to Sources/Network/GrpcConnection/GrpcCallable/GrpcCallable.swift diff --git a/Sources/Network/Connection/GrpcClient/AttestableGrpcClient.swift b/Sources/Network/GrpcConnection/GrpcClient/AttestableGrpcClient.swift similarity index 100% rename from Sources/Network/Connection/GrpcClient/AttestableGrpcClient.swift rename to Sources/Network/GrpcConnection/GrpcClient/AttestableGrpcClient.swift diff --git a/Sources/Network/Connection/GrpcClient/AuthGrpcCallableClient.swift b/Sources/Network/GrpcConnection/GrpcClient/AuthGrpcCallableClient.swift similarity index 100% rename from Sources/Network/Connection/GrpcClient/AuthGrpcCallableClient.swift rename to Sources/Network/GrpcConnection/GrpcClient/AuthGrpcCallableClient.swift diff --git a/Sources/Network/Connection/GrpcClient/GrpcCallableClient.swift b/Sources/Network/GrpcConnection/GrpcClient/GrpcCallableClient.swift similarity index 100% rename from Sources/Network/Connection/GrpcClient/GrpcCallableClient.swift rename to Sources/Network/GrpcConnection/GrpcClient/GrpcCallableClient.swift diff --git a/Sources/Network/GrpcConnection/GrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnection.swift new file mode 100644 index 00000000..5e28342f --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnection.swift @@ -0,0 +1,102 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC + +class GrpcConnection: ConnectionProtocol { + private let inner: SerialDispatchLock + + init(config: ConnectionConfigProtocol, targetQueue: DispatchQueue?) { + let inner = Inner(config: config) + self.inner = .init(inner, targetQueue: targetQueue) + } + + func setAuthorization(credentials: BasicCredentials) { + inner.accessAsync { + $0.setAuthorization(credentials: credentials) + } + } + + func performCall( + _ call: Call, + request: Call.Request, + completion: @escaping (Result) -> Void + ) { + func performCallCallback(callResult: UnaryCallResult) { + inner.accessAsync { + let result = $0.processResponse(callResult: callResult) + switch result { + case .success: + logger.info("Call complete. url: \($0.url)", logFunction: false) + case .failure(let connectionError): + let errorMessage = + "Connection failure. url: \($0.url), error: \(connectionError)" + switch connectionError { + case .connectionFailure, .serverRateLimited: + logger.warning(errorMessage, logFunction: false) + case .authorizationFailure, .invalidServerResponse, + .attestationVerificationFailed, .outdatedClient: + logger.error(errorMessage, logFunction: false) + } + } + completion(result) + } + } + + inner.accessAsync { + logger.info("Performing call... url: \($0.url)", logFunction: false) + + let callOptions = $0.requestCallOptions() + call.call(request: request, callOptions: callOptions, completion: performCallCallback) + } + } + + func performCall( + _ call: Call, + completion: @escaping (Result) -> Void + ) where Call.Request == () { + performCall(call, request: (), completion: completion) + } +} + +extension GrpcConnection { + private struct Inner { + let url: MobileCoinUrlProtocol + private let session: ConnectionSession + + init(config: ConnectionConfigProtocol) { + self.url = config.url + self.session = ConnectionSession(config: config) + } + + func setAuthorization(credentials: BasicCredentials) { + session.authorizationCredentials = credentials + } + + func requestCallOptions() -> CallOptions { + var callOptions = CallOptions() + session.addRequestHeaders(to: &callOptions.customMetadata) + return callOptions + } + + func processResponse(callResult: UnaryCallResult) + -> Result + { + guard callResult.status.code != .unauthenticated else { + return .failure(.authorizationFailure("url: \(url)")) + } + + guard callResult.status.isOk, let response = callResult.response else { + return .failure(.connectionFailure("url: \(url), status: \(callResult.status)")) + } + + if let initialMetadata = callResult.initialMetadata { + session.processResponse(headers: initialMetadata) + } + + return .success(response) + } + } +} diff --git a/Sources/Network/GrpcConnection/GrpcConnections/BlockchainGrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnections/BlockchainGrpcConnection.swift new file mode 100644 index 00000000..37396cd6 --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnections/BlockchainGrpcConnection.swift @@ -0,0 +1,45 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin +import SwiftProtobuf + +final class BlockchainGrpcConnection: GrpcConnection, BlockchainService { + private let client: ConsensusCommon_BlockchainAPIClient + + init( + config: ConnectionConfig, + channelManager: GrpcChannelManager, + targetQueue: DispatchQueue? + ) { + let channel = channelManager.channel(for: config) + self.client = ConsensusCommon_BlockchainAPIClient(channel: channel) + super.init(config: config, targetQueue: targetQueue) + } + + func getLastBlockInfo( + completion: + @escaping (Result) -> Void + ) { + performCall(GetLastBlockInfoCall(client: client), completion: completion) + } +} + +extension BlockchainGrpcConnection { + private struct GetLastBlockInfoCall: GrpcCallable { + let client: ConsensusCommon_BlockchainAPIClient + + func call( + request: (), + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + let unaryCall = + client.getLastBlockInfo(Google_Protobuf_Empty(), callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} diff --git a/Sources/Network/GrpcConnection/GrpcConnections/ConsensusGrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnections/ConsensusGrpcConnection.swift new file mode 100644 index 00000000..51d99edd --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnections/ConsensusGrpcConnection.swift @@ -0,0 +1,58 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +final class ConsensusGrpcConnection: AttestedGrpcConnection, ConsensusService { + private let client: ConsensusClient_ConsensusClientAPIClient + + init( + config: AttestedConnectionConfig, + channelManager: GrpcChannelManager, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + let channel = channelManager.channel(for: config) + self.client = ConsensusClient_ConsensusClientAPIClient(channel: channel) + super.init( + client: Attest_AttestedApiClient(channel: channel), + config: config, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext) + } + + func proposeTx( + _ tx: External_Tx, + completion: @escaping (Result) -> Void + ) { + performAttestedCall( + ProposeTxCall(client: client), + request: tx, + completion: completion) + } +} + +extension ConsensusGrpcConnection { + private struct ProposeTxCall: AttestedGrpcCallable { + typealias InnerRequest = External_Tx + typealias InnerResponse = ConsensusCommon_ProposeTxResponse + + let client: ConsensusClient_ConsensusClientAPIClient + + func call( + request: Attest_Message, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + let unaryCall = client.clientTxPropose(request, callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} + +extension Attest_AttestedApiClient: AuthGrpcCallableClient {} diff --git a/Sources/Network/GrpcConnection/GrpcConnections/FogBlockGrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnections/FogBlockGrpcConnection.swift new file mode 100644 index 00000000..1241ff3c --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnections/FogBlockGrpcConnection.swift @@ -0,0 +1,43 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +final class FogBlockGrpcConnection: GrpcConnection, FogBlockService { + private let client: FogLedger_FogBlockAPIClient + + init( + config: ConnectionConfig, + channelManager: GrpcChannelManager, + targetQueue: DispatchQueue? + ) { + let channel = channelManager.channel(for: config) + self.client = FogLedger_FogBlockAPIClient(channel: channel) + super.init(config: config, targetQueue: targetQueue) + } + + func getBlocks( + request: FogLedger_BlockRequest, + completion: @escaping (Result) -> Void + ) { + performCall(GetBlocksCall(client: client), request: request, completion: completion) + } +} + +extension FogBlockGrpcConnection { + private struct GetBlocksCall: GrpcCallable { + let client: FogLedger_FogBlockAPIClient + + func call( + request: FogLedger_BlockRequest, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + let unaryCall = client.getBlocks(request, callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} diff --git a/Sources/Network/GrpcConnection/GrpcConnections/FogKeyImageGrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnections/FogKeyImageGrpcConnection.swift new file mode 100644 index 00000000..86b9ae44 --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnections/FogKeyImageGrpcConnection.swift @@ -0,0 +1,58 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +final class FogKeyImageGrpcConnection: AttestedGrpcConnection, FogKeyImageService { + private let client: FogLedger_FogKeyImageAPIClient + + init( + config: AttestedConnectionConfig, + channelManager: GrpcChannelManager, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + let channel = channelManager.channel(for: config) + self.client = FogLedger_FogKeyImageAPIClient(channel: channel) + super.init( + client: self.client, + config: config, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext) + } + + func checkKeyImages( + request: FogLedger_CheckKeyImagesRequest, + completion: @escaping (Result) -> Void + ) { + performAttestedCall( + CheckKeyImagesCall(client: client), + request: request, + completion: completion) + } +} + +extension FogKeyImageGrpcConnection { + private struct CheckKeyImagesCall: AttestedGrpcCallable { + typealias InnerRequest = FogLedger_CheckKeyImagesRequest + typealias InnerResponse = FogLedger_CheckKeyImagesResponse + + let client: FogLedger_FogKeyImageAPIClient + + func call( + request: Attest_Message, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + let unaryCall = client.checkKeyImages(request, callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} + +extension FogLedger_FogKeyImageAPIClient: AuthGrpcCallableClient {} diff --git a/Sources/Network/GrpcConnection/GrpcConnections/FogMerkleProofGrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnections/FogMerkleProofGrpcConnection.swift new file mode 100644 index 00000000..f6682e67 --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnections/FogMerkleProofGrpcConnection.swift @@ -0,0 +1,58 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +final class FogMerkleProofGrpcConnection: AttestedGrpcConnection, FogMerkleProofService { + private let client: FogLedger_FogMerkleProofAPIClient + + init( + config: AttestedConnectionConfig, + channelManager: GrpcChannelManager, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + let channel = channelManager.channel(for: config) + self.client = FogLedger_FogMerkleProofAPIClient(channel: channel) + super.init( + client: self.client, + config: config, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext) + } + + func getOutputs( + request: FogLedger_GetOutputsRequest, + completion: @escaping (Result) -> Void + ) { + performAttestedCall( + GetOutputsCall(client: client), + request: request, + completion: completion) + } +} + +extension FogMerkleProofGrpcConnection { + private struct GetOutputsCall: AttestedGrpcCallable { + typealias InnerRequest = FogLedger_GetOutputsRequest + typealias InnerResponse = FogLedger_GetOutputsResponse + + let client: FogLedger_FogMerkleProofAPIClient + + func call( + request: Attest_Message, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + let unaryCall = client.getOutputs(request, callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} + +extension FogLedger_FogMerkleProofAPIClient: AuthGrpcCallableClient {} diff --git a/Sources/Network/GrpcConnection/GrpcConnections/FogReportGrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnections/FogReportGrpcConnection.swift new file mode 100644 index 00000000..7945d33c --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnections/FogReportGrpcConnection.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +final class FogReportGrpcConnection: ArbitraryGrpcConnection, FogReportService { + private let client: Report_ReportAPIClient + + init(url: FogUrl, channelManager: GrpcChannelManager, targetQueue: DispatchQueue?) { + let channel = channelManager.channel(for: url) + self.client = Report_ReportAPIClient(channel: channel) + super.init(url: url, targetQueue: targetQueue) + } + + func getReports( + request: Report_ReportRequest, + completion: @escaping (Result) -> Void + ) { + performCall(GetReportsCall(client: client), request: request, completion: completion) + } +} + +extension FogReportGrpcConnection { + private struct GetReportsCall: GrpcCallable { + let client: Report_ReportAPIClient + + func call( + request: Report_ReportRequest, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + let unaryCall = client.getReports(request, callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} diff --git a/Sources/Network/GrpcConnection/GrpcConnections/FogUntrustedTxOutGrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnections/FogUntrustedTxOutGrpcConnection.swift new file mode 100644 index 00000000..13d1e794 --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnections/FogUntrustedTxOutGrpcConnection.swift @@ -0,0 +1,43 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +final class FogUntrustedTxOutGrpcConnection: GrpcConnection, FogUntrustedTxOutService { + private let client: FogLedger_FogUntrustedTxOutApiClient + + init( + config: ConnectionConfig, + channelManager: GrpcChannelManager, + targetQueue: DispatchQueue? + ) { + let channel = channelManager.channel(for: config) + self.client = FogLedger_FogUntrustedTxOutApiClient(channel: channel) + super.init(config: config, targetQueue: targetQueue) + } + + func getTxOuts( + request: FogLedger_TxOutRequest, + completion: @escaping (Result) -> Void + ) { + performCall(GetTxOutsCall(client: client), request: request, completion: completion) + } +} + +extension FogUntrustedTxOutGrpcConnection { + private struct GetTxOutsCall: GrpcCallable { + let client: FogLedger_FogUntrustedTxOutApiClient + + func call( + request: FogLedger_TxOutRequest, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + let unaryCall = client.getTxOuts(request, callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} diff --git a/Sources/Network/GrpcConnection/GrpcConnections/FogViewGrpcConnection.swift b/Sources/Network/GrpcConnection/GrpcConnections/FogViewGrpcConnection.swift new file mode 100644 index 00000000..8842ace2 --- /dev/null +++ b/Sources/Network/GrpcConnection/GrpcConnections/FogViewGrpcConnection.swift @@ -0,0 +1,61 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +final class FogViewGrpcConnection: AttestedGrpcConnection, FogViewService { + private let client: FogView_FogViewAPIClient + + init( + config: AttestedConnectionConfig, + channelManager: GrpcChannelManager, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + let channel = channelManager.channel(for: config) + self.client = FogView_FogViewAPIClient(channel: channel) + super.init( + client: self.client, + config: config, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext) + } + + func query( + requestAad: FogView_QueryRequestAAD, + request: FogView_QueryRequest, + completion: @escaping (Result) -> Void + ) { + performAttestedCall( + EnclaveRequestCall(client: client), + requestAad: requestAad, + request: request, + completion: completion) + } +} + +extension FogViewGrpcConnection { + private struct EnclaveRequestCall: AttestedGrpcCallable { + typealias InnerRequestAad = FogView_QueryRequestAAD + typealias InnerRequest = FogView_QueryRequest + typealias InnerResponse = FogView_QueryResponse + + let client: FogView_FogViewAPIClient + + func call( + request: Attest_Message, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + let unaryCall = client.query(request, callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} + +extension FogView_FogViewAPIClient: AuthGrpcCallableClient {} diff --git a/Sources/Network/HttpConnection/AttestedHttpConnection.swift b/Sources/Network/HttpConnection/AttestedHttpConnection.swift new file mode 100644 index 00000000..48149366 --- /dev/null +++ b/Sources/Network/HttpConnection/AttestedHttpConnection.swift @@ -0,0 +1,358 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +// swiftlint:disable closure_body_length cyclomatic_complexity function_body_length +// swiftlint:disable multiline_function_chains operator_usage_whitespace + +import Foundation +import GRPC +import LibMobileCoin +import NIO +import NIOHPACK + +enum AttestedHttpConnectionError: Error { + case connectionError(ConnectionError) + case attestationFailure(String = String()) +} + +extension AttestedHttpConnectionError: CustomStringConvertible { + var description: String { + "Attested connection error: " + { + switch self { + case .connectionError(let connectionError): + return "\(connectionError)" + case .attestationFailure(let reason): + return "Attestation failure\(!reason.isEmpty ? ": \(reason)" : "")" + } + }() + } +} + +class AttestedHttpConnection: ConnectionProtocol { + private let inner: SerialCallbackLock + + init( + client: AttestableHttpClient, + config: AttestedConnectionConfigProtocol, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + let inner = Inner(client: client, config: config, rng: rng, rngContext: rngContext) + self.inner = .init(inner, targetQueue: targetQueue) + } + + func setAuthorization(credentials: BasicCredentials) { + inner.priorityAccessAsync { + $0.setAuthorization(credentials: credentials) + } + } + + func performAttestedCall( + _ call: Call, + request: Call.InnerRequest, + completion: @escaping (Result) -> Void + ) where Call.InnerRequestAad == (), Call.InnerResponseAad == () { + performAttestedCall(call, requestAad: (), request: request, completion: completion) + } + + func performAttestedCall( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + completion: @escaping (Result) -> Void + ) where Call.InnerResponseAad == () { + performAttestedCall(call, requestAad: requestAad, request: request) { + completion($0.map { $0.response }) + } + } + + func performAttestedCall( + _ call: Call, + request: Call.InnerRequest, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + ConnectionError> + ) -> Void + ) where Call.InnerRequestAad == () { + performAttestedCall(call, requestAad: (), request: request, completion: completion) + } + + func performAttestedCall( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + ConnectionError> + ) -> Void + ) { + inner.accessAsync(block: { inner, callback in + inner.performAttestedCallWithAuth( + call, + requestAad: requestAad, + request: request, + completion: callback) + }, completion: completion) + } +} + +extension AttestedHttpConnection { + // Note: Because `SerialCallbackLock` is being used to wrap `AttestedConnection.Inner`, calls + // to `AttestedConnection.Inner` have exclusive access (other calls will be queued up) until the + // executing call invokes the completion handler that returns control back to + // `AttestedConnection`, at which point the block passed to the async `SerialCallbackLock` + // method that invoked the call to inner will complete and the next async `SerialCallbackLock` + // access block will execute. + // + // This means that calls to `AttestedConnection.Inner` can assume thread-safety until the call + // invokes the completion handler. + private struct Inner { + private let url: MobileCoinUrlProtocol + private let session: ConnectionSession + private let client: AttestableHttpClient + private let attestAke: AttestAke + + private let responderId: String + private let attestationVerifier: AttestationVerifier + private let rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? + private let rngContext: Any? + + init( + client: AttestableHttpClient, + config: AttestedConnectionConfigProtocol, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + self.url = config.url + self.session = ConnectionSession(config: config) + self.client = client + self.attestAke = AttestAke() + self.responderId = config.url.responderId + self.attestationVerifier = AttestationVerifier(attestation: config.attestation) + self.rng = rng + self.rngContext = rngContext + } + + func setAuthorization(credentials: BasicCredentials) { + session.authorizationCredentials = credentials + } + + func performAttestedCallWithAuth( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + ConnectionError> + ) -> Void + ) { + doPerformAttestedCallWithAuth( + call, + requestAad: requestAad, + request: request, + attestAkeCipher: attestAke.cipher.map { ($0, freshCipher: false) }, + completion: completion) + } + + private func doPerformAttestedCallWithAuth( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + attestAkeCipher: (AttestAke.Cipher, freshCipher: Bool)?, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + ConnectionError> + ) -> Void + ) { + if let (attestAkeCipher, freshCipher) = attestAkeCipher { + logger.info( + "Performing attested call... url: \(self.url)", + logFunction: false) + + doPerformAttestedCall( + call, + requestAad: requestAad, + request: request, + attestAkeCipher: attestAkeCipher + ) { + switch $0 { + case .success(let response): + logger.info( + "Attested call successful. url: \(self.url)", + logFunction: false) + + completion(.success(response)) + case .failure(.connectionError(let connectionError)): + let errorMessage = "Connection failure while performing attested call. " + + "url: \(self.url), error: \(connectionError)" + switch connectionError { + case .connectionFailure, .serverRateLimited: + logger.warning(errorMessage, logFunction: false) + case .authorizationFailure, .invalidServerResponse, + .attestationVerificationFailed, .outdatedClient: + logger.error(errorMessage, logFunction: false) + } + + completion(.failure(connectionError)) + case .failure(.attestationFailure): + self.attestAke.deattest() + + if freshCipher { + let errorMessage = + "Attestation failure with fresh auth. url: \(self.url)" + logger.warning(errorMessage, logFunction: false) + + completion(.failure(.invalidServerResponse(errorMessage))) + } else { + logger.info( + "Attestation failure using cached auth, reattesting... url: " + + "\(self.url)", + logFunction: false) + + self.doPerformAttestedCallWithAuth( + call, + requestAad: requestAad, + request: request, + attestAkeCipher: nil, + completion: completion) + } + } + } + } else { + logger.info( + "Peforming attestation... url: \(url)", + logFunction: false) + + doPerformAuthCall { + switch $0 { + case .success(let attestAkeCipher): + logger.info( + "Attestation successful. url: \(self.url)", + logFunction: false) + + self.doPerformAttestedCallWithAuth( + call, + requestAad: requestAad, + request: request, + attestAkeCipher: (attestAkeCipher, freshCipher: true), + completion: completion) + case .failure(let connectionError): + let errorMessage = "Connection failure while performing attestation. " + + "url: \(self.url), error: \(connectionError)" + switch connectionError { + case .connectionFailure, .serverRateLimited: + logger.warning(errorMessage, logFunction: false) + case .authorizationFailure, .invalidServerResponse, + .attestationVerificationFailed, .outdatedClient: + logger.error(errorMessage, logFunction: false) + } + + completion(.failure(connectionError)) + } + } + } + } + + private func doPerformAuthCall( + completion: @escaping (Result) -> Void + ) { + let request = attestAke.authBeginRequest( + responderId: responderId, + rng: rng, + rngContext: rngContext) + + doPerformCall( + AuthHttpCallableWrapper(authCallable: client.authCallable), + request: request + ) { + completion( + $0.mapError { + switch $0 { + case .connectionError(let connectionError): + return connectionError + case .attestationFailure: + self.attestAke.deattest() + + return .invalidServerResponse( + "Attestation failure during auth. url: \(self.url)") + } + }.flatMap { response in + self.attestAke.authEnd( + authResponse: response, + attestationVerifier: self.attestationVerifier + ).mapError { + switch $0 { + case .invalidInput(let reason): + return .invalidServerResponse(reason) + case .attestationVerificationFailed(let reason): + return .attestationVerificationFailed(reason) + } + } + }) + } + } + + private func doPerformAttestedCall( + _ call: Call, + requestAad: Call.InnerRequestAad, + request: Call.InnerRequest, + attestAkeCipher: AttestAke.Cipher, + completion: @escaping ( + Result<(responseAad: Call.InnerResponseAad, response: Call.InnerResponse), + AttestedHttpConnectionError> + ) -> Void + ) { + guard let processedRequest = + call.processRequest( + requestAad: requestAad, + request: request, + attestAkeCipher: attestAkeCipher) + .mapError({ _ in .attestationFailure() }) + .successOr(completion: completion) + else { return } + + doPerformCall(call, request: processedRequest) { + completion($0.flatMap { response in + call.processResponse(response: response, attestAkeCipher: attestAkeCipher) + }) + } + } + + private func doPerformCall( + _ call: Call, + request: Call.Request, + completion: @escaping (Result) -> Void + ) { + call.call(request: request) { + completion(self.processResponse(callResult: $0)) + } + } + + private func processResponse(callResult: HttpCallResult) + -> Result + { + // Basic credential authorization failure + guard callResult.status.isOk else { + return .failure(.connectionError(.authorizationFailure("url: \(url)"))) + } + + // Attestation failure, reattest + guard callResult.status.code != 403 else { + return .failure(.attestationFailure()) + } + + guard callResult.status.code == 200, let response = callResult.response else { + return .failure(.connectionError( + .connectionFailure("url: \(url), status: \(callResult.status.code)"))) + } + + if let initialMetadata = callResult.initialMetadata { + session.processResponse(headers: initialMetadata.allHeaderFields) + } + + return .success(response) + } + } +} diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTP.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTP.swift new file mode 100644 index 00000000..a23bb3a5 --- /dev/null +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTP.swift @@ -0,0 +1,11 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import SwiftProtobuf + + +public enum HTTP { +// public typealias CallOptions = URLSessionConfiguration +} diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift new file mode 100644 index 00000000..186ad14b --- /dev/null +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift @@ -0,0 +1,18 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + + +public struct HTTPCallOptions { + var headers: [String : String] + var timeoutIntervalForRequest : TimeInterval? = nil + var timeoutIntervalForResource : TimeInterval? = nil + +} +extension HTTPCallOptions { + public init() { + self.init(headers: [:], timeoutIntervalForRequest: 30, timeoutIntervalForResource: 30) + } +} diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift new file mode 100644 index 00000000..c4fcf5e3 --- /dev/null +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift @@ -0,0 +1,19 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import SwiftProtobuf + +/// A HTTP client. +public protocol HTTPClient { + /// The call options to use should the user not provide per-call options. + var defaultHTTPCallOptions: HTTPCallOptions { get set } +} + +extension HTTPClient { + public func makeUnaryCall(path: String, request: Request, callOptions: HTTPCallOptions? = nil, responseType: Response.Type = Response.self) -> HTTPUnaryCall where Request : SwiftProtobuf.Message, Response : SwiftProtobuf.Message { + HTTPUnaryCall(path: path, options: callOptions, requestPayload: request, responseType: responseType) + } +} + diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift new file mode 100644 index 00000000..c22e95a8 --- /dev/null +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift @@ -0,0 +1,69 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import SwiftProtobuf + + +public protocol HTTPClientCall { + /// The type of the request message for the call. + associatedtype RequestPayload: SwiftProtobuf.Message + + /// The type of the response message for the call. + associatedtype ResponsePayload: SwiftProtobuf.Message + + /// The resource path (generated) + var path: String { get } + + /// The http method to use for the call + var method: HTTPMethod { get } + + var requestPayload: RequestPayload? { get set } + + /// The response message returned from the service if the call is successful. This may be failed + /// if the call encounters an error. + /// + /// Callers should rely on the `status` of the call for the canonical outcome. + var responseType: ResponsePayload.Type { get set } + + /// The options used to make the session. + var options: HTTPCallOptions? { get } + + /// Initial response metadata. + var initialMetadata: HTTPURLResponse? { get } + + /// Status of this call which may be populated by the server or client. + /// + /// The client may populate the status if, for example, it was not possible to connect to the service. + /// + /// Note: despite `GRPCStatus` conforming to `Error`, the value will be __always__ delivered as a __success__ + /// result even if the status represents a __negative__ outcome. This future will __never__ be fulfilled + /// with an error. + var status: HTTPStatus? { get } + + /// Cancel the current call. + /// + /// Closes the HTTP/2 stream once it becomes available. Additional writes to the channel will be ignored. + /// Any unfulfilled promises will be failed with a cancelled status (excepting `status` which will be + /// succeeded, if not already succeeded). + func cancel() +} + +//public struct HTTPRestCall : HTTPClientCall { +// +// /// The options used in the URLSession +// public var options: HTTP.CallOptions? +// +// /// Cancel this session if it hasn't already completed. +// public func cancel() { +// +// } +// +// /// The initial metadata returned from the server. +// public var initialMetadata: HTTPURLResponse? +// +// /// The final status of the the session. +// public var status: HTTPStatus? +//} +// diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift new file mode 100644 index 00000000..78bfed93 --- /dev/null +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import SwiftProtobuf + +/// A unary http call. The request is sent on initialization. +/// +/// Note: while this object is a `struct`, its implementation delegates to `Call`. It therefore +/// has reference semantics. +public struct HTTPUnaryCall : HTTPClientCall { + public var path: String + + public var method: HTTPMethod = .POST + + public var response: ResponsePayload? + + /// The options used in the URLSession + public var options: HTTPCallOptions? + + /// Cancel this session if it hasn't already completed. + public func cancel() { } + + /// The initial metadata returned from the server. + public var initialMetadata: HTTPURLResponse? = nil + + /// The request message sent to the server + public var requestPayload: RequestPayload? + + /// The response returned by the server. + public var responseType: ResponsePayload.Type + public var responsePayload: ResponsePayload? + + /// The final status of the the RPC. + public var status: HTTPStatus? = nil +} diff --git a/Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift b/Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift new file mode 100644 index 00000000..bc810437 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift @@ -0,0 +1,162 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin +import SwiftProtobuf + +//enum AttestedCallError: Error { +// case aeadError(AeadError) +// case invalidInput(String) +//} +// +//extension AttestedCallError: CustomStringConvertible { +// var description: String { +// "Attested call error: " + { +// switch self { +// case .aeadError(let innerError): +// return "\(innerError)" +// case .invalidInput(let reason): +// return "Invalid input: \(reason)" +// } +// }() +// } +//} + +protocol AttestedHttpCallable: HttpCallable { + associatedtype InnerRequestAad = () + associatedtype InnerRequest + associatedtype InnerResponseAad = () + associatedtype InnerResponse + + func processRequest( + requestAad: InnerRequestAad, + request: InnerRequest, + attestAkeCipher: AttestAke.Cipher + ) -> Result + + func processResponse( + response: Response, + attestAkeCipher: AttestAke.Cipher + ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), + AttestedHttpConnectionError> +} + +extension AttestedHttpCallable where InnerRequestAad == (), InnerRequest == Request { + func processRequest( + requestAad: InnerRequestAad, + request: InnerRequest, + attestAkeCipher: AttestAke.Cipher + ) -> Result { + .success(request) + } +} + +extension AttestedHttpCallable where InnerResponseAad == (), InnerResponse == Response { + func processResponse(response: Response, attestAkeCipher: AttestAke.Cipher) + -> Result<(responseAad: InnerResponseAad, response: InnerResponse), + AttestedHttpConnectionError> + { + .success((responseAad: (), response: response)) + } +} + +extension AttestedHttpCallable + where InnerRequestAad == (), + Request == Attest_Message, + InnerRequest: InfallibleDataSerializable +{ + func processRequest( + requestAad: InnerRequestAad, + request: InnerRequest, + attestAkeCipher: AttestAke.Cipher + ) -> Result { + let aad = Data() + let plaintext = request.serializedDataInfallible + + return attestAkeCipher.encryptMessage(aad: aad, plaintext: plaintext) + } +} + +extension AttestedHttpCallable + where InnerResponseAad == (), + Response == Attest_Message, + InnerResponse: Message +{ + func processResponse( + response: Attest_Message, + attestAkeCipher: AttestAke.Cipher + ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), + AttestedHttpConnectionError> + { + guard response.aad == Data() else { + return .failure(.connectionError(.invalidServerResponse( + "\(Self.self) received unexpected aad: " + + "\(redacting: response.aad.base64EncodedString()), message: " + + "\(redacting: response.serializedDataInfallible.base64EncodedString())"))) + } + + return attestAkeCipher.decryptMessage(response) + .mapError { _ in .attestationFailure() } + .flatMap { plaintext in + guard let response = try? InnerResponse(serializedData: plaintext) else { + return .failure(.connectionError(.invalidServerResponse( + "Failed to deserialized attested message plaintext into " + + "\(InnerResponse.self). plaintext: " + + "\(redacting: plaintext.base64EncodedString())"))) + } + + return .success((responseAad: (), response: response)) + } + } +} + +extension AttestedHttpCallable + where InnerRequestAad: InfallibleDataSerializable, + Request == Attest_Message, + InnerRequest: InfallibleDataSerializable +{ + func processRequest( + requestAad: InnerRequestAad, + request: InnerRequest, + attestAkeCipher: AttestAke.Cipher + ) -> Result { + let aad = requestAad.serializedDataInfallible + let plaintext = request.serializedDataInfallible + + return attestAkeCipher.encryptMessage(aad: aad, plaintext: plaintext) + } +} + +extension AttestedHttpCallable + where InnerResponseAad: Message, + Response == Attest_Message, + InnerResponse: Message +{ + func processResponse( + response: Attest_Message, + attestAkeCipher: AttestAke.Cipher + ) -> Result<(responseAad: InnerResponseAad, response: InnerResponse), + AttestedHttpConnectionError> + { + guard let responseAad = try? InnerResponseAad(serializedData: response.aad) else { + return .failure(.connectionError(.invalidServerResponse( + "Failed to deserialized attested message aad into \(InnerResponseAad.self). aad: " + + "\(redacting: response.aad.base64EncodedString())"))) + } + + return attestAkeCipher.decryptMessage(response) + .mapError { _ in .attestationFailure() } + .flatMap { plaintext in + guard let plaintextResponse = try? InnerResponse(serializedData: plaintext) else { + return .failure(.connectionError(.invalidServerResponse( + "Failed to deserialized attested message plaintext into " + + "\(InnerResponse.self). plaintext: " + + "\(redacting: plaintext.base64EncodedString())"))) + } + + return .success((responseAad: responseAad, response: plaintextResponse)) + } + } +} diff --git a/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallable.swift b/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallable.swift new file mode 100644 index 00000000..6fe0d25a --- /dev/null +++ b/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallable.swift @@ -0,0 +1,29 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +protocol AuthHttpCallable { + func auth( + _ request: Attest_AuthMessage, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void) +} + +struct AuthHttpCallableWrapper: HttpCallable { + typealias Request = Attest_AuthMessage + typealias Response = Attest_AuthMessage + + let authCallable: AuthHttpCallable + + func call( + request: Attest_AuthMessage, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + authCallable.auth(request, callOptions: callOptions, completion: completion) + } +} diff --git a/Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift b/Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift new file mode 100644 index 00000000..5724011c --- /dev/null +++ b/Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift @@ -0,0 +1,22 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC + +public protocol HttpCallable { + associatedtype Request + associatedtype Response + + func call( + request: Request, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void) +} + +extension HttpCallable { + func call(request: Request, completion: @escaping (HttpCallResult) -> Void) { + call(request: request, callOptions: nil, completion: completion) + } +} diff --git a/Sources/Network/HttpConnection/HttpClient/AttestableHttpClient.swift b/Sources/Network/HttpConnection/HttpClient/AttestableHttpClient.swift new file mode 100644 index 00000000..d07afa26 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpClient/AttestableHttpClient.swift @@ -0,0 +1,9 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + +protocol AttestableHttpClient { + var authCallable: AuthHttpCallable { get } +} diff --git a/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift b/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift new file mode 100644 index 00000000..d38fa4e2 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift @@ -0,0 +1,28 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import LibMobileCoin + +protocol AuthHttpCallableClient: AttestableHttpClient, AuthHttpCallable { + func auth(_ request: Attest_AuthMessage, callOptions: CallOptions?) + -> UnaryCall +} + +extension AuthHttpCallableClient { + var authCallable: AuthHttpCallable { + self + } +} + +extension AuthHttpCallableClient { + func auth( + _ request: Attest_AuthMessage, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + auth(request, callOptions: callOptions).callResult.whenSuccess(completion) + } +} diff --git a/Sources/Network/HttpConnection/HttpClient/HttpCallableClient.swift b/Sources/Network/HttpConnection/HttpClient/HttpCallableClient.swift new file mode 100644 index 00000000..47b4c3cc --- /dev/null +++ b/Sources/Network/HttpConnection/HttpClient/HttpCallableClient.swift @@ -0,0 +1,20 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC + +protocol HttpCallableClient: HttpCallable { + func call(request: Request, callOptions: CallOptions?) -> UnaryCall +} + +extension HttpCallableClient { + func call( + request: Request, + callOptions: CallOptions?, + completion: @escaping (UnaryCallResult) -> Void + ) { + call(request: request, callOptions: callOptions).callResult.whenSuccess(completion) + } +} diff --git a/Sources/Network/HttpConnection/HttpClientWrapper.swift b/Sources/Network/HttpConnection/HttpClientWrapper.swift new file mode 100644 index 00000000..2cdc7fa4 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpClientWrapper.swift @@ -0,0 +1,56 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +// swiftlint:disable multiline_parameters_brackets + +import Foundation +import LibMobileCoin +import GRPC + +final class HttpClientWrapper: AttestableHttpClient { + + private let httpRequester: HttpRequester? + private let headers: [String: String] + private let config: ConnectionConfigProtocol + private let httpMethod = HTTPMethod.POST + var authCallable: AuthHttpCallable { + get { + TestAuthCallable() + } + } + + required init(config: ConnectionConfigProtocol, httpRequester: HttpRequester?) { + self.httpRequester = httpRequester + self.config = config + self.headers = [:] + } + + func request( + body: Data?, + completion: @escaping (Result) -> Void) { + if let requester = httpRequester { + requester.request( + url: config.url.url, + method: httpMethod, + headers: headers, + body: body) { httpResponse in + switch httpResponse { + case .success(let response): + return completion(.success(response.responseData)) + case .failure(let error): + return completion(.failure(error)) + } + } + } else { + return completion( + .failure(InvalidInputError("HttpRequester was not set in the Network config"))) + } + } +} + +public struct TestAuthCallable : AuthHttpCallable { + func auth(_ request: Attest_AuthMessage, callOptions: HTTPCallOptions?, completion: @escaping (HttpCallResult) -> Void) { + print("Implement") + } +} diff --git a/Sources/Network/HttpConnection/HttpConnection.swift b/Sources/Network/HttpConnection/HttpConnection.swift new file mode 100644 index 00000000..c91e2402 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnection.swift @@ -0,0 +1,98 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + +class HttpConnection: ConnectionProtocol { + private let inner: SerialDispatchLock + + init(config: ConnectionConfigProtocol, targetQueue: DispatchQueue?) { + let inner = Inner(config: config) + self.inner = .init(inner, targetQueue: targetQueue) + } + + func setAuthorization(credentials: BasicCredentials) { + inner.accessAsync { + $0.setAuthorization(credentials: credentials) + } + } + + func performCall( + _ call: Call, + request: Call.Request, + completion: @escaping (Result) -> Void + ) { + func performCallCallback(callResult: HttpCallResult) { + inner.accessAsync { + let result = $0.processResponse(callResult: callResult) + switch result { + case .success: + logger.info("Call complete. url: \($0.url)", logFunction: false) + case .failure(let connectionError): + let errorMessage = + "Connection failure. url: \($0.url), error: \(connectionError)" + switch connectionError { + case .connectionFailure, .serverRateLimited: + logger.warning(errorMessage, logFunction: false) + case .authorizationFailure, .invalidServerResponse, + .attestationVerificationFailed, .outdatedClient: + logger.error(errorMessage, logFunction: false) + } + } + completion(result) + } + } + + inner.accessAsync { + logger.info("Performing call... url: \($0.url)", logFunction: false) + + call.call(request: request, callOptions: $0.requestCallOptions(), completion: performCallCallback) + } + } + + func performCall( + _ call: Call, + completion: @escaping (Result) -> Void + ) where Call.Request == () { + performCall(call, request: (), completion: completion) + } +} + +extension HttpConnection { + private struct Inner { + let url: MobileCoinUrlProtocol + private let session: ConnectionSession + + init(config: ConnectionConfigProtocol) { + self.url = config.url + self.session = ConnectionSession(config: config) + } + + func setAuthorization(credentials: BasicCredentials) { + session.authorizationCredentials = credentials + } + + func requestCallOptions() -> HTTPCallOptions { + HTTPCallOptions(headers: session.requestHeaders) + } + + func processResponse(callResult: HttpCallResult) + -> Result + { + guard callResult.status.code != 403 else { + return .failure(.authorizationFailure("url: \(url)")) + } + + guard callResult.status.isOk, let response = callResult.response else { + return .failure(.connectionFailure("url: \(url), status: \(callResult.status)")) + } + + if let initialMetadata = callResult.initialMetadata { + session.processResponse(headers: initialMetadata.allHeaderFields) + } + + return .success(response) + } + } +} diff --git a/Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift new file mode 100644 index 00000000..38a12565 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift @@ -0,0 +1,54 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin +import SwiftProtobuf + +final class BlockchainHttpConnection: HttpConnection, BlockchainService { + private let client: ConsensusCommon_BlockchainAPIRestClient + private let requester: HTTPRequester + + init( + config: ConnectionConfig, + targetQueue: DispatchQueue? + ) { + self.client = ConsensusCommon_BlockchainAPIRestClient() + self.requester = HTTPRequester(baseUrl: config.url.httpBasedUrl, trustRoots: config.trustRoots) + super.init(config: config, targetQueue: targetQueue) + } + + func getLastBlockInfo( + completion: + @escaping (Result) -> Void + ) { + performCall(GetLastBlockInfoCall(client: client, requester: requester), completion: completion) + } +} + +extension BlockchainHttpConnection { + private struct GetLastBlockInfoCall: HttpCallable { + let client: ConsensusCommon_BlockchainAPIRestClient + let requester: HTTPRequester + + func call( + request: (), + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + let clientCall = client.getLastBlockInfo(Google_Protobuf_Empty()) + requester.makeRequest(call: clientCall) { result in + switch result { + case .success(let callResult): + completion(callResult) + case .failure(let error): + logger.error(error.localizedDescription) + } + } +// let unaryCall = +// client.getLastBlockInfo(Google_Protobuf_Empty(), callOptions: callOptions) +// unaryCall.callResult.whenSuccess(completion) + } + } +} diff --git a/Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift new file mode 100644 index 00000000..cfe564f5 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift @@ -0,0 +1,19 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin + +final class ConsensusHttpConnection: ConnectionProtocol, ConsensusService { + func proposeTx( + _ tx: External_Tx, + completion: @escaping (Result) -> Void + ) { + + } + + func setAuthorization(credentials: BasicCredentials) { + + } +} diff --git a/Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift new file mode 100644 index 00000000..ec975509 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift @@ -0,0 +1,56 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin + + +//final class FogBlockHttpConnection: ConnectionProtocol, FogBlockService { +// func getBlocks( +// request: FogLedger_BlockRequest, +// completion: @escaping (Result) -> Void +// ) { +// } +// +// func setAuthorization(credentials: BasicCredentials) { +// +// } +//} + +final class FogBlockHttpConnection: HttpConnection, FogBlockService { + private let client: FogLedger_FogBlockAPIRestClient + private let requester: HTTPRequester + + init( + config: ConnectionConfig, + targetQueue: DispatchQueue? + ) { + self.client = FogLedger_FogBlockAPIRestClient() + self.requester = HTTPRequester(baseUrl: config.url.httpBasedUrl, trustRoots: config.trustRoots) + super.init(config: config, targetQueue: targetQueue) + } + + func getBlocks( + request: FogLedger_BlockRequest, + completion: @escaping (Result) -> Void + ) { + performCall(GetBlocksCall(client: client, requester: requester), request: request, completion: completion) + } +} + +extension FogBlockHttpConnection { + private struct GetBlocksCall: HttpCallable { + let client: FogLedger_FogBlockAPIRestClient + let requester: HTTPRequester + + func call( + request: FogLedger_BlockRequest, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + let unaryCall = client.getBlocks(request, callOptions: callOptions) + unaryCall.callResult.whenSuccess(completion) + } + } +} diff --git a/Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift new file mode 100644 index 00000000..6f4e55f8 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift @@ -0,0 +1,18 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin + +final class FogKeyImageHttpConnection: ConnectionProtocol, FogKeyImageService { + func checkKeyImages( + request: FogLedger_CheckKeyImagesRequest, + completion: @escaping (Result) -> Void + ) { + } + + func setAuthorization(credentials: BasicCredentials) { + + } +} diff --git a/Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift new file mode 100644 index 00000000..4e924c55 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift @@ -0,0 +1,18 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin + +final class FogMerkleProofHttpConnection: ConnectionProtocol, FogMerkleProofService { + func getOutputs( + request: FogLedger_GetOutputsRequest, + completion: @escaping (Result) -> Void + ) { + } + + func setAuthorization(credentials: BasicCredentials) { + + } +} diff --git a/Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift new file mode 100644 index 00000000..67f1799b --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift @@ -0,0 +1,14 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin + +final class FogReportHttpConnection: FogReportService { + func getReports( + request: Report_ReportRequest, + completion: @escaping (Result) -> Void + ) { + } +} diff --git a/Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift new file mode 100644 index 00000000..5cbfa0a1 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift @@ -0,0 +1,18 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin + +final class FogUntrustedTxOutHttpConnection: ConnectionProtocol, FogUntrustedTxOutService { + func getTxOuts( + request: FogLedger_TxOutRequest, + completion: @escaping (Result) -> Void + ) { + } + + func setAuthorization(credentials: BasicCredentials) { + + } +} diff --git a/Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift new file mode 100644 index 00000000..da8dde29 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift @@ -0,0 +1,28 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin + +final class FogViewHttpConnection: AttestedHttpConnection, FogViewService { + + init( + config: AttestedConnectionConfig, + client: HttpClientWrapper, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + super.init(client: client, config: config, targetQueue: targetQueue) + } + + func query( + requestAad: FogView_QueryRequestAAD, + request: FogView_QueryRequest, + completion: @escaping (Result) -> Void + ) { + + } + +} diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift new file mode 100644 index 00000000..1f0c2c16 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift @@ -0,0 +1,65 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import SwiftProtobuf +import LibMobileCoin + +///// Usage: instantiate `ConsensusClient_ConsensusClientAPIRestClient`, then call methods of this protocol to make APIRest calls. +public protocol ConsensusClient_ConsensusClientAPIRestClientProtocol: HTTPClient { + var serviceName: String { get } + + func clientTxPropose( + _ request: Attest_Message, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall +} + +extension ConsensusClient_ConsensusClientAPIRestClientProtocol { + public var serviceName: String { + return "consensus_client.ConsensusClientAPIRest" + } + + //// This APIRest call is made with an encrypted payload for the enclave, + //// indicating a new value to be acted upon. + /// + /// - Parameters: + /// - request: Request to send to ClientTxPropose. + /// - callOptions: Call options. + /// - Returns: A `HTTPUnaryCall` with futures for the metadata, status and response. + public func clientTxPropose( + _ request: Attest_Message, + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { + return self.makeHTTPUnaryCall( + path: "/consensus_client.ConsensusClientAPIRest/ClientTxPropose", + request: request, + callOptions: callOptions ?? self.defaultHTTPCallOptions + ) + } +} + +public protocol ConsensusClient_ConsensusClientAPIRestClientInterceptorFactoryProtocol { + + /// - Returns: Interceptors to use when invoking 'clientTxPropose'. + func makeClientTxProposeInterceptors() -> [ClientInterceptor] +} + +public final class ConsensusClient_ConsensusClientAPIRestClient: ConsensusClient_ConsensusClientAPIRestClientProtocol { + public var defaultHTTPCallOptions: HTTPCallOptions + + /// Creates a client for the consensus_client.ConsensusClientAPIRest service. + /// + /// - Parameters: + /// - channel: `HTTPChannel` to the service host. + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. + /// - interceptors: A factory providing interceptors for each RPC. + public init( + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions(), + interceptors: ConsensusClient_ConsensusClientAPIRestClientInterceptorFactoryProtocol? = nil + ) { + self.defaultHTTPCallOptions = defaultHTTPCallOptions + } +} + diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift new file mode 100644 index 00000000..9f1b81c0 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift @@ -0,0 +1,84 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// +// swiftlint:disable all + +import Foundation +import NIO +import SwiftProtobuf +import LibMobileCoin + + +//// Blockchain APIRest shared between clients and peers. +/// +/// Usage: instantiate `ConsensusCommon_BlockchainAPIRestClient`, then call methods of this protocol to make APIRest calls. +public protocol ConsensusCommon_BlockchainAPIRestClientProtocol: HTTPClient { + var serviceName: String { get } + + func getLastBlockInfo( + _ request: SwiftProtobuf.Google_Protobuf_Empty, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall + + func getBlocks( + _ request: ConsensusCommon_BlocksRequest, + callOptions: HTTPCallOptions? + ) ->HTTPUnaryCall +} + +extension ConsensusCommon_BlockchainAPIRestClientProtocol { + public var serviceName: String { + return "consensus_common.BlockchainAPIRest" + } + + /// Unary call to GetLastBlockInfo + /// + /// - Parameters: + /// - request: Request to send to GetLastBlockInfo. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func getLastBlockInfo( + _ request: SwiftProtobuf.Google_Protobuf_Empty, + callOptions: HTTPCallOptions? = nil + ) ->HTTPUnaryCall { + return self.makeUnaryCall( + path: "/consensus_common.BlockchainAPIRest/GetLastBlockInfo", + request: request, + callOptions: callOptions ?? self.defaultHTTPCallOptions + ) + } + + /// Unary call to GetBlocks + /// + /// - Parameters: + /// - request: Request to send to GetBlocks. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func getBlocks( + _ request: ConsensusCommon_BlocksRequest, + callOptions: HTTPCallOptions? = nil + ) ->HTTPUnaryCall { + return self.makeUnaryCall( + path: "/consensus_common.BlockchainAPIRest/GetBlocks", + request: request, + callOptions: callOptions ?? self.defaultHTTPCallOptions + ) + } +} + +public final class ConsensusCommon_BlockchainAPIRestClient: ConsensusCommon_BlockchainAPIRestClientProtocol { + public var defaultHTTPCallOptions: HTTPCallOptions + + /// Creates a client for the consensus_common.BlockchainAPIRest service. + /// + /// - Parameters: + /// - channel: `GRPCChannel` to the service host. + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. + /// - interceptors: A factory providing interceptors for each RPC. + public init( + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() + ) { + self.defaultHTTPCallOptions = defaultHTTPCallOptions + } +} + diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift new file mode 100644 index 00000000..3f8a1ca4 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift @@ -0,0 +1,323 @@ +// +// DO NOT EDIT. +// +// Generated by the protocol buffer compiler. +// Source: ledger.proto +// + +// +// Copyright 2018, gRPC Authors All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +import GRPC +import NIO +import SwiftProtobuf +import LibMobileCoin + + +/// Usage: instantiate `FogLedger_FogMerkleProofAPI`, then call methods of this protocol to make API calls. +public protocol FogLedger_FogMerkleProofAPIRestProtocol: HTTPClient { + var serviceName: String { get } + + func auth( + _ request: Attest_AuthMessage, + callOptions: CallOptions? + ) -> UnaryCall + + func getOutputs( + _ request: Attest_Message, + callOptions: CallOptions? + ) -> UnaryCall +} + +extension FogLedger_FogMerkleProofAPIRestProtocol { + public var serviceName: String { + return "fog_ledger.FogMerkleProofAPI" + } + + //// This is called to perform mc-noise IX key exchange with the enclave, + //// before calling GetOutputs. + /// + /// - Parameters: + /// - request: Request to send to Auth. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func auth( + _ request: Attest_AuthMessage, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: "/fog_ledger.FogMerkleProofAPI/Auth", + request: request, + callOptions: callOptions ?? self.defaultCallOptions + } + + //// Get TxOut's and merkle proofs of membership for these outputs + //// These requests can be the user's "real" outputs from fog view, in order + //// to get the needed merkle proof, or their mixins for RingCT. + /// + /// - Parameters: + /// - request: Request to send to GetOutputs. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func getOutputs( + _ request: Attest_Message, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: "/fog_ledger.FogMerkleProofAPI/GetOutputs", + request: request, + callOptions: callOptions ?? self.defaultCallOptions + ) + } +} + +public protocol FogLedger_FogMerkleProofAPIInterceptorFactoryProtocol { + + /// - Returns: Interceptors to use when invoking 'auth'. + func makeAuthInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'getOutputs'. + func makeGetOutputsInterceptors() -> [ClientInterceptor] +} + +public final class FogLedger_FogMerkleProofAPI: FogLedger_FogMerkleProofAPIRestProtocol { + public let channel: GRPCChannel + public var defaultCallOptions: CallOptions + + /// Creates a client for the fog_ledger.FogMerkleProofAPI service. + /// + /// - Parameters: + /// - channel: `GRPCChannel` to the service host. + /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions() + ) { + self.channel = channel + self.defaultCallOptions = defaultCallOptions + } +} + +/// Usage: instantiate `FogLedger_FogKeyImageAPI`, then call methods of this protocol to make API calls. +public protocol FogLedger_FogKeyImageAPIRestProtocol: HTTPClient { + var serviceName: String { get } + + func auth( + _ request: Attest_AuthMessage, + callOptions: CallOptions? + ) -> UnaryCall + + func checkKeyImages( + _ request: Attest_Message, + callOptions: CallOptions? + ) -> UnaryCall +} + +extension FogLedger_FogKeyImageAPIRestProtocol { + public var serviceName: String { + return "fog_ledger.FogKeyImageAPI" + } + + //// This is called to perform IX key exchange with the enclave before calling GetOutputs. + /// + /// - Parameters: + /// - request: Request to send to Auth. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func auth( + _ request: Attest_AuthMessage, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: "/fog_ledger.FogKeyImageAPI/Auth", + request: request, + callOptions: callOptions ?? self.defaultCallOptions + ) + } + + //// Check if key images have appeared in the ledger, and if so, when + /// + /// - Parameters: + /// - request: Request to send to CheckKeyImages. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func checkKeyImages( + _ request: Attest_Message, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: "/fog_ledger.FogKeyImageAPI/CheckKeyImages", + request: request, + callOptions: callOptions ?? self.defaultCallOptions + ) + } +} + +public protocol FogLedger_FogKeyImageAPIInterceptorFactoryProtocol { + + /// - Returns: Interceptors to use when invoking 'auth'. + func makeAuthInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'checkKeyImages'. + func makeCheckKeyImagesInterceptors() -> [ClientInterceptor] +} + +public final class FogLedger_FogKeyImageAPI: FogLedger_FogKeyImageAPIRestProtocol { + public let channel: GRPCChannel + public var defaultCallOptions: CallOptions + + /// Creates a client for the fog_ledger.FogKeyImageAPI service. + /// + /// - Parameters: + /// - channel: `GRPCChannel` to the service host. + /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions() + ) { + self.channel = channel + self.defaultCallOptions = defaultCallOptions + } +} + +/// Usage: instantiate `FogLedger_FogBlockAPI`, then call methods of this protocol to make API calls. +public protocol FogLedger_FogBlockAPIRestProtocol: HTTPClient { + var serviceName: String { get } + + func getBlocks( + _ request: FogLedger_BlockRequest, + callOptions: CallOptions? + ) -> UnaryCall +} + +extension FogLedger_FogBlockAPIRestProtocol { + public var serviceName: String { + return "fog_ledger.FogBlockAPI" + } + + //// Request for all of the TxOuts for a particular range of blocks. + //// This is meant to help the users recover from "missed blocks" i.e. + //// data loss in the fog service. + /// + /// - Parameters: + /// - request: Request to send to GetBlocks. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func getBlocks( + _ request: FogLedger_BlockRequest, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: "/fog_ledger.FogBlockAPI/GetBlocks", + request: request, + callOptions: callOptions ?? self.defaultCallOptions + ) + } +} + +public protocol FogLedger_FogBlockAPIInterceptorFactoryProtocol { + + /// - Returns: Interceptors to use when invoking 'getBlocks'. + func makeGetBlocksInterceptors() -> [ClientInterceptor] +} + +public final class FogLedger_FogBlockAPI: FogLedger_FogBlockAPIRestProtocol { + public let channel: GRPCChannel + public var defaultCallOptions: CallOptions + + /// Creates a client for the fog_ledger.FogBlockAPI service. + /// + /// - Parameters: + /// - channel: `GRPCChannel` to the service host. + /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions() + ) { + self.channel = channel + self.defaultCallOptions = defaultCallOptions + } +} + +/// Usage: instantiate `FogLedger_FogUntrustedTxOutApiClient`, then call methods of this protocol to make API calls. +public protocol FogLedger_FogUntrustedTxOutApiClientProtocol: HTTPClient { + var serviceName: String { get } + + func getTxOuts( + _ request: FogLedger_TxOutRequest, + callOptions: CallOptions? + ) -> UnaryCall +} + +extension FogLedger_FogUntrustedTxOutApiClientProtocol { + public var serviceName: String { + return "fog_ledger.FogUntrustedTxOutApi" + } + + //// This can be used by a sender who may be sharing their private keys across + //// multiple parties / devices, to confirm that a transaction that they sent + //// landed in the blockchain, by confirming that one of the random keys from + //// a TxOut that they produced appears in the ledger. + //// + //// Given the TxOut.pubkey value, we return if it is found, and the num_blocks + //// value, allowing Alice to determine that her transactions succeeded, or if + //// num_blocks exceeded her tombstone value, conclude that it failed somehow. + //// We also return the global tx out index. We don't currently return the block + //// index or time stamp in which the TxOut appeared. + //// + //// This API is NOT attested and Bob, the recipient, SHOULD NOT use it in connection + //// to the same TxOut, as that will leak the transaction graph to fog operator, + //// which breaks the privacy statement for fog as a whole. + /// + /// - Parameters: + /// - request: Request to send to GetTxOuts. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func getTxOuts( + _ request: FogLedger_TxOutRequest, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: "/fog_ledger.FogUntrustedTxOutApi/GetTxOuts", + request: request, + callOptions: callOptions ?? self.defaultCallOptions + ) + } +} + +public protocol FogLedger_FogUntrustedTxOutApiClientInterceptorFactoryProtocol { + + /// - Returns: Interceptors to use when invoking 'getTxOuts'. + func makeGetTxOutsInterceptors() -> [ClientInterceptor] +} + +public final class FogLedger_FogUntrustedTxOutApiClient: FogLedger_FogUntrustedTxOutApiClientProtocol { + public let channel: GRPCChannel + public var defaultCallOptions: CallOptions + + /// Creates a client for the fog_ledger.FogUntrustedTxOutApi service. + /// + /// - Parameters: + /// - channel: `GRPCChannel` to the service host. + /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions() + ) { + self.channel = channel + self.defaultCallOptions = defaultCallOptions + } +} + diff --git a/Sources/Network/HttpConnection/HttpRequester.swift b/Sources/Network/HttpConnection/HttpRequester.swift new file mode 100644 index 00000000..5555c587 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpRequester.swift @@ -0,0 +1,240 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +// swiftlint:disable all + +import Foundation +import SwiftProtobuf +import NIOSSL + +public protocol HttpRequester { + func request( + url: URL, + method: HTTPMethod, + headers: [String: String]?, + body: Data?, + completion: @escaping (HTTPResult) -> Void) +} + +public enum HTTPMethod : String { + case GET = "GET" + case POST = "POST" + case PUT = "PUT" + case HEAD = "HEAD" + case PATCH = "PATCH" + case DELETE = "DELETE" +} + +public struct HTTPResponse { + public let httpUrlResponse: HTTPURLResponse + public let responseData: Data? + + public var statusCode: Int { + httpUrlResponse.statusCode + } + + public var allHeaderFields: [AnyHashable: Any] { + httpUrlResponse.allHeaderFields + } +} + +public enum HTTPResult { + case success(response: HTTPResponse) + case failure(error: Error) +} + +// - Add relative path component toe NetworkedMessage and then combine at runtime. + +public class HTTPRequester { + public static let defaultConfiguration : URLSessionConfiguration = { + let config = URLSessionConfiguration.default + config.timeoutIntervalForRequest = 30 + config.timeoutIntervalForResource = 30 + return config + }() + + let configuration : URLSessionConfiguration + let baseUrl: URL + let trustRoots: [NIOSSLCertificate]? + let prefix: String = "gw" + + public init(baseUrl: URL, trustRoots: [NIOSSLCertificate]?, configuration: URLSessionConfiguration = HTTPRequester.defaultConfiguration) { + self.configuration = configuration + self.baseUrl = baseUrl + self.trustRoots = trustRoots + } +} + +public protocol Requester { +// func makeRequest(call: T, completion: @escaping (Result) -> Void) + func makeRequest(call: T, completion: @escaping (Result, Error>) -> Void) +} + +extension HTTPRequester : Requester { + private func completeURLFromPath(_ path: String) -> URL? { + URL(string: path, relativeTo: URL(string: prefix, relativeTo: baseUrl)) + } + +// public func makeRequest(call: T, completion: @escaping (Result, Error>) -> Void) { + public func makeRequest(call: T, completion: @escaping (Result, Error>) -> Void) { + let session = URLSession(configuration: configuration) + + guard let url = completeURLFromPath(call.path) else { + completion(.failure(InvalidInputError("Invalid URL"))) + return + } + + var request = URLRequest(url: url) + request.httpMethod = call.method.rawValue + request.addProtoHeaders() + + do { + request.httpBody = try call.requestPayload?.serializedData() ?? Google_Protobuf_Empty().serializedData() + logger.debug("MC HTTP Request: \(call.requestPayload?.prettyPrintJSON() ?? "")") + } catch let error { + logger.debug(error.localizedDescription) + } + + session.dataTask(with: request) { data, response, error in + if let error = error { + completion(.failure(error)) + return + } + + guard let response = response as? HTTPURLResponse else { + completion(.failure(NetworkingError.noResponse)) + return + } + + guard (200...299).contains(response.statusCode) else { + completion(.failure(HTTPResponseStatusCodeError(response.statusCode))) + return + } + + guard let data = data else { + completion(.failure(NetworkingError.noData)) + return + } + + do { + let responsePayload = try T.ResponsePayload.init(serializedData: data) + logger.debug("Resposne Proto as JSON: \((try? responsePayload.jsonString()) ?? "Unable to print JSON")") + + // let result = HttpCallResult(status: HTTPStatus(code: response.statusCode, message: ""), initialMetadata: response, response: responsePayload) + let result = HttpCallResult(status: HTTPStatus(code: response.statusCode, message: ""), initialMetadata: response, response: responsePayload) + completion(.success(result)) + } catch { + completion(.failure(error)) + } + }.resume() + } + +} + +fileprivate extension URLRequest { + mutating func addProtoHeaders() { + let contentType = HTTPHeadersConstants.CONTENT_TYPE_PROTOBUF + self.setValue(contentType.value, forHTTPHeaderField: contentType.fieldName) + + let accept = HTTPHeadersConstants.ACCEPT_PROTOBUF + self.addValue(accept.value, forHTTPHeaderField: accept.fieldName) + } +} + +struct HTTPHeadersConstants { + static var ACCEPT_PROTOBUF = (fieldName:"Accept", value:"application/x-protobuf") + static var CONTENT_TYPE_PROTOBUF = (fieldName:"Content-Type", value:"application/x-protobuf") +} + +extension Message { + func prettyPrintJSON() -> String { + guard let jsonData = try? self.jsonUTF8Data(), + let data = try? JSONSerialization.jsonObject(with: jsonData, options: []), + let object = try? JSONSerialization.data(withJSONObject: data, options: [.prettyPrinted]), + let prettyPrintedString = String(data: object, encoding: String.Encoding.utf8) else { + return "Unable to pretty print json" + } + return prettyPrintedString + } +} + +public enum HTTPResponseStatusCodeError : Error { + case unauthorized + case badRequest + case forbidden + case unprocessableEntity + case internalServerError + case invalidResponseFromExternal + case unknown(Int) + + // TODO add other HTTP errors here + init(_ code: Int) { + switch code { + case 400: self = .badRequest + case 401: self = .unauthorized + case 403: self = .forbidden + case 422: self = .unprocessableEntity + case 500: self = .internalServerError + case 502: self = .invalidResponseFromExternal + default: self = .unknown(code) + } + } + + var value : Int? { + switch self { + case .badRequest: return 400 + case .unauthorized: return 401 + case .forbidden: return 403 + case .unprocessableEntity: return 422 + case .internalServerError: return 500 + case .invalidResponseFromExternal: return 502 + default: return nil + } + } +} + +extension HTTPResponseStatusCodeError : CustomStringConvertible { + public var description: String { + switch self { + case .badRequest: return "The request is malformed (ex. missing or incorrect parameters)" + case .unauthorized: return "Failed to provide proper authentication with the request." + case .forbidden: return "The action in the request is not allowed." + case .unprocessableEntity: return "The server understands the content type of the request entity, and the syntax of the request entity is correct, but it was unable to process the contained instructions." + case .internalServerError: return "Unhandled exception from one of the other services: the Database, FTX, or the Full Service Wallet." + case .invalidResponseFromExternal: return "The server was acting as a gateway or proxy and received an invalid response from the upstream server (ie. one of the other services: the Database, FTX, or the Full Service Wallet.)" + case .unknown(let code): return "HTTP Response code \(code)" + } + } +} + +extension HTTPResponseStatusCodeError : Equatable { + public static func == (lhs: HTTPResponseStatusCodeError, rhs: HTTPResponseStatusCodeError) -> Bool { + switch (lhs, rhs) { + case (.unknown(let lhsValue), .unknown(let rhsValue)): + return lhsValue == rhsValue + default: + return lhs.value ?? -1 == rhs.value ?? -1 + } + } +} + +public enum NetworkingError: Error { + case unknownDecodingError + case noResponseStatus + case noResponse + case unknown + case noData +} + +extension NetworkingError: CustomStringConvertible { + public var description : String { + switch self { + case .noResponseStatus: return "Response status not explicitly set in proto response" + case .noResponse: return "URLResponse object is nil" + case .unknownDecodingError: return "Unknown decoding error" + case .unknown: return "Unknown netowrking error" + case .noData: return "No data in resposne" + } + } +} diff --git a/Sources/Network/NetworkConfig.swift b/Sources/Network/NetworkConfig.swift index 42a2a12a..7bdd74ed 100644 --- a/Sources/Network/NetworkConfig.swift +++ b/Sources/Network/NetworkConfig.swift @@ -21,12 +21,16 @@ struct NetworkConfig { private let attestation: AttestationConfig + var transportProtocol: TransportProtocol = .grpc + var consensusTrustRoots: [NIOSSLCertificate]? var fogTrustRoots: [NIOSSLCertificate]? var consensusAuthorization: BasicCredentials? var fogUserAuthorization: BasicCredentials? + var httpRequester: HttpRequester? + init(consensusUrl: ConsensusUrl, fogUrl: FogUrl, attestation: AttestationConfig) { self.consensusUrl = consensusUrl self.fogUrl = fogUrl @@ -36,6 +40,7 @@ struct NetworkConfig { var consensus: AttestedConnectionConfig { AttestedConnectionConfig( url: consensusUrl, + transportProtocolOption: transportProtocol.option, attestation: attestation.consensus, trustRoots: consensusTrustRoots, authorization: consensusAuthorization) @@ -44,6 +49,7 @@ struct NetworkConfig { var blockchain: ConnectionConfig { ConnectionConfig( url: consensusUrl, + transportProtocolOption: transportProtocol.option, trustRoots: consensusTrustRoots, authorization: consensusAuthorization) } @@ -51,6 +57,7 @@ struct NetworkConfig { var fogView: AttestedConnectionConfig { AttestedConnectionConfig( url: fogUrl, + transportProtocolOption: transportProtocol.option, attestation: attestation.fogView, trustRoots: fogTrustRoots, authorization: fogUserAuthorization) @@ -59,6 +66,7 @@ struct NetworkConfig { var fogMerkleProof: AttestedConnectionConfig { AttestedConnectionConfig( url: fogUrl, + transportProtocolOption: transportProtocol.option, attestation: attestation.fogMerkleProof, trustRoots: fogTrustRoots, authorization: fogUserAuthorization) @@ -67,6 +75,7 @@ struct NetworkConfig { var fogKeyImage: AttestedConnectionConfig { AttestedConnectionConfig( url: fogUrl, + transportProtocolOption: transportProtocol.option, attestation: attestation.fogKeyImage, trustRoots: fogTrustRoots, authorization: fogUserAuthorization) @@ -75,6 +84,7 @@ struct NetworkConfig { var fogBlock: ConnectionConfig { ConnectionConfig( url: fogUrl, + transportProtocolOption: transportProtocol.option, trustRoots: fogTrustRoots, authorization: fogUserAuthorization) } @@ -82,6 +92,7 @@ struct NetworkConfig { var fogUntrustedTxOut: ConnectionConfig { ConnectionConfig( url: fogUrl, + transportProtocolOption: transportProtocol.option, trustRoots: fogTrustRoots, authorization: fogUserAuthorization) } diff --git a/Sources/Network/Service/DefaultServiceProvider.swift b/Sources/Network/Service/DefaultServiceProvider.swift index 0b4bdeb0..0b3295a7 100644 --- a/Sources/Network/Service/DefaultServiceProvider.swift +++ b/Sources/Network/Service/DefaultServiceProvider.swift @@ -5,8 +5,7 @@ import Foundation final class DefaultServiceProvider: ServiceProvider { - private let targetQueue: DispatchQueue? - private let channelManager = GrpcChannelManager() + private let inner: SerialDispatchLock private let consensus: ConsensusConnection private let blockchain: BlockchainConnection @@ -16,10 +15,12 @@ final class DefaultServiceProvider: ServiceProvider { private let block: FogBlockConnection private let untrustedTxOut: FogUntrustedTxOutConnection - private var reportUrlToReportConnection: [GrpcChannelConfig: FogReportConnection] = [:] - init(networkConfig: NetworkConfig, targetQueue: DispatchQueue?) { - self.targetQueue = targetQueue + let channelManager = GrpcChannelManager() + + let inner = Inner(channelManager: channelManager, targetQueue: targetQueue) + self.inner = .init(inner, targetQueue: targetQueue) + self.consensus = ConsensusConnection( config: networkConfig.consensus, channelManager: channelManager, @@ -31,6 +32,7 @@ final class DefaultServiceProvider: ServiceProvider { self.view = FogViewConnection( config: networkConfig.fogView, channelManager: channelManager, + httpRequester: networkConfig.httpRequester, targetQueue: targetQueue) self.merkleProof = FogMerkleProofConnection( config: networkConfig.fogMerkleProof, @@ -56,19 +58,26 @@ final class DefaultServiceProvider: ServiceProvider { var fogMerkleProofService: FogMerkleProofService { merkleProof } var fogKeyImageService: FogKeyImageService { keyImage } var fogBlockService: FogBlockService { block } - var fogUntrustedTxOutService: FogUntrustedTxOutConnection { untrustedTxOut } - - func fogReportService(for fogReportUrl: FogUrl) -> FogReportService { - let config = GrpcChannelConfig(url: fogReportUrl) - guard let reportConnection = reportUrlToReportConnection[config] else { - let reportConnection = FogReportConnection( - url: fogReportUrl, - channelManager: channelManager, - targetQueue: targetQueue) - reportUrlToReportConnection[config] = reportConnection - return reportConnection + var fogUntrustedTxOutService: FogUntrustedTxOutService { untrustedTxOut } + + func fogReportService( + for fogReportUrl: FogUrl, + completion: @escaping (FogReportService) -> Void + ) { + inner.accessAsync { completion($0.fogReportService(for: fogReportUrl)) } + } + + func setTransportProtocolOption(_ transportProtocolOption: TransportProtocol.Option) { + inner.accessAsync { + $0.setTransportProtocolOption(transportProtocolOption) + self.consensus.setTransportProtocolOption(transportProtocolOption) + self.blockchain.setTransportProtocolOption(transportProtocolOption) + self.view.setTransportProtocolOption(transportProtocolOption) + self.merkleProof.setTransportProtocolOption(transportProtocolOption) + self.keyImage.setTransportProtocolOption(transportProtocolOption) + self.block.setTransportProtocolOption(transportProtocolOption) + self.untrustedTxOut.setTransportProtocolOption(transportProtocolOption) } - return reportConnection } func setConsensusAuthorization(credentials: BasicCredentials) { @@ -84,3 +93,42 @@ final class DefaultServiceProvider: ServiceProvider { untrustedTxOut.setAuthorization(credentials: credentials) } } + +extension DefaultServiceProvider { + private struct Inner { + private let targetQueue: DispatchQueue? + private let channelManager: GrpcChannelManager + + private var reportUrlToReportConnection: [GrpcChannelConfig: FogReportConnection] = [:] + private(set) var transportProtocolOption: TransportProtocol.Option + + init(channelManager: GrpcChannelManager, targetQueue: DispatchQueue?) { + self.targetQueue = targetQueue + self.channelManager = channelManager + self.transportProtocolOption = TransportProtocol.grpc.option + } + + mutating func fogReportService(for fogReportUrl: FogUrl) -> FogReportService { + let config = GrpcChannelConfig(url: fogReportUrl) + guard let reportConnection = reportUrlToReportConnection[config] else { + let reportConnection = FogReportConnection( + url: fogReportUrl, + transportProtocolOption: transportProtocolOption, + channelManager: channelManager, + targetQueue: targetQueue) + reportUrlToReportConnection[config] = reportConnection + return reportConnection + } + return reportConnection + } + + mutating func setTransportProtocolOption( + _ transportProtocolOption: TransportProtocol.Option + ) { + self.transportProtocolOption = transportProtocolOption + for reportConnection in reportUrlToReportConnection.values { + reportConnection.setTransportProtocolOption(transportProtocolOption) + } + } + } +} diff --git a/Sources/Network/Service/ServiceProvider.swift b/Sources/Network/Service/ServiceProvider.swift index 67cc50ed..f9b1f049 100644 --- a/Sources/Network/Service/ServiceProvider.swift +++ b/Sources/Network/Service/ServiceProvider.swift @@ -12,9 +12,13 @@ protocol ServiceProvider { var fogMerkleProofService: FogMerkleProofService { get } var fogKeyImageService: FogKeyImageService { get } var fogBlockService: FogBlockService { get } - var fogUntrustedTxOutService: FogUntrustedTxOutConnection { get } + var fogUntrustedTxOutService: FogUntrustedTxOutService { get } - func fogReportService(for fogReportUrl: FogUrl) -> FogReportService + func fogReportService( + for fogReportUrl: FogUrl, + completion: @escaping (FogReportService) -> Void) + + func setTransportProtocolOption(_ transportProtocolOption: TransportProtocol.Option) func setConsensusAuthorization(credentials: BasicCredentials) func setFogUserAuthorization(credentials: BasicCredentials) diff --git a/Sources/Network/TransportProtocol.swift b/Sources/Network/TransportProtocol.swift new file mode 100644 index 00000000..2f2f339d --- /dev/null +++ b/Sources/Network/TransportProtocol.swift @@ -0,0 +1,19 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + +public struct TransportProtocol { + public static let grpc = TransportProtocol(option: .grpc) + public static let http = TransportProtocol(option: .http) + + let option: Option +} + +extension TransportProtocol { + enum Option { + case grpc + case http + } +} diff --git a/Sources/Utils/HTTP/HttpCallResult.swift b/Sources/Utils/HTTP/HttpCallResult.swift new file mode 100644 index 00000000..5a0b84ba --- /dev/null +++ b/Sources/Utils/HTTP/HttpCallResult.swift @@ -0,0 +1,185 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC +import NIO +import NIOHPACK + + +public struct HttpCallResult { + let status: HTTPStatus + let initialMetadata: HTTPURLResponse? + let response: ResponsePayload? +} + +extension HttpCallResult { + init( + status: GRPCStatus, + initialMetadata: HTTPURLResponse?, + response: ResponsePayload? + ) { + // TODO REMOVE + self.init(status: HTTPStatus(grpcStatus: status), initialMetadata: initialMetadata, response: response) + } +} + +protocol HttpClientCall { + /// The type of the request message for the call. + associatedtype RequestPayload + + /// The type of the response message for the call. + associatedtype ResponsePayload + + /// The event loop this call is running on. + var eventLoop: NIOCore.EventLoop { get } + + /// The options used to make the RPC. + var options: GRPC.CallOptions { get } + + /// HTTP/2 stream that requests and responses are sent and received on. + var subchannel: NIOCore.EventLoopFuture { get } + + /// Initial response metadata. + var initialMetadata: NIOCore.EventLoopFuture { get } + + /// Status of this call which may be populated by the server or client. + /// + /// The client may populate the status if, for example, it was not possible to connect to the service. + /// + /// Note: despite `GRPCStatus` conforming to `Error`, the value will be __always__ delivered as a __success__ + /// result even if the status represents a __negative__ outcome. This future will __never__ be fulfilled + /// with an error. + var status: NIOCore.EventLoopFuture { get } + + /// Trailing response metadata. + var trailingMetadata: NIOCore.EventLoopFuture { get } + + /// Cancel the current call. + /// + /// Closes the HTTP/2 stream once it becomes available. Additional writes to the channel will be ignored. + /// Any unfulfilled promises will be failed with a cancelled status (excepting `status` which will be + /// succeeded, if not already succeeded). + func cancel(promise: NIOCore.EventLoopPromise?) + + var response: NIOCore.EventLoopFuture { get } +} + +//struct HttpResponseClientCall : HttpClientCall { +// var response: EventLoopFuture +// +// var eventLoop: EventLoop +// +// var options: CallOptions +// +// var subchannel: EventLoopFuture +// +// var initialMetadata: EventLoopFuture +// +// var status: EventLoopFuture +// +// var trailingMetadata: EventLoopFuture +// +// func cancel(promise: EventLoopPromise?) { +// +// } +// +// typealias RequestPayload = Int +// +// typealias ResponsePayload = Int +// +// var callResult: EventLoopFuture> { +// var resolvedInitialMetadata: HPACKHeaders? +// initialMetadata.whenSuccess { resolvedInitialMetadata = $0 } +// var resolvedResponse: ResponsePayload? +// response.whenSuccess { resolvedResponse = $0 } +// var resolvedTrailingMetadata: HPACKHeaders? +// trailingMetadata.whenSuccess { resolvedTrailingMetadata = $0 } +// +// return status.flatMap { status in +// self.eventLoop.makeSucceededFuture( +// HttpCallResult( +// status: status, +// initialMetadata: resolvedInitialMetadata, +// response: resolvedResponse, +// trailingMetadata: resolvedTrailingMetadata)) +// } +// } +//} + + + +/// Encapsulates the result of a gRPC call. +public struct HTTPStatus : Error { + + /// The status code of the RPC. + public var code: Int + + /// The status message of the RPC. + public var message: String? + + /// Whether the status is '.ok'. + public var isOk: Bool { + (200...299).contains(code) + } + + /// The default status to return for succeeded calls. + /// + /// - Important: This should *not* be used when checking whether a returned status has an 'ok' + /// status code. Use `HTTPStatus.isOk` or check the code directly. + public static let ok: HTTPStatus = .init(code: 200, message: "Success") + + /// "Internal server error" status. + public static let processingError: HTTPStatus = .init(code: 500, message: "Error") +} + +extension HTTPStatus { + init(grpcStatus: GRPCStatus) { + self.init(code: grpcStatus.isOk ? 200 : 500, message: grpcStatus.message) + } + + func temp(code: GRPCStatus.Code) -> Int{ + switch code { + case .ok: + return 200 + case .cancelled: + return 500 + case .unknown: + return 500 + case .invalidArgument: + return 400 + case .deadlineExceeded: + return 504 + case .notFound: + return 404 + case .alreadyExists: + return 409 + case .permissionDenied: + return 403 + case .resourceExhausted: + return 400 + case .failedPrecondition: + return 412 + case .aborted: + return 500 + case .outOfRange: + return 400 + case .unimplemented: + return 501 + case .internalError: + return 500 + case .unavailable: + return 503 + case .dataLoss: + return 500 + case .unauthenticated: + return 403 + default: + return 500 + } + } +} + + + diff --git a/TERMS-OF-USE.md b/TERMS-OF-USE.md index 1ed75ba9..2b88aea2 100644 --- a/TERMS-OF-USE.md +++ b/TERMS-OF-USE.md @@ -1,132 +1,190 @@ -# **TERMS OF USE** **FOR MOBILECOINS AND MOBILECOIN WALLETS** +**MobileCoins are not offered or sold to U.S. Persons or entities or other Prohibited Persons regardless of their location. Purchasers of MobileCoins may not transact, transfers, or trade MobileCoins in the United States or with U.S. Persons or entities, or persons or entities present in the United States.** -The MobileCoin Network uses an open source software protocol commonly known as the MobileCoin protocol. The MobileCoin protocol is designed to enable holders of digital tokens known as MobileCoins to send and receive peer-to-peer payments securely and privately through a digital wallet that can send and receive MobileCoins (MobileCoin Wallets). MobileCoins and MobileCoin Wallets enable a simple, secure, and private medium of exchange for consumers in countries of operation to manage and move their money using a currency of equivalent value across countries. +# TERMS OF USE FOR MOBILECOINS AND MOBILECOIN WALLETS -These Terms of Use for MobileCoins and MobileCoin Wallets (Terms) govern: +The MobileCoin Network operates utilizing an open source software protocol commonly known as the MobileCoin protocol. The MobileCoin protocol is designed to enable holders of digital tokens known as MobileCoins to send and receive peer-to-peer payments securely and privately through a digital wallet that is capable of sending and receiving MobileCoins (MobileCoin Wallets). MobileCoins enable a simple, secure, and private medium of exchange for consumers in countries of operation to manage and move their money using personal mobile devices and a currency of equivalent value across countries. +These Terms of Use for MobileCoins and MobileCoin Wallets (Terms) govern: - MobileCoins and their use and transfer; and - MobileCoin Wallets and their access and use. -Please read these Terms carefully before you start to use any MobileCoins and any MobileCoin Wallet. By acquiring or otherwise obtaining MobileCoins, using or transferring MobileCoins or obtaining, accessing or using a MobileCoin Wallet, you acknowledge that you have read, understand, and completely agree to be bound by these Terms. You also agree to require any transferee of your MobileCoins and any holder of a MobileCoin Wallet facilitated by you to be subject to these Terms. These Terms may be enforced against you by MobileCoin TS Ltd., MobileCoin U.S., LLC or other authorized entities (which are collectively referred to in these Terms as the Compliance Entities). These Terms may be amended, changed, or updated by the Compliance Entities at any time and without prior notice to you by posting at [www.buymobilecoin.us](https://www.buymobilecoin.us/). Your continued use of any MobileCoins and any MobileCoin Wallets following the posting of any amendment, change, or update means that you accept and agree to the amended, changed, or updated Terms. These Terms are first effective as of August 17, 2021 and supersede any previous versions. +Please read these Terms carefully before you start to use any MobileCoins and any MobileCoin Wallet. By acquiring or otherwise obtaining MobileCoins, using or transferring MobileCoins or obtaining, accessing or using a MobileCoin Wallet, you acknowledge that you have read, understand, and completely agree to be bound by these Terms. You also agree to require any transferee of your MobileCoins and any holder of a MobileCoin Wallet facilitated by you to be subject to these Terms. These Terms may be enforced against you by MobileCoin TS Ltd. or other authorized entities (which are collectively referred to in these Terms as the Compliance Entities). These Terms may be amended, changed, or updated by the Compliance Entities at any time and without prior notice to you by posting at the MobileCoin TS Ltd. Website at http://www.buymobilecoin.com/. Your continued use of any MobileCoins and any MobileCoin Wallets following the posting of any amendment, change, or update means that you accept and agree to the amended, changed, or updated Terms. These Terms are first effective as of November 23, 2020. -Access or use of any MobileCoin Wallets or use or transfer of any MobileCoins is void where such access, use or transfer is prohibited by, would constitute a violation of, or would be subject to penalties under applicable laws. Such access or use of MobileCoin Wallets or use or transfer of any MobileCoins which is void will not be the basis for the assertion or recognition of any interest, right, remedy, power, or privilege. \[Please also consult the applicable Terms of Sale and Access and Use of the Site, available at the MobileCoin U.S. LLC website at [www.buymobilecoin.us](https://www.buymobilecoin.us/) or the MobileCoin TS Ltd. website at [www.buymobilecoin.com](https://www.buymobilecoin.com). Information on the way personal information is handled is included in the appropriate Privacy Policy, available at [www.buymobilecoin.us](https://www.buymobilecoin.us/) or [www.buymobilecoin.com](https://www.buymobilecoin.com/).\] +Access or use of any MobileCoin Wallets or use or transfer of any MobileCoins is void where such access, use or transfer is prohibited by, would constitute a violation of, or would be subject to penalties under applicable laws, and will not be the basis for the assertion or recognition of any interest, right, remedy, power, or privilege. Please also consult the Terms of Sale and Access and Use of the Site, available at the MobileCoin TS Ltd. website at http://www.buymobilecoin.com/. Information on the way personal information is handled is included in the Privacy Policy, available at http://www.buymobilecoin.com/. -## **Limitations on Access or Use of MobileCoin Wallets and Use and Transfer of MobileCoins** +## Limitations on Access or Use of MobileCoin Wallets and Use and Transfer of MobileCoins -The right to access or use MobileCoin Wallets and use or transfer MobileCoins is a personal, restricted, non-exclusive, non-sublicensable, revocable, limited license, and it is subject to the limitations and obligations in these Terms. Every Prohibited Person is strictly prohibited from directly or indirectly transacting, transferring, holding, owning, accessing or using any MobileCoins and any MobileCoin Wallets in any way. - -You are a Prohibited Person if you are: +The right to access or use MobileCoin Wallets and use or transfer MobileCoins is a personal, restricted, non-exclusive, non-transferable, non-sublicensable, revocable, limited license, and it is subject to the limitations and obligations in these Terms. Every **Prohibited Person** and **U.S. Person** is strictly prohibited from directly or indirectly transacting, transferring, holding, owning, accessing or using any MobileCoins and any MobileCoin Wallets in any way. +You are a **Prohibited Person** if you are: 1. an individual or entity present in or subject to the jurisdiction of any jurisdiction in which the distribution or offer of or transaction in MobileCoins is unlawful or who is restricted or prohibited by applicable law, including without limitation, anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, and economic sanctions laws, from purchasing or otherwise obtaining MobileCoins or transacting in MobileCoins; -2. an individual or entity present in or subject to the jurisdiction of Cuba, Democratic People's Republic of Korea (North Korea), Iran, Syria or Crimea (a region of Ukraine annexed by the Russian Federation) (a Prohibited Jurisdiction); -3. a government or government official of any Prohibited Jurisdiction or of Venezuela or any subdivision thereof; -4. an individual or entity subject to asset freezing or blocking sanctions imposed by the United Nations, British Virgin Islands, United Kingdom, European Union, or United States or any entity owned 50 percent or more by one or more such persons (a Sanctioned Person); + +2. an individual or entity present in or subject to the jurisdiction of Cuba, Democratic People’s Republic of Korea (North Korea), Iran, Syria or Crimea (a region of Ukraine annexed by the Russian Federation) (a Prohibited Jurisdiction); + +3. a government or government official of any Prohibited Jurisdiction or of Venezuela or any subdivision thereof; + +4. an individual or entity subject to asset freezing or blocking sanctions imposed by the United Nations, British Virgin Islands, United Kingdom, European Union, or United States or any entity owned 50 percent or more by one or more such persons (a Sanctioned Person); + 5. a person under 18 years of age; or + 6. any other individual or entity whose dealings in MobileCoins or use of a MobileCoin Wallet could expose the Compliance Entities to civil or criminal liability or cause the Compliance Entities to engage in sanctionable conduct. -## **MobileCoin Wallets** +You are a **“U.S. Person”** if you are: +1. (i) a U.S. citizen, (ii) a U.S. lawful permanent resident, protected individual or asylee under the U.S. Immigration and Nationality Act, (iii) an individual present in the U.S. in a non-immigrant status which carries an allowable admission period exceeding 6 months, (iv) an individual or entity present in the U.S., or (v) an individual or entity acting for the financial or other benefit of or on behalf of any U.S. Person; + +2. a corporation, partnership, or other entity established or organized in or under the laws of the United States; + +3. a corporation, partnership, or other entity formed by a U.S. Person principally for the purpose of investing in securities, unless it is organized or incorporated, and owned, by accredited investors who are not natural persons, estates or trusts; + +4. an estate of which any executor or administrator is a U.S. Person (unless this executor or administrator is a professional fiduciary and shares with a non-U.S. Person investment discretion with respect to the assets of an estate that is governed by foreign law); + +5. a trust if the trustee is a U.S. Person (unless this trustee is a professional fiduciary and shares with a non-U.S. Person investment discretion with respect to the trust assets and no beneficiary of the trust (and no settlor if the trust is revocable) is a U.S. Person); + +6. an agency or branch of a non-U.S. entity located in the U.S.; -No MobileCoin Wallet may be operated for and no order or transaction in a MobileCoin Wallet may be used for the financial or other benefit of or on behalf of a Prohibited Person. Persons, whether or not Prohibited Persons, are prohibited from operating a MobileCoin Wallet in any way or otherwise transacting on or using any MobileCoins and any MobileCoin Wallets while they or any individual (including any fiduciary, dealer, trustee, executor or administrator), agency or branch operating their MobileCoin Wallet on their behalf is present in any jurisdiction in which MobileCoins are unlawful. +7. a non-discretionary account or similar account held by a dealer or other fiduciary for the benefit or account of a U.S. Person; -Certain software comprising MobileCoin Wallets is available to the public without charge on an open source basis. This software is provided "as is" without warranty of any kind. However, MobileCoin Wallets linked to a mobile messaging application may integrate software from a third party. MobileCoin Wallets must be accessed through a telephone, computer or other equipment as well as a network connection through telecommunication lines or other utility. None of these components of the MobileCoin Wallet is provided or controlled by the Compliance Entities. The Compliance Entities are not responsible for the accuracy or reliability of any open-source software or of any software, hardware, information, or advice provided by third parties or for their privacy and security policies and procedures. +8. any discretionary account or similar account held by a dealer or other fiduciary organized, incorporated, or resident in the U.S. (held for the exclusive benefit or account of non-U.S. Persons); or + +9. any government or government official of the United States. + +In these Terms, United States or U.S. means the several states of the United States of America, the District of Columbia, Puerto Rico, the Virgin Islands, and the insular possessions of the United States of America. + +## MobileCoin Wallets + +No MobileCoin Wallet may be operated for and no order or transaction in a MobileCoin Wallet may be for the financial or other benefit of or on behalf of a Prohibited Person or U.S. Person. Persons, whether or not Prohibited Persons, are prohibited from operating a MobileCoin Wallet in any way or otherwise transacting on or using any MobileCoins and any MobileCoin Wallets while they or any individual (including any fiduciary, dealer, trustee, executor or administrator), agency or branch operating their MobileCoin Wallet on their behalf is present in the United States or any jurisdiction in which MobileCoins are unlawful. + +Certain software comprising MobileCoin Wallets is available to the public without charge on an open source basis. This software is provided “as is” and “as available,” without warranty of any kind. However, MobileCoin Wallets linked to a Signal mobile messaging application or any other mobile messaging applications may integrate software from a third party. MobileCoin Wallets must be accessed through a telephone, computer or other equipment as well as a network connection through telecommunication lines or other utility. None of these components of the MobileCoin Wallet is provided or controlled by the Compliance Entities. The Compliance Entities and their Associates are not responsible for the accuracy or reliability of any open-source software or of any software, hardware, information, or advice provided by third parties or for their privacy and security policies and procedures. Access to and use of your MobileCoin Wallet may from time to time be unavailable, delayed, limited or slowed due to failures of hardware, software, utility services or other causes outside the control of the Compliance Entities. You may suffer losses as a result of these delays and limitations. You assume all risks associated with the operation, performance and security of a MobileCoin Wallet. You are responsible for maintaining the security of your MobileCoin Wallet and any password or other security designed to limit access. -In addition to these Terms, you may be bound by any additional terms required by your third-party providers. These third parties' terms may apply to your use of the MobileCoin Wallets. Please be aware that these Terms do not govern third parties' relationships with you. These third parties, and not any Compliance Entity, are responsible for any product or service warranties, whether express or implied by law, provided to you. +In addition to these Terms, you may be bound by any additional terms required by your third-party providers. These third parties’ terms may apply to your use of the MobileCoin Wallets. Please be aware that these Terms do not govern third parties’ relationships with you. These third parties, and not any Compliance Entity, are responsible for any product or service warranties, whether express or implied by law, provided to you. -## **Nature of MobileCoins and Transactions in MobileCoins** +## Nature of MobileCoins and Transactions in MobileCoins -MobileCoins are digital tokens. Digital tokens such as MobileCoins are not legal tender, are not backed by any government, and are not insured. MobileCoins do not provide you with any ownership of any physical asset or ownership or other interest or rights of any form with respect to the Compliance Entities or any affiliate or its revenue or assets, including any voting, distribution, redemption, liquidation, proprietary (including all forms of intellectual property), or other financial or legal rights. MobileCoins are distributed and offered on an as-is, and, are offered without any representation as to merchantability or fitness for any particular purpose. +MobileCoins are digital tokens. Digital tokens such as MobileCoins are not legal tender, are not backed by any government, and are not insured. MobileCoins do not provide you with any ownership of any physical asset or ownership or other interest or rights of any form with respect to the Compliance Entities or any affiliate or its revenue or assets, including any voting, distribution, redemption, liquidation, proprietary (including all forms of intellectual property), or other financial or legal rights. MobileCoins are distributed and offered on an as-is, where-is basis and, without limiting the generality of the foregoing, are offered without any representation as to merchantability or fitness for any particular purpose. -You accept that the Compliance Entities may be required to share your user information with other contractual third parties, including financial institutions, or as required under applicable laws or demanded upon a lawful request by any government. When information includes personal data under European Union law and/or California law, the terms of the Privacy Policy will apply. Please consult the appropriate Privacy Policy available at [www.buymobilecoin.us](https://www.buymobilecoin.us/) and [www.buymobilecoin.com](https://www.buymobilecoin.com/). +You accept that the Compliance Entities may be required to share your user information with other contractual third parties, including financial institutions, or as required under applicable laws or demanded upon a lawful request by any government. When information includes personal data under European Union law, the terms of the Privacy Policy will apply. Please consult the Privacy Policy available at the MobileCoin TS Ltd. website at http://www.buymobilecoin.com/. -You accept all consequences of sending MobileCoins. MobileCoin transactions are not reversible or refundable. Once you send MobileCoins to an address, whether intentionally or by a fraudulent or accidental transaction, you accept the risk that you may lose access to, and any claim on, those MobileCoins indefinitely or permanently. +You accept all consequences of sending MobileCoins. MobileCoin transactions are not reversible. Once you send MobileCoins to an address, whether intentionally or by a fraudulent or accidental transaction, you accept the risk that you may lose access to, and any claim on, those MobileCoins indefinitely or permanently. -## **Prohibited Uses and Transfers of MobileCoins and Uses of MobileCoin Wallets** +## Prohibited Uses and Transfers of MobileCoins and Uses of MobileCoin Wallets You may not: - -- use or transfer MobileCoins or access or use a MobileCoin Wallet for any illegal purposes; - use or transfer MobileCoins or access or use a MobileCoin Wallet in order to disguise the origin or nature of illicit proceeds of, or to further, any breach of applicable laws, or to transact or deal in any contraband funds, property, or proceeds; + - use or transfer MobileCoins or access or use a MobileCoin Wallet if such conduct is prohibited, penalized, or otherwise sanctionable under any applicable laws, including without limitation anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, and economic sanctions laws or would expose the Compliance Entities or their affiliates to liability under any applicable laws; -- use or transfer MobileCoins or access or use a MobileCoin Wallet or any third party services to facilitate, approve, evade, avoid, or circumvent any applicable laws, including anti-money laundering laws, counterterrorist financing laws, anti-corruption laws, and economic sanctions laws; -- use, or transfer MobileCoins with a Prohibited Person or any individual or entity prohibited from using, transacting, transferring, trading, or receiving MobileCoins by these Terms or applicable laws; + +- use, transact, transfer, or trade MobileCoins (i) in the U.S.; (ii) with U.S. Persons; (iii) with persons or entities present in the U.S.; or (iv) if you are a U.S. Person, which includes but is not limited to while you are present in the U.S.; + +- transfer MobileCoins to a Prohibited Person, a U.S. Person, or any individual or entity prohibited from using, transacting, transferring, trading, or receiving MobileCoins by these Terms or applicable laws; + +- use or transfer MobileCoins or access or use a MobileCoin Wallet or any third party services to facilitate, approve, evade, avoid, or circumvent any applicable laws, including anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, and economic sanctions laws; + +- use a U.S. financial institution in connection with any dealings involving MobileCoins or MobileCoin Wallets or the Compliance Entities; + - use or transfer MobileCoins or access or use a MobileCoin Wallet to evade taxes under applicable laws; + - use or transfer MobileCoins or access or use a MobileCoin Wallet to interfere with or subvert the rights or obligations of the Compliance Entities or the rights or obligations of any other individual or entity; + - use or transfer MobileCoins or access or use a MobileCoin Wallet by using misleading or inaccurate information or to take advantage of any technical glitch, malfunction, failure, delay, default, or security breach; + - use or transfer MobileCoins or access or use a MobileCoin Wallet to engage in conduct that is detrimental to the Compliance Entities or to any other individual or entity; -- falsify or materially omit any information provided to or provide misleading or inaccurate information requested by the Compliance Entities or impersonate another individual or entity or misrepresent your affiliation with an individual or entity; + +- falsify any information provided to the Compliance Entities or impersonate another individual or entity or misrepresent your affiliation with an individual or entity; + +- falsify or materially omit any information or provide misleading or inaccurate information requested by the Compliance Entities; + - cause injury to, or attempt to harm, the Compliance Entities or any other individual or entity through your access to or use of any MobileCoins and any MobileCoin Wallets; or + - violate, promote, or cause a violation of, or conspire or attempt to violate these Terms or applicable laws. Any of these uses may be described in these Terms as a Prohibited Use. Should your actions or inaction result in Loss being suffered by the Compliance Entities or any Associates, you will pay an amount to the Compliance Entities or the Associates so as to render the Compliance Entities or the Associates whole, including the amount of taxes or penalties that might be imposed on the Compliance Entities or the Associates. -In these Terms, Associates of the Compliance Entities means the successors, assignees and affiliates of MobileCoin TS Ltd., MobileCoin U.S., LLC and their respective shareholders, directors, officers, affiliates, employees, contractors, agents, partners, insurers, attorneys, and any licensors of technology to the Compliance Entities. +In these Terms, Associates of the Compliance Entities means the successors, assignees and affiliates of MobileCoin TS Ltd. and their respective shareholders, directors, officers, affiliates, employees, contractors, agents, partners, insurers, attorneys, and any licensors of technology to the Compliance Entities. -In these Terms, Losses means any claim, application, loss, injury, delay, accident, cost, business interruption costs, or any other expenses (including attorneys' fees or the costs of any claim or suit), including any incidental, direct, indirect, general, special, punitive, exemplary, or consequential damages, loss of goodwill or business profits, work stoppage, data loss, computer failure or malfunction, or any and all other commercial losses; +In these Terms, Losses means any claim, application, loss, injury, delay, accident, cost, business interruption costs, or any other expenses (including attorneys’ fees or the costs of any claim or suit), including any incidental, direct, indirect, general, special, punitive, exemplary, or consequential damages, loss of goodwill or business profits, work stoppage, data loss, computer failure or malfunction, or any and all other commercial losses; -## **Intellectual Property** +## Intellectual Property -The MobileCoin name and logo are protected trademarks. You agree not to copy, modify, display, or use these trademarks without written permission from the Compliance Entities. All rights not expressly granted to you in these Terms are reserved. +The MobileCoin name and logo are protected trademarks. You agree not to appropriate, copy, reproduce, modify, display, or use these trademarks without express, prior, written permission from the Compliance Entities. All rights not expressly granted to you in these Terms are reserved. -## **Your Representations and Warranties** +## Your Representations and Warranties -You represent and warrant to the Compliance Entities on the date of your acceptance of these Terms and each day on which you use or transfer MobileCoins or use a MobileCoin Wallet, in each case with reference to the facts and circumstances existing at such date, as follows: +You represent and warrant to the Compliance Entities on the date of your acceptance or deemed acceptance of these Terms and each day on which you use or transfer MobileCoins or each time you access or use a MobileCoin Wallet, in each case with reference to the facts and circumstances existing at such date, as follows: - that, if you are an individual, you are 18 years of age or older and that you have the capacity to contract under applicable laws; + - that, if you are acting on behalf of a legal entity, (i) such legal entity is duly organized and validly existing under the applicable laws of the jurisdiction of its organization; and (ii) you are duly authorized by such legal entity to act on its behalf; -- that neither you nor any individual or entity acting on your behalf is a Prohibited Person or otherwise prohibited or restricted from purchasing or otherwise obtaining MobileCoins, using or transferring MobileCoins or accessing or using MobileCoin Wallets; + +- that neither you nor any individual or entity acting on your behalf is a Prohibited Person or U.S. Person, or otherwise prohibited or restricted from purchasing or otherwise obtaining MobileCoins, using or transferring MobileCoins or accessing or using MobileCoin Wallets; + - that you will not engage in any Prohibited Uses or transfers, as described above; + - that you comply with the laws of your country of establishment, incorporation, residence, or location and, as applicable, the country from which you use any MobileCoins and any MobileCoin Wallets; -- that you understand and acknowledge that the Compliance Entities are not registered with or licensed by any financial regulatory authority in the British Virgin Islands, United States or elsewhere; and that accordingly, no British Virgin Islands, United States or other financial regulatory authority has passed upon the contents of these Terms or the merits of purchasing or using MobileCoins, nor have these Terms been filed with, or reviewed by any British Virgin Islands, United States or other financial regulatory authority; + +- that you understand and acknowledge that the Compliance Entities are not registered with or licensed by any financial regulatory authority in the British Virgin Islands or elsewhere; and that accordingly, no British Virgin Islands or other financial regulatory authority has passed upon the contents of these Terms or the merits of purchasing or using MobileCoins, nor have these Terms been filed with, or reviewed by any British Virgin Islands or other financial regulatory authority; + - that you have had the opportunity to seek legal, accounting, taxation and other professional advice regarding these Terms, any MobileCoins and any MobileCoin Wallets; + - that you are currently in compliance with, and must, at your own cost and expense, comply with all laws that relate to or affect these Terms, including anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, economic sanctions laws, Tax Information Exchange Laws or other tax laws; + - that you will not utilize any virtual private network, proxy service, or any other third-party service, or network for the purpose of disguising or misrepresenting your IP address or location in order to download or use the MobileCoin Wallet in a manner prohibited in these Terms; + - that you consent to any and all tax and information reporting under anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, economic sanctions laws, Tax Information Exchange Laws or other tax laws as the Compliance Entities may reasonably determine and to extent permitted by law; + - that neither you nor any of your affiliates are acting directly or indirectly (i) on behalf of or for the benefit of a Prohibited Person; (ii) in violation of or as prohibited, restricted, or penalized under applicable economic sanctions laws; or (iii) in any way that would violate, be inconsistent with, penalized under, or cause the omission of filing of any report required under applicable anti-money laundering laws, counter-terrorist financing laws, or economic sanctions laws; -- that neither you nor any of your affiliates is: (i) itself or owned (beneficially or of record) or controlled by a Prohibited Person; (ii) involved in any transaction, transfer, or conduct that is likely to result in you or your affiliates becoming a Prohibited Person; (iii) residing or domiciled in a Prohibited Jurisdiction; (iv) transferring any funds, where denominated in MobileCoin or another cryptocurrency or fiat currency, to, from, or through a Prohibited Jurisdiction in connection to any dealings or conduct with or involving the Compliance Entities; (v) a government or government official of a Prohibited Jurisdiction; or (vi) otherwise a Prohibited Person; + +- that neither you nor any of your affiliates is: (i) itself or owned (beneficially or of record) or controlled by a Prohibited Person; (ii) involved in any transaction, transfer, or conduct that is likely to result in you or your affiliates becoming a Prohibited Person; (iii) residing or domiciled in a Prohibited Jurisdiction or the United States; (iv) transferring any funds, where denominated in MobileCoin or another cryptocurrency or fiat currency, to, from, or through a Prohibited Jurisdiction or the United States in connection to any dealings or conduct with or involving the Compliance Entities; (v) a government or government official of a Prohibited Jurisdiction; or (vi) otherwise a Prohibited Person; + - that you will fairly and promptly report all income associated with your use, transaction, transfer, or trade of MobileCoins and access and use MobileCoin Wallets, as applicable, pursuant to applicable laws and pay any and all taxes thereon; + - that you will accurately and promptly inform the Compliance Entities if you know or have reason to know whether any of the foregoing representations or warranties no longer is correct or becomes incorrect; and + - you will use, transact, transfer, and trade MobileCoins and access and use your MobileCoin Wallet for consumptive, and not for investment, purposes. In these Terms, Tax Information Exchange Laws means laws relating to the exchange of information relating to taxes between governments, including United States Foreign Account Tax Compliance Act, as enacted by Title V, Subtitle A of the Hiring Incentives to Restore Employment Act, P.L 111-147 (2010), as amended; and common reporting standard or the Standard for Automatic Exchange of Financial Account Information. -## **No Representations or Advice by the Compliance Entities** +## No Representations or Advice by the Compliance Entities + +The Compliance Entities make no representations, warranties, covenants or guarantees to you of any kind and, to the extent permitted by applicable laws, the Compliance Entities expressly disclaim all representations, warranties, covenants or guarantees, express, implied or statutory, with respect to MobileCoins and any MobileCoin Wallet. The MobileCoins and the MobileCoin Wallet are distributed and offered strictly on an as-is, where-is basis and, without limiting the generality of the foregoing, are distributed and offered without any representation as to merchantability or fitness for any particular purpose. The Compliance Entities do not provide any investment, legal, accounting, tax or other advice. + +## Limitation of Liability, Release, and Indemnity + +**Important: Except as may be provided for in these Terms, the Compliance Entities assume no liability or responsibility for and will have no liability or responsibility for any Losses directly or indirectly arising out of or related to:** + +- **these Terms,** -The Compliance Entities make no warranties, or guarantees to you of any kind and, to the extent permitted by applicable laws, the Compliance Entities expressly disclaim all representations, warranties, covenants or guarantees, express, implied or statutory, with respect to MobileCoins and any MobileCoin Wallet. The MobileCoins and the MobileCoin Wallet are distributed and offered strictly on an as-is, and, without limiting the generality of the foregoing, are distributed and offered without any representation as to merchantability or fitness for any particular purpose. The Compliance Entities do not provide any investment, legal, accounting, tax or other advice. +- **MobileCoins and their use and transfer,** -## **Limitation of Liability, Release, and Indemnity** +- **your MobileCoin Wallet, and your access and use of it,** -Important: Except as may be provided for in these Terms, the Compliance Entities assume no liability or responsibility for and will have no liability or responsibility for any Losses directly or indirectly arising out of or related to: +- **to the extent permitted by law, any stolen, lost, or unauthorized use of your personal information, any breach of security or data breach related to your personal information, or any criminal or other third-party act affecting the Compliance Entities, or** -- these Terms, -- MobileCoins and their use and transfer, -- your MobileCoin Wallet, and your access and use of it, -- to the extent permitted by law, any stolen, lost, or unauthorized use of your personal information, any breach of security or data breach related to your personal information, or any criminal or other third-party act affecting the Compliance Entities, or -- any unauthorized representation, suggestion, statement, or claim made about MobileCoins or the MobileCoin Wallet. +- **any representation, suggestion, statement, or claim made about MobileCoins or the MobileCoin Wallet.** -You agree to release the Compliance Entities and its Associates from liability for any and all Losses, and you will indemnify and save and hold the Compliance Entities and its Associates harmless from and against all Losses. The foregoing limitations of liability will apply, to the extent permitted by law, whether the alleged liability or losses are based on contract, negligence, tort, unjust enrichment, strict liability, violation of law or regulation, or any other basis, even if the Compliance Entities and its Associates have been advised of or should have known of the possibility of such losses and damages, and without regard to the success or effectiveness of any other remedies. +**You agree to release the Compliance Entities and its Associates from liability for any and all Losses, and you will indemnify and save and hold the Compliance Entities and its Associates harmless from and against all Losses. The foregoing limitations of liability will apply, to the extent permitted by law, whether the alleged liability or losses are based on contract, negligence, tort, unjust enrichment, strict liability, violation of law or regulation, or any other basis, even if the Compliance Entities and its Associates have been advised of or should have known of the possibility of such losses and damages, and without regard to the success or effectiveness of any other remedies.** -## **Electronic Communications** +## Electronic Communications -You agree and consent to receive electronically all communications, agreements, receipts and disclosures that the Compliance Entities may provide in connection with these Terms. Information in relation to how we may communicate with you and your rights in that respect can be found in the appropriate Privacy Policy at [www.buymobilecoin.us](https://www.buymobilecoin.us/) or [www.buymobilecoin.com](https://www.buymobilecoin.com/). +You agree and consent to receive electronically all communications, agreements, documents, receipts, notices and disclosures that the Compliance Entities may provide in connection with these Terms. Information in relation to how we may communicate with you and your rights in that respect can be found in the Privacy Policy at http://www.buymobilecoin.com/. -## **Miscellaneous** +## Miscellaneous -Any right or remedy of the Compliance Entities set forth in these Terms is in addition to, and not in lieu of, any other right or remedy whether described in these Terms, at law or in equity. The Compliance Entities' failure or delay in exercising any right, power, or privilege under these Terms will not operate as a waiver thereof. If any portion of these Terms is found to be invalid or unenforceable for any reason, the invalid or unenforceable provision shall be severed from these Terms. Severance of invalid or unenforceable provisions of any of these Terms will not affect the validity or enforceability of any other of these Terms, all of which will remain in full force and effect. The Compliance Entities will have no responsibility or liability for any failure or delay in performance, or any loss or damage that you may incur, due to any Force Majeure or circumstance or event beyond its control. You may not assign or transfer any of your rights or obligations under these Terms, without the Compliance Entities' prior written consent, including by operation of law or in connection with any change of control, and any such assignment or transfer by you without the Compliance Entities' prior written consent shall be null and void and of no effect. The Compliance Entities may assign or transfer any or all of its rights or obligations under these Terms, without notice or your consent. If there is a conflict between these Terms and any other agreement with the Compliance Entities, these Terms will control unless the other agreement specifically identifies these Terms and declares that the other agreement supersedes these Terms. These Terms do not create any third-party beneficiary rights in any person, save that any Compliance Entity or any of its respective Associates may rely on these Terms in any action, suit, proceeding or other dispute brought against it by you, to exercise any right or to benefit from any limitation expressly provided to it hereunder and to enforce such provisions of these Terms as if party hereto. +Any right or remedy of the Compliance Entities set forth in these Terms is in addition to, and not in lieu of, any other right or remedy whether described in these Terms, at law or in equity. The Compliance Entities’ failure or delay in exercising any right, power, or privilege under these Terms will not operate as a waiver thereof. The invalidity or unenforceability of any of these Terms will not affect the validity or enforceability of any other of these Terms, all of which will remain in full force and effect. The Compliance Entities will have no responsibility or liability for any failure or delay in performance, or any loss or damage that you may incur, due to any Force Majeure or circumstance or event beyond its control. You may not assign or transfer any of your rights or obligations under these Terms, without the Compliance Entities’ prior written consent, including by operation of law or in connection with any change of control. The Compliance Entities may assign or transfer any or all of it rights or obligations under these Terms, without notice or your consent. If there is a conflict between these Terms and any other agreement you may have with the Compliance Entities, these Terms will control unless the other agreement specifically identifies these Terms and declares that the other agreement supersedes these Terms. If one or more provisions of these Terms is invalidated or declared ineffective, all other provisions of these Terms shall remain in full force and effect. These Terms do not create any third-party beneficiary rights in any person, save that any Compliance Entity or any of its respective Associates may rely on these Terms in any action, suit, proceeding or other dispute brought against it by you, to exercise any right or to benefit from any limitation expressly provided to it hereunder and to enforce such provisions of these Terms as if party hereto. -## **Governing Law and Resolution of Disputes** +## Governing Law and Resolution of Disputes -Any dispute, claim, controversy or action arising out of or related to (a) these Terms or the existence, breach, termination, enforcement, interpretation or validity thereof or (b) your MobileCoins or MobileCoin Wallet, will be subject to the exclusive jurisdiction of the courts of the British Virgin Islands. This provision expressly applies to any claim, whether in tort, contract or otherwise, against the Compliance Entities. +Any dispute, claim, controversy or action arising out of or related to (a) these Terms or the existence, breach, termination, enforcement, interpretation or validity thereof or (b) your MobileCoins or MobileCoin Wallet, will be subject to the exclusive jurisdiction of the courts of the British Virgin Islands. For the avoidance of doubt, and without limiting the generality of the foregoing, this provision expressly applies to any claim, whether in tort, contract or otherwise, against the Compliance Entities. -You irrevocably and unconditionally agree and consent to the jurisdiction and venue of the courts of the British Virgin Islands, and you waive any objections. The foregoing shall be without prejudice to any applicable provisions of mandatory consumer protection law under the laws of your country of residence, to the extent that these offer you more protection. +You irrevocably and unconditionally agree and consent to the jurisdiction and venue of the courts of the British Virgin Islands, and you waive any objections thereto, including under the doctrine of forum non conveniens or other similar doctrines. The foregoing shall be without prejudice to any applicable provisions of mandatory consumer protection law under the laws of your country of residence, to the extent that these offer you more protection. Any complaint or dispute is personal to you and you agree that it will not be brought as a class action, class arbitration or any other type of representative proceeding. There will be no class action in which you attempt to resolve a complaint or dispute as a representative of another individual or group of individuals, save with the express agreement in writing of the relevant Compliance Entity. -JURY TRIAL WAIVER: TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, THE PARTIES HEREBY IRREVOCABLY AND UNCONDITIONALLY WAIVE ALL RIGHT TO TRIAL BY JURY IN ANY LEGAL ACTION OR PROCEEDING OF ANY KIND WHATSOVER ARISING OUT OF OR RELATING TO THESE TERMS OR ANY BREACH THEREOF, ANY USE OR ATTEMPTED USE OR TRANSFER OF MOBILECOINS OR USE OR ATTEMPED USE OF A MOBILECOIN WALLET BY YOU, AND/OR ANY OTHER MATTER INVOLVING THE PARTIES. +JURY TRIAL WAIVER: TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, THE PARTIES HEREBY IRREVOCABLY AND UNCONDITIONALLY WAIVE ALL RIGHT TO TRIAL BY JURY IN ANY LEGAL ACTION OR PROCEEDING OF ANY KIND WHATSOVER ARISING OUT OF OR RELATING TO THESE TERMS OR ANY BREACH THEREOF, ANY USE OR ATTEMPTED USE OR TRANSFER OF MOBILECOINS OR USE OR ATTEMPED USE OF A MOBILECOIN WALLET BY YOU, AND/OR ANY OTHER MATTER INVOLVING THE PARTIES. -## **Language and Contact** +## Language and Contact -These Terms and any information or notifications that are provided under these Terms shall be in English. +These Terms and any information or notifications that are provided under these Terms shall be in English. -If you have any questions relating to these Terms, your rights and obligations arising from these Terms and/or your use of any MobileCoins and any MobileCoin Wallets, please use the question form at [www.buymobilecoin.us](https://www.buymobilecoin.us/) or the MobileCoin TS Ltd. website at [www.buymobilecoin.com](https://www.buymobilecoin.com/). +If you have any questions relating to these Terms, your rights and obligations arising from these Terms and/or your use of any MobileCoins and any MobileCoin Wallets or any other matter, please utilize the question form on the MobileCoin TS Ltd. website at http://www.buymobilecoin.com/. diff --git a/Tests/Common/Fixtures/Network/NetworkPreset.swift b/Tests/Common/Fixtures/Network/NetworkPreset.swift index dd486cfc..ff1538e2 100644 --- a/Tests/Common/Fixtures/Network/NetworkPreset.swift +++ b/Tests/Common/Fixtures/Network/NetworkPreset.swift @@ -308,6 +308,32 @@ extension NetworkPreset { } +final class TestHttpRequester: HttpRequester { + func request( + url: URL, + method: HTTPMethod, + headers: [String: String]?, + body: Data?, + completion: @escaping (HTTPResult) -> Void + ) { + let task = URLSession.shared.dataTask(with: url) {data, response, error in + if let error = error { + completion(.failure(error: error)) + return + } + guard let response = response as? HTTPURLResponse, + (200...299).contains(response.statusCode) else { + completion(.failure(error: ConnectionError.invalidServerResponse(""))) + return + } + let httpResponse = HTTPResponse(httpUrlResponse: response, responseData: data) + completion(.success(response: httpResponse)) + + } + task.resume() + } +} + extension NetworkPreset { func networkConfig() throws -> NetworkConfig { @@ -316,6 +342,7 @@ extension NetworkPreset { consensusUrl: consensusUrl, fogUrl: fogUrl, attestation: attestationConfig).get() + networkConfig.httpRequester = TestHttpRequester() networkConfig.consensusTrustRoots = try consensusTrustRoots() networkConfig.fogTrustRoots = try fogTrustRoots() networkConfig.consensusAuthorization = consensusCredentials diff --git a/Tests/Integration/IntegrationTestFixtures.swift b/Tests/Integration/IntegrationTestFixtures.swift index 5625bf04..c43a1cab 100644 --- a/Tests/Integration/IntegrationTestFixtures.swift +++ b/Tests/Integration/IntegrationTestFixtures.swift @@ -9,7 +9,7 @@ import NIOSSL import XCTest enum IntegrationTestFixtures { - static let network: NetworkPreset = .alpha + static let network: NetworkPreset = .mobiledev } extension IntegrationTestFixtures { diff --git a/Tests/Integration/Network/Connection/FogReportConnectionIntTests.swift b/Tests/Integration/Network/Connection/FogReportConnectionIntTests.swift index deb069cd..dbe42d9e 100644 --- a/Tests/Integration/Network/Connection/FogReportConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/FogReportConnectionIntTests.swift @@ -32,6 +32,7 @@ extension FogReportConnectionIntTests { let url = try FogUrl.make(string: IntegrationTestFixtures.network.fogReportUrl).get() return FogReportConnection( url: url, + transportProtocolOption: .grpc, channelManager: GrpcChannelManager(), targetQueue: DispatchQueue.main) } diff --git a/Tests/Integration/Network/Connection/FogViewConnectionIntTests.swift b/Tests/Integration/Network/Connection/FogViewConnectionIntTests.swift index d27d84a4..1de33e7b 100644 --- a/Tests/Integration/Network/Connection/FogViewConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/FogViewConnectionIntTests.swift @@ -250,6 +250,7 @@ extension FogViewConnectionIntTests { FogViewConnection( config: networkConfig.fogView, channelManager: GrpcChannelManager(), + httpRequester: nil, targetQueue: DispatchQueue.main) } } From 82f62ab79bec7ebbf52a3d4349eb4c7d4197b300 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Wed, 25 Aug 2021 01:23:20 -0700 Subject: [PATCH 16/53] add converted grpc -> http bindings for consensus_client and ledger --- .../consensus_client.http.swift | 11 +-- .../Http Proto Generated/ledger.http.swift | 93 ++++++++++--------- 2 files changed, 49 insertions(+), 55 deletions(-) diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift index 1f0c2c16..389d6f75 100644 --- a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift @@ -32,7 +32,7 @@ extension ConsensusClient_ConsensusClientAPIRestClientProtocol { _ request: Attest_Message, callOptions: HTTPCallOptions? = nil ) -> HTTPUnaryCall { - return self.makeHTTPUnaryCall( + return self.makeUnaryCall( path: "/consensus_client.ConsensusClientAPIRest/ClientTxPropose", request: request, callOptions: callOptions ?? self.defaultHTTPCallOptions @@ -40,12 +40,6 @@ extension ConsensusClient_ConsensusClientAPIRestClientProtocol { } } -public protocol ConsensusClient_ConsensusClientAPIRestClientInterceptorFactoryProtocol { - - /// - Returns: Interceptors to use when invoking 'clientTxPropose'. - func makeClientTxProposeInterceptors() -> [ClientInterceptor] -} - public final class ConsensusClient_ConsensusClientAPIRestClient: ConsensusClient_ConsensusClientAPIRestClientProtocol { public var defaultHTTPCallOptions: HTTPCallOptions @@ -56,8 +50,7 @@ public final class ConsensusClient_ConsensusClientAPIRestClient: ConsensusClient /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. /// - interceptors: A factory providing interceptors for each RPC. public init( - defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions(), - interceptors: ConsensusClient_ConsensusClientAPIRestClientInterceptorFactoryProtocol? = nil + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { self.defaultHTTPCallOptions = defaultHTTPCallOptions } diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift index 3f8a1ca4..22c136ea 100644 --- a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift @@ -32,13 +32,13 @@ public protocol FogLedger_FogMerkleProofAPIRestProtocol: HTTPClient { func auth( _ request: Attest_AuthMessage, - callOptions: CallOptions? - ) -> UnaryCall + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall func getOutputs( _ request: Attest_Message, - callOptions: CallOptions? - ) -> UnaryCall + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall } extension FogLedger_FogMerkleProofAPIRestProtocol { @@ -55,12 +55,13 @@ extension FogLedger_FogMerkleProofAPIRestProtocol { /// - Returns: A `UnaryCall` with futures for the metadata, status and response. public func auth( _ request: Attest_AuthMessage, - callOptions: CallOptions? = nil - ) -> UnaryCall { + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { return self.makeUnaryCall( path: "/fog_ledger.FogMerkleProofAPI/Auth", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultHTTPCallOptions + ) } //// Get TxOut's and merkle proofs of membership for these outputs @@ -73,12 +74,12 @@ extension FogLedger_FogMerkleProofAPIRestProtocol { /// - Returns: A `UnaryCall` with futures for the metadata, status and response. public func getOutputs( _ request: Attest_Message, - callOptions: CallOptions? = nil - ) -> UnaryCall { + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { return self.makeUnaryCall( path: "/fog_ledger.FogMerkleProofAPI/GetOutputs", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultHTTPCallOptions ) } } @@ -94,19 +95,19 @@ public protocol FogLedger_FogMerkleProofAPIInterceptorFactoryProtocol { public final class FogLedger_FogMerkleProofAPI: FogLedger_FogMerkleProofAPIRestProtocol { public let channel: GRPCChannel - public var defaultCallOptions: CallOptions + public var defaultHTTPCallOptions: HTTPCallOptions /// Creates a client for the fog_ledger.FogMerkleProofAPI service. /// /// - Parameters: /// - channel: `GRPCChannel` to the service host. - /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. public init( channel: GRPCChannel, - defaultCallOptions: CallOptions = CallOptions() + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { self.channel = channel - self.defaultCallOptions = defaultCallOptions + self.defaultHTTPCallOptions = defaultHTTPCallOptions } } @@ -116,13 +117,13 @@ public protocol FogLedger_FogKeyImageAPIRestProtocol: HTTPClient { func auth( _ request: Attest_AuthMessage, - callOptions: CallOptions? - ) -> UnaryCall + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall func checkKeyImages( _ request: Attest_Message, - callOptions: CallOptions? - ) -> UnaryCall + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall } extension FogLedger_FogKeyImageAPIRestProtocol { @@ -138,12 +139,12 @@ extension FogLedger_FogKeyImageAPIRestProtocol { /// - Returns: A `UnaryCall` with futures for the metadata, status and response. public func auth( _ request: Attest_AuthMessage, - callOptions: CallOptions? = nil - ) -> UnaryCall { + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { return self.makeUnaryCall( path: "/fog_ledger.FogKeyImageAPI/Auth", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultHTTPCallOptions ) } @@ -155,12 +156,12 @@ extension FogLedger_FogKeyImageAPIRestProtocol { /// - Returns: A `UnaryCall` with futures for the metadata, status and response. public func checkKeyImages( _ request: Attest_Message, - callOptions: CallOptions? = nil - ) -> UnaryCall { + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { return self.makeUnaryCall( path: "/fog_ledger.FogKeyImageAPI/CheckKeyImages", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultHTTPCallOptions ) } } @@ -176,19 +177,19 @@ public protocol FogLedger_FogKeyImageAPIInterceptorFactoryProtocol { public final class FogLedger_FogKeyImageAPI: FogLedger_FogKeyImageAPIRestProtocol { public let channel: GRPCChannel - public var defaultCallOptions: CallOptions + public var defaultHTTPCallOptions: HTTPCallOptions /// Creates a client for the fog_ledger.FogKeyImageAPI service. /// /// - Parameters: /// - channel: `GRPCChannel` to the service host. - /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. public init( channel: GRPCChannel, - defaultCallOptions: CallOptions = CallOptions() + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { self.channel = channel - self.defaultCallOptions = defaultCallOptions + self.defaultHTTPCallOptions = defaultHTTPCallOptions } } @@ -198,8 +199,8 @@ public protocol FogLedger_FogBlockAPIRestProtocol: HTTPClient { func getBlocks( _ request: FogLedger_BlockRequest, - callOptions: CallOptions? - ) -> UnaryCall + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall } extension FogLedger_FogBlockAPIRestProtocol { @@ -217,12 +218,12 @@ extension FogLedger_FogBlockAPIRestProtocol { /// - Returns: A `UnaryCall` with futures for the metadata, status and response. public func getBlocks( _ request: FogLedger_BlockRequest, - callOptions: CallOptions? = nil - ) -> UnaryCall { + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { return self.makeUnaryCall( path: "/fog_ledger.FogBlockAPI/GetBlocks", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultHTTPCallOptions ) } } @@ -235,19 +236,19 @@ public protocol FogLedger_FogBlockAPIInterceptorFactoryProtocol { public final class FogLedger_FogBlockAPI: FogLedger_FogBlockAPIRestProtocol { public let channel: GRPCChannel - public var defaultCallOptions: CallOptions + public var defaultHTTPCallOptions: HTTPCallOptions /// Creates a client for the fog_ledger.FogBlockAPI service. /// /// - Parameters: /// - channel: `GRPCChannel` to the service host. - /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. public init( channel: GRPCChannel, - defaultCallOptions: CallOptions = CallOptions() + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { self.channel = channel - self.defaultCallOptions = defaultCallOptions + self.defaultHTTPCallOptions = defaultHTTPCallOptions } } @@ -257,8 +258,8 @@ public protocol FogLedger_FogUntrustedTxOutApiClientProtocol: HTTPClient { func getTxOuts( _ request: FogLedger_TxOutRequest, - callOptions: CallOptions? - ) -> UnaryCall + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall } extension FogLedger_FogUntrustedTxOutApiClientProtocol { @@ -287,12 +288,12 @@ extension FogLedger_FogUntrustedTxOutApiClientProtocol { /// - Returns: A `UnaryCall` with futures for the metadata, status and response. public func getTxOuts( _ request: FogLedger_TxOutRequest, - callOptions: CallOptions? = nil - ) -> UnaryCall { + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { return self.makeUnaryCall( path: "/fog_ledger.FogUntrustedTxOutApi/GetTxOuts", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultHTTPCallOptions ) } } @@ -305,19 +306,19 @@ public protocol FogLedger_FogUntrustedTxOutApiClientInterceptorFactoryProtocol { public final class FogLedger_FogUntrustedTxOutApiClient: FogLedger_FogUntrustedTxOutApiClientProtocol { public let channel: GRPCChannel - public var defaultCallOptions: CallOptions + public var defaultHTTPCallOptions: HTTPCallOptions /// Creates a client for the fog_ledger.FogUntrustedTxOutApi service. /// /// - Parameters: /// - channel: `GRPCChannel` to the service host. - /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. public init( channel: GRPCChannel, - defaultCallOptions: CallOptions = CallOptions() + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { self.channel = channel - self.defaultCallOptions = defaultCallOptions + self.defaultHTTPCallOptions = defaultHTTPCallOptions } } From c571e0559eb388db2c2ad3e9ba1506d51cf179ee Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Fri, 3 Sep 2021 16:27:24 -0700 Subject: [PATCH 17/53] Squashed Changes --- .gitmodules | 2 +- Example/Podfile.lock | 30 ++-- MobileCoin.podspec | 4 +- Sources/Common/Errors.swift | 3 + Sources/Fog/View/FogView.swift | 6 +- Sources/Ledger/KnownTxOut.swift | 10 +- Sources/Ledger/LedgerTxOut.swift | 19 +- Sources/Ledger/PartialTxOut.swift | 39 ++-- Sources/Ledger/TxOutProtocol.swift | 14 +- Sources/Ledger/TxOutUtils.swift | 129 +++++++++----- Sources/LibMobileCoin/ProtoExtensions.swift | 2 +- .../Connection/ConnectionSession.swift | 155 ++++++++++++++++ .../Connections/BlockchainConnection.swift | 9 +- .../Connections/ConsensusConnection.swift | 11 +- .../Connections/FogBlockConnection.swift | 9 +- .../Connections/FogKeyImageConnection.swift | 11 +- .../FogMerkleProofConnection.swift | 11 +- .../Connections/FogReportConnection.swift | 9 +- .../FogUntrustedTxOutConnection.swift | 9 +- .../Connections/FogViewConnection.swift | 12 +- .../ArbitraryHttpConnection.swift | 79 +++++++++ .../AttestedHttpConnection.swift | 23 ++- .../HTTPInterface/HTTPClientCall.swift | 20 +-- .../HTTPInterface/HTTPUnaryCall.swift | 2 +- .../HttpCallable/AuthHttpCallable.swift | 34 +++- .../AuthHttpCallableClientWrapper.swift | 105 +++++++++++ .../HttpCallable/HttpCallable.swift | 3 +- .../HttpClient/AuthHttpCallableClient.swift | 24 ++- .../HttpConnection/HttpClientWrapper.swift | 90 +++++----- .../HttpConnection/HttpConnection.swift | 9 +- .../BlockchainHttpConnection.swift | 19 +- .../ConsensusHttpConnection.swift | 53 +++++- .../FogBlockHttpConnection.swift | 24 +-- .../FogKeyImageHttpConnection.swift | 51 +++++- .../FogMerkleProofHttpConnection.swift | 51 +++++- .../FogReportHttpConnection.swift | 28 ++- .../FogUntrustedTxOutHttpConnection.swift | 34 +++- .../FogViewHttpConnection.swift | 45 ++++- .../Http Proto Generated/attest.http.swift | 90 ++++++++++ .../consensus_client.http.swift | 5 +- .../consensus_common.http.swift | 6 +- .../Http Proto Generated/ledger.http.swift | 82 ++------- .../Http Proto Generated/report.http.swift | 78 ++++++++ .../Http Proto Generated/view.http.swift | 96 ++++++++++ .../HttpConnection/HttpRequester.swift | 167 +++++++++++------- Sources/Network/NetworkConfig.swift | 4 +- .../Service/DefaultServiceProvider.swift | 14 +- Sources/Transaction/Receipt.swift | 31 +++- .../Transaction/TransactionSubmitter.swift | 2 + Sources/Utils/HTTP/HttpCallResult.swift | 95 +--------- Sources/Utils/MobileCoin-Bridging-Header.h | 18 ++ Sources/Utils/TestBridgingHeader.h | 11 ++ Sources/Utils/TestBridgingHeader.m | 16 ++ .../Fixtures/Network/NetworkPreset.swift | 40 +++-- .../Common/Mocks/Network/MockFogService.swift | 4 +- .../Integration/IntegrationTestFixtures.swift | 4 +- .../ConsensusConnectionIntTests.swift | 1 + .../FogBlockConnectionIntTests.swift | 1 + .../FogKeyImageConnectionIntTests.swift | 1 + .../FogMerkleProofConnectionIntTests.swift | 1 + .../FogReportConnectionIntTests.swift | 3 +- .../FogUntrustedTxOutConnectionIntTests.swift | 1 + .../FogViewConnectionIntTests.swift | 2 +- Vendor/libmobilecoin-ios-artifacts | 2 +- 64 files changed, 1458 insertions(+), 505 deletions(-) create mode 100644 Sources/Network/HttpConnection/ArbitraryHttpConnection.swift create mode 100644 Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/attest.http.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/report.http.swift create mode 100644 Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/view.http.swift create mode 100644 Sources/Utils/MobileCoin-Bridging-Header.h create mode 100644 Sources/Utils/TestBridgingHeader.h create mode 100644 Sources/Utils/TestBridgingHeader.m diff --git a/.gitmodules b/.gitmodules index 379ec5f2..a1e57401 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "Vendor/libmobilecoin-ios-artifacts"] path = Vendor/libmobilecoin-ios-artifacts - url = https://github.com/mobilecoinofficial/libmobilecoin-ios-artifacts.git + url = https://github.com/the-real-adammork/libmobilecoin-ios-artifacts.git shallow = true diff --git a/Example/Podfile.lock b/Example/Podfile.lock index bfb811b9..61c0b51b 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -18,42 +18,42 @@ PODS: - SwiftNIOTransportServices (< 2.0.0, >= 1.6.0) - SwiftProtobuf (< 2.0.0, >= 1.9.0) - Keys (1.0.1) - - LibMobileCoin (1.1.0): - - gRPC-Swift (~> 1.0.0) + - LibMobileCoin (1.1.1): + - gRPC-Swift (~> 1.0) - SwiftProtobuf (~> 1.5) - Logging (1.4.0) - - MobileCoin (1.1.0): - - MobileCoin/Core (= 1.1.0) - - MobileCoin/Core (1.1.0): + - MobileCoin (1.1.1): + - MobileCoin/Core (= 1.1.1) + - MobileCoin/Core (1.1.1): - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1) + - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint - SwiftNIO (~> 2.22) - SwiftNIOHPACK (~> 1.16) - SwiftNIOHTTP1 (~> 2.18) - SwiftProtobuf (~> 1.5) - - MobileCoin/Core/IntegrationTests (1.1.0): + - MobileCoin/Core/IntegrationTests (1.1.1): - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1) + - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint - SwiftNIO (~> 2.22) - SwiftNIOHPACK (~> 1.16) - SwiftNIOHTTP1 (~> 2.18) - SwiftProtobuf (~> 1.5) - - MobileCoin/Core/PerformanceTests (1.1.0): + - MobileCoin/Core/PerformanceTests (1.1.1): - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1) + - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint - SwiftNIO (~> 2.22) - SwiftNIOHPACK (~> 1.16) - SwiftNIOHTTP1 (~> 2.18) - SwiftProtobuf (~> 1.5) - - MobileCoin/Core/Tests (1.1.0): + - MobileCoin/Core/Tests (1.1.1): - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1) + - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint - SwiftNIO (~> 2.22) @@ -157,9 +157,9 @@ SPEC CHECKSUMS: CNIOWindows: f2baa102255e986467578337ffa2f777cb6bdf7f gRPC-Swift: 77154009a019e97f8c4bd8f2bb75fe9726801157 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: b6f5200b484ceac10bf988a42c1168e1d443bacc + LibMobileCoin: 5a070cacfba08e9a1dec3462c9b632785d0ed0a4 Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: c59b70afc472ffab517ffebae90a7cfc8a28259c + MobileCoin: d9d636ae8ebe8aef9ddc44107c615f5bb19bf5de SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftNIO: 81d33ce8c500b7e41b6cdde5f2f12330b9750219 SwiftNIOConcurrencyHelpers: 23fc68bac541a465162d7225d2c743edd2f1012c @@ -173,6 +173,6 @@ SPEC CHECKSUMS: SwiftNIOTransportServices: 896c9a4ac98698d32aa2feea7657ade219ae80bb SwiftProtobuf: 3320217e9d8fb75f36b40282e78c482640fd75dd -PODFILE CHECKSUM: a0d081de36bb0e26c2f240e65e5e63f9f111ec19 +PODFILE CHECKSUM: 21810a12546c9ea22d94f5e3fe7d63c8dc089fcf COCOAPODS: 1.9.3 diff --git a/MobileCoin.podspec b/MobileCoin.podspec index 827c2fe5..a95b2b3e 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -3,7 +3,7 @@ Pod::Spec.new do |s| # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.name = "MobileCoin" - s.version = "1.1.0" + s.version = "1.1.1" s.summary = "A library for communicating with MobileCoin network" s.author = "MobileCoin" @@ -28,7 +28,7 @@ Pod::Spec.new do |s| "Sources/**/*.{h,m,swift}", ] - subspec.dependency "LibMobileCoin", "~> 1.1" + subspec.dependency "LibMobileCoin", "~> 1.1.1" subspec.dependency "gRPC-Swift", "~> 1.0" subspec.dependency "Logging", "~> 1.4" diff --git a/Sources/Common/Errors.swift b/Sources/Common/Errors.swift index 105571de..c23b6200 100644 --- a/Sources/Common/Errors.swift +++ b/Sources/Common/Errors.swift @@ -142,6 +142,7 @@ public enum TransactionSubmissionError: Error { case invalidTransaction(String = String()) case feeError(String = String()) case tombstoneBlockTooFar(String = String()) + case missingMemo(String = String()) case inputsAlreadySpent(String = String()) } @@ -151,6 +152,8 @@ extension TransactionSubmissionError: CustomStringConvertible { switch self { case .connectionError(let connectionError): return "\(connectionError)" + case .missingMemo(let reason): + return "Missing memo error\(!reason.isEmpty ? ": \(reason)" : "")" case .feeError(let reason): return "Fee error\(!reason.isEmpty ? ": \(reason)" : "")" case .invalidTransaction(let reason): diff --git a/Sources/Fog/View/FogView.swift b/Sources/Fog/View/FogView.swift index 8fb2e855..8c948cfa 100644 --- a/Sources/Fog/View/FogView.swift +++ b/Sources/Fog/View/FogView.swift @@ -74,7 +74,7 @@ final class FogView { }.collectResult() }.flatMap { txOutRecords in txOutRecords.map { txOutRecord in - LedgerTxOut.make(txOutRecord: txOutRecord) + LedgerTxOut.make(txOutRecord: txOutRecord, viewKey: accountKey.viewPrivateKey) }.collectResult() }.map { txOuts in let foundTxOuts = Self.ownedTxOuts(validating: txOuts, accountKey: accountKey) @@ -179,10 +179,10 @@ struct FogSearchAttempt { } extension LedgerTxOut { - fileprivate static func make(txOutRecord: FogView_TxOutRecord) + fileprivate static func make(txOutRecord: FogView_TxOutRecord, viewKey: RistrettoPrivate) -> Result { - guard let ledgerTxOut = LedgerTxOut(txOutRecord) else { + guard let ledgerTxOut = LedgerTxOut(txOutRecord, viewKey: viewKey) else { let errorMessage = "Invalid TxOut returned from Fog View. TxOutRecord: " + "\(redacting: txOutRecord.serializedDataInfallible.base64EncodedString())" logger.error(errorMessage) diff --git a/Sources/Ledger/KnownTxOut.swift b/Sources/Ledger/KnownTxOut.swift index 35612f8c..9626514c 100644 --- a/Sources/Ledger/KnownTxOut.swift +++ b/Sources/Ledger/KnownTxOut.swift @@ -10,18 +10,26 @@ struct KnownTxOut: TxOutProtocol { let keyImage: KeyImage init?(_ ledgerTxOut: LedgerTxOut, accountKey: AccountKey) { + guard let value = ledgerTxOut.value(accountKey: accountKey), let keyImage = ledgerTxOut.keyImage(accountKey: accountKey) else { return nil } + + + guard let commitment = TxOutUtils.sharedSecret(publicKey: ledgerTxOut.publicKey, viewPrivateKey:accountKey.viewPrivateKey) else { + return nil + } + logger.warning("self.commitment: \n\n\(commitment.data.hexEncodedString(options: Data.HexEncodingOptions.upperCase))\n") + self.commitment = commitment.data32 self.ledgerTxOut = ledgerTxOut self.value = value self.keyImage = keyImage } - var commitment: Data32 { ledgerTxOut.commitment } + var commitment: Data32 var maskedValue: UInt64 { ledgerTxOut.maskedValue } var targetKey: RistrettoPublic { ledgerTxOut.targetKey } var publicKey: RistrettoPublic { ledgerTxOut.publicKey } diff --git a/Sources/Ledger/LedgerTxOut.swift b/Sources/Ledger/LedgerTxOut.swift index d14c2cbf..461082ae 100644 --- a/Sources/Ledger/LedgerTxOut.swift +++ b/Sources/Ledger/LedgerTxOut.swift @@ -17,6 +17,21 @@ struct LedgerTxOut: TxOutProtocol { } var commitment: Data32 { txOut.commitment } + + /* + public static RistrettoPublic getSharedSecret( + @NonNull RistrettoPrivate viewPrivateKey, + @NonNull RistrettoPublic txOutPublicKey + ) throws TransactionBuilderException { + Logger.i(TAG, "Retrieving shared secret", null, "txOut public:", txOutPublicKey); + try { + long rustObj = get_shared_secret(viewPrivateKey, txOutPublicKey); + return RistrettoPublic.fromJNI(rustObj); + } catch(Exception ex) { + throw new TransactionBuilderException(ex.getLocalizedMessage(), ex); + } + } + */ var maskedValue: UInt64 { txOut.maskedValue } var targetKey: RistrettoPublic { txOut.targetKey } var publicKey: RistrettoPublic { txOut.publicKey } @@ -30,8 +45,8 @@ extension LedgerTxOut: Equatable {} extension LedgerTxOut: Hashable {} extension LedgerTxOut { - init?(_ txOutRecord: FogView_TxOutRecord) { - guard let partialTxOut = PartialTxOut(txOutRecord) else { + init?(_ txOutRecord: FogView_TxOutRecord, viewKey: RistrettoPrivate) { + guard let partialTxOut = PartialTxOut(txOutRecord, viewKey: viewKey) else { return nil } let globalIndex = txOutRecord.txOutGlobalIndex diff --git a/Sources/Ledger/PartialTxOut.swift b/Sources/Ledger/PartialTxOut.swift index 77ac6e6d..debc5bc9 100644 --- a/Sources/Ledger/PartialTxOut.swift +++ b/Sources/Ledger/PartialTxOut.swift @@ -40,29 +40,34 @@ extension PartialTxOut { publicKey: publicKey) } - init?(_ txOut: FogView_FogTxOut) { - guard let commitment = Data32(txOut.amount.commitment.data), - let targetKey = RistrettoPublic(txOut.targetKey.data), - let publicKey = RistrettoPublic(txOut.publicKey.data) +// init?(_ txOut: FogView_FogTxOut) { +// guard let commitment = Data32(txOut.amount.commitment.data), +// let targetKey = RistrettoPublic(txOut.targetKey.data), +// let publicKey = RistrettoPublic(txOut.publicKey.data) +// else { +// return nil +// } +// self.init( +// commitment: commitment, +// maskedValue: txOut.amount.maskedValue, +// targetKey: targetKey, +// publicKey: publicKey) +// } +// + init?(_ txOutRecord: FogView_TxOutRecord, viewKey: RistrettoPrivate) { +// let commitment = Data32(txOutRecord.txOutAmountCommitmentData) ?? Data32() + guard let targetKey = RistrettoPublic(txOutRecord.txOutTargetKeyData), + let publicKey = RistrettoPublic(txOutRecord.txOutPublicKeyData) else { return nil } - self.init( - commitment: commitment, - maskedValue: txOut.amount.maskedValue, - targetKey: targetKey, - publicKey: publicKey) - } - - init?(_ txOutRecord: FogView_TxOutRecord) { - guard let commitment = Data32(txOutRecord.txOutAmountCommitmentData), - let targetKey = RistrettoPublic(txOutRecord.txOutTargetKeyData), - let publicKey = RistrettoPublic(txOutRecord.txOutPublicKeyData) - else { + + guard let commitment = TxOutUtils.sharedSecret(publicKey: publicKey, viewPrivateKey: viewKey) else { + logger.warning("nil") return nil } self.init( - commitment: commitment, + commitment: commitment.data32, maskedValue: txOutRecord.txOutAmountMaskedValue, targetKey: targetKey, publicKey: publicKey) diff --git a/Sources/Ledger/TxOutProtocol.swift b/Sources/Ledger/TxOutProtocol.swift index e61c2b8b..4fd2f4ed 100644 --- a/Sources/Ledger/TxOutProtocol.swift +++ b/Sources/Ledger/TxOutProtocol.swift @@ -6,7 +6,7 @@ import Foundation import LibMobileCoin protocol TxOutProtocol { - var commitment: Data32 { get } + var commitment: Data32 { get } // Deprecate ?? var maskedValue: UInt64 { get } var targetKey: RistrettoPublic { get } var publicKey: RistrettoPublic { get } @@ -23,7 +23,6 @@ extension TxOutProtocol { func matchesAnySubaddress(accountKey: AccountKey) -> Bool { TxOutUtils.matchesAnySubaddress( - commitment: commitment, maskedValue: maskedValue, publicKey: publicKey, viewPrivateKey: accountKey.viewPrivateKey) @@ -40,7 +39,6 @@ extension TxOutProtocol { /// own `TxOut` or because ` TxOut` values are incongruent. func value(accountKey: AccountKey) -> UInt64? { TxOutUtils.value( - commitment: commitment, maskedValue: maskedValue, publicKey: publicKey, viewPrivateKey: accountKey.viewPrivateKey) @@ -57,16 +55,6 @@ extension TxOutProtocol { } } -extension FogView_FogTxOut { - init(_ txOut: TxOutProtocol) { - self.init() - self.amount = - External_Amount(commitment: txOut.commitment, maskedValue: txOut.maskedValue) - self.targetKey = External_CompressedRistretto(txOut.targetKey) - self.publicKey = External_CompressedRistretto(txOut.publicKey) - } -} - extension FogView_TxOutRecord { init(_ txOut: TxOutProtocol) { self.init() diff --git a/Sources/Ledger/TxOutUtils.swift b/Sources/Ledger/TxOutUtils.swift index 216bbacc..d82e73a0 100644 --- a/Sources/Ledger/TxOutUtils.swift +++ b/Sources/Ledger/TxOutUtils.swift @@ -9,27 +9,24 @@ import LibMobileCoin enum TxOutUtils { static func matchesAnySubaddress( - commitment: Data32, maskedValue: UInt64, publicKey: RistrettoPublic, viewPrivateKey: RistrettoPrivate ) -> Bool { - commitment.asMcBuffer { commitmentPtr in - var mcAmount = McTxOutAmount(commitment: commitmentPtr, masked_value: maskedValue) - return publicKey.asMcBuffer { publicKeyPtr in - viewPrivateKey.asMcBuffer { viewPrivateKeyPtr in - var matches = false - // Safety: mc_tx_out_matches_any_subaddress is infallible when preconditions are - // upheld. - withMcInfallible { - mc_tx_out_matches_any_subaddress( - &mcAmount, - publicKeyPtr, - viewPrivateKeyPtr, - &matches) - } - return matches + var mcAmount = McTxOutAmount(masked_value: maskedValue) + return publicKey.asMcBuffer { publicKeyPtr in + viewPrivateKey.asMcBuffer { viewPrivateKeyPtr in + var matches = false + // Safety: mc_tx_out_matches_any_subaddress is infallible when preconditions are + // upheld. + withMcInfallible { + mc_tx_out_matches_any_subaddress( + &mcAmount, + publicKeyPtr, + viewPrivateKeyPtr, + &matches) } + return matches } } } @@ -62,6 +59,45 @@ enum TxOutUtils { } } + static func sharedSecret( + publicKey: RistrettoPublic, + viewPrivateKey: RistrettoPrivate + ) -> RistrettoPublic? { + publicKey.asMcBuffer { publicKeyBufferPtr in + viewPrivateKey.asMcBuffer { viewPrivateKeyPtr in + switch Data32.make(withMcMutableBuffer: { bufferPtr, errorPtr in + mc_tx_out_shared_secret( + publicKeyBufferPtr, + viewPrivateKeyPtr, + bufferPtr, + &errorPtr) + }) { + case .success(let bytes): + // Safety: It's safe to skip validation because + // mc_tx_out_get_subaddress_spend_public_key should always return a valid + // RistrettoPublic on success. + return RistrettoPublic(skippingValidation: bytes) + case .failure(let error): + switch error.errorCode { + case .invalidInput: + // Safety: This condition indicates a programming error and can only + // happen if arguments to mc_tx_out_get_subaddress_spend_public_key are + // supplied incorrectly. + // FIXME + logger.warning("error: \(redacting: error)") + return nil + default: + // Safety: mc_fog_resolver_add_report_response should not throw + // non-documented errors. + // FIXME + logger.warning("Unhandled LibMobileCoin error: \(redacting: error)") + return nil + } + } + } + } + } + static func subaddressSpentPublicKey( targetKey: RistrettoPublic, publicKey: RistrettoPublic, @@ -104,42 +140,39 @@ enum TxOutUtils { /// - Returns: `nil` when `viewPrivateKey` cannot unmask value, either because `viewPrivateKey` /// does not own `TxOut` or because `TxOut` values are incongruent. static func value( - commitment: Data32, maskedValue: UInt64, publicKey: RistrettoPublic, viewPrivateKey: RistrettoPrivate ) -> UInt64? { - commitment.asMcBuffer { commitmentPtr in - var mcAmount = McTxOutAmount(commitment: commitmentPtr, masked_value: maskedValue) - return publicKey.asMcBuffer { publicKeyPtr in - viewPrivateKey.asMcBuffer { viewKeyBufferPtr in - var valueOut: UInt64 = 0 - switch withMcError({ errorPtr in - mc_tx_out_get_value( - &mcAmount, - publicKeyPtr, - viewKeyBufferPtr, - &valueOut, - &errorPtr) - }) { - case .success: - return valueOut - case .failure(let error): - switch error.errorCode { - case .transactionCrypto: - // Indicates either `commitment`/`maskedValue`/`publicKey` values are - // incongruent or `viewPrivateKey` does not own `TxOut`. However, it's - // not possible to determine which, only that the provided `commitment` - // doesn't match the computed commitment. - return nil - case .invalidInput: - // Safety: This condition indicates a programming error and can only - // happen if arguments to mc_tx_out_get_value are supplied incorrectly. - logger.fatalError("error: \(redacting: error)") - default: - // Safety: mc_tx_out_get_value should not throw non-documented errors. - logger.fatalError("Unhandled LibMobileCoin error: \(redacting: error)") - } + var mcAmount = McTxOutAmount(masked_value: maskedValue) + return publicKey.asMcBuffer { publicKeyPtr in + viewPrivateKey.asMcBuffer { viewKeyBufferPtr in + var valueOut: UInt64 = 0 + switch withMcError({ errorPtr in + mc_tx_out_get_value( + &mcAmount, + publicKeyPtr, + viewKeyBufferPtr, + &valueOut, + &errorPtr) + }) { + case .success: + return valueOut + case .failure(let error): + switch error.errorCode { + case .transactionCrypto: + // Indicates either `commitment`/`maskedValue`/`publicKey` values are + // incongruent or `viewPrivateKey` does not own `TxOut`. However, it's + // not possible to determine which, only that the provided `commitment` + // doesn't match the computed commitment. + return nil + case .invalidInput: + // Safety: This condition indicates a programming error and can only + // happen if arguments to mc_tx_out_get_value are supplied incorrectly. + logger.fatalError("error: \(redacting: error)") + default: + // Safety: mc_tx_out_get_value should not throw non-documented errors. + logger.fatalError("Unhandled LibMobileCoin error: \(redacting: error)") } } } diff --git a/Sources/LibMobileCoin/ProtoExtensions.swift b/Sources/LibMobileCoin/ProtoExtensions.swift index b640ee50..5eeaa2c2 100644 --- a/Sources/LibMobileCoin/ProtoExtensions.swift +++ b/Sources/LibMobileCoin/ProtoExtensions.swift @@ -150,7 +150,7 @@ extension FogLedger_BlockRequest { } } -extension FogLedger_Block { +extension FogLedger_BlockData { var timestampDate: Date { get { Date(timeIntervalSince1970: TimeInterval(timestamp)) } set { timestamp = UInt64(newValue.timeIntervalSince1970) } diff --git a/Sources/Network/Connection/ConnectionSession.swift b/Sources/Network/Connection/ConnectionSession.swift index 8ba2609e..b4bac514 100644 --- a/Sources/Network/Connection/ConnectionSession.swift +++ b/Sources/Network/Connection/ConnectionSession.swift @@ -1,11 +1,13 @@ // // Copyright (c) 2020-2021 MobileCoin. All rights reserved. // +// swiftlint:disable all import Foundation import GRPC import NIOHPACK import NIOHTTP1 +import NIOSSL final class ConnectionSession { private static var ephemeralCookieStorage: HTTPCookieStorage { @@ -115,3 +117,156 @@ extension HPACKHeaders { add(contentsOf: HPACKHeaders(httpHeaders: httpHeaders)) } } + +class ConnectionSessionTrust : NSObject, URLSessionDelegate { + let trustRoots: [NIOSSLCertificate] + let url : URL + + init(url: URL, trustRoots: [NIOSSLCertificate]) { + self.url = url + self.trustRoots = trustRoots + } + + func urlSession(_ session: URLSession, + didReceive challenge: URLAuthenticationChallenge, + completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)) + } + // indicates the server requested a client certificate. +// guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate else { +// logger.info("No cert needed") +// completionHandler(.performDefaultHandling, nil) +// return +// } + +// guard let trust = challenge.protectionSpace.serverTrust else { +// logger.info("no server trust") +// completionHandler(.performDefaultHandling, nil) +// return +// } +// +//// let isServerTrusted = SecTrustEvaluateWithError(serverTrust, nil) +// +// guard let host = url.host else { +// completionHandler(.performDefaultHandling, nil) +// return +// } +// +// +// guard let ourCertData = Data(base64Encoded: String.trustRootsB64) else { //, options: Data.Base64DecodingOptions.ignoreUnknownCharacters) else { +// completionHandler(.performDefaultHandling, nil) +// return +// } +// +// guard let certificate = SecCertificateCreateWithData(nil, ourCertData as CFData) else { +// completionHandler(.performDefaultHandling, nil) +// return +// } +// +//// // use certificate e.g. copy the public key +//// let publicKey = SecCertificateCopyKey(certificate)! +//// +//// guard let publicKeySec = SecKeyCreateWithData(ourCertData as! CFData, attributesRSAPub as CFDictionary, &error) else { +//// completionHandler(.performDefaultHandling, nil) +//// return +//// } +// let policy = SecPolicyCreateSSL(true, (host as CFString)) +// let basicPolicy = SecPolicyCreateBasicX509() +// let manualTrust = UnsafeMutablePointer.allocate(capacity: 1) +// if let serverCertificate = SecTrustGetCertificateAtIndex(trust, 0) { +// let certArray = Array(arrayLiteral:serverCertificate, certificate) +// let status = SecTrustCreateWithCertificates(certArray as AnyObject, policy, manualTrust) +// +// print(serverCertificate) +// print(certificate) +// print(certificate == serverCertificate) +// +// guard status == errSecSuccess else { return } +// +//// let trust = optionalTrust! +// +//// if let pointee = manualTrust.pointee, +//// let key = SecTrustCopyPublicKey(pointee) { +//// trustRoots.compactMap({ root in +//// try? root.extractPublicKey().toSPKIBytes() +//// }).forEach({print($0)}) +//// +//// print(key) +//// if pinnedKeys().contains(serverCertificateKey) { +//// completionHandler(.useCredential, URLCredential(trust: trust)) +//// return +//// } +//// } +// } +//// guard let file = Bundle(for: HTTPAccessURLSessionDelegate.self).url(forResource: p12Filename, withExtension: "p12"), +//// let p12Data = try? Data(contentsOf: file) else { +//// // Loading of the p12 file's data failed. +//// completionHandler(.performDefaultHandling, nil) +//// return +//// } +//// +//// // Interpret the data in the P12 data blob with +//// // a little helper class called `PKCS12`. +//// let password = "MyP12Password" // Obviously this should be stored or entered more securely. +//// let p12Contents = PKCS12(pkcs12Data: p12Data, password: password) +//// guard let identity = p12Contents.identity else { +//// // Creating a PKCS12 never fails, but interpretting th contained data can. So again, no identity? We fall back to default. +//// completionHandler(.performDefaultHandling, nil) +//// return +//// } +// +// // In my case, and as Apple recommends, +// // we do not pass the certificate chain into +// // the URLCredential used to respond to the challenge. +//// let credential = URLCredential(identity: identity, +//// certificates: nil, +//// persistence: .none) +//// challenge.sender?.use(credential, for: challenge) +//// completionHandler(.useCredential, credential) +// } +} + +extension String { + static let trustRootsB64 = + /// MobileCoin-managed Consensus and Fog services use Let's Encrypt with an intermediate + /// certificate that's cross-signed by IdenTrust's "DST Root CA X3": https://crt.sh/?d=8395 + """ + MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQKExtEaWdpdGF\ + sIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDT\ + IxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU\ + 1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxr\ + MMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoO\ + ifooUMM0RoOEqOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK\ + 3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40du\ + tolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB\ + /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqGSIb3DQEBBQUAA4I\ + BAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8fa\ + XbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ip\ + xZzR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wC\ + CZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ + """ +} + + +/* + all our keys are x509 certs + + certs include lots of info AND Public key + + certs have public and private key + + Im CA, gives me his certificate, then as CA I sign it, I hash his certificate and encrypt with my private key of my certificate. + + anyone who can decrypt their cert using the CA public key, and they can compare the hash of the leaf cert with the decrypted has using the CA public key. + + leaf certificate stored on device + + server will send you its certificate, usually sends the whole chain except root which is in the system. + + instead of including leaf cert, we include CA certificate. + + consensus TLS connection + + negotiate encryption key + + */ diff --git a/Sources/Network/Connection/Connections/BlockchainConnection.swift b/Sources/Network/Connection/Connections/BlockchainConnection.swift index f7fcfbf9..b5f3ecee 100644 --- a/Sources/Network/Connection/Connections/BlockchainConnection.swift +++ b/Sources/Network/Connection/Connections/BlockchainConnection.swift @@ -17,6 +17,7 @@ final class BlockchainConnection: init( config: ConnectionConfig, channelManager: GrpcChannelManager, + httpRequester: HttpRequester?, targetQueue: DispatchQueue? ) { self.config = config @@ -33,7 +34,13 @@ final class BlockchainConnection: channelManager: channelManager, targetQueue: targetQueue)) case .http: - return .http(httpService: BlockchainHttpConnection(config: config, targetQueue: targetQueue)) + guard let requester = httpRequester else { + logger.fatalError("Transport Protocol is .http but no HttpRequester provided") + } + return .http(httpService: BlockchainHttpConnection( + config: config, + requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + targetQueue: targetQueue)) } }, transportProtocolOption: config.transportProtocolOption, diff --git a/Sources/Network/Connection/Connections/ConsensusConnection.swift b/Sources/Network/Connection/Connections/ConsensusConnection.swift index bacda281..c59d717d 100644 --- a/Sources/Network/Connection/Connections/ConsensusConnection.swift +++ b/Sources/Network/Connection/Connections/ConsensusConnection.swift @@ -18,6 +18,7 @@ final class ConsensusConnection: init( config: AttestedConnectionConfig, channelManager: GrpcChannelManager, + httpRequester: HttpRequester?, targetQueue: DispatchQueue?, rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil @@ -40,7 +41,15 @@ final class ConsensusConnection: rng: rng, rngContext: rngContext)) case .http: - return .http(httpService: ConsensusHttpConnection()) + guard let requester = httpRequester else { + logger.fatalError("Transport Protocol is .http but no HttpRequester provided") + } + return .http(httpService: ConsensusHttpConnection( + config: config, + requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext)) } }, transportProtocolOption: config.transportProtocolOption, diff --git a/Sources/Network/Connection/Connections/FogBlockConnection.swift b/Sources/Network/Connection/Connections/FogBlockConnection.swift index 88d66316..7fa7d220 100644 --- a/Sources/Network/Connection/Connections/FogBlockConnection.swift +++ b/Sources/Network/Connection/Connections/FogBlockConnection.swift @@ -16,6 +16,7 @@ final class FogBlockConnection: init( config: ConnectionConfig, channelManager: GrpcChannelManager, + httpRequester: HttpRequester?, targetQueue: DispatchQueue? ) { self.config = config @@ -32,7 +33,13 @@ final class FogBlockConnection: channelManager: channelManager, targetQueue: targetQueue)) case .http: - return .http(httpService: FogBlockHttpConnection()) + guard let requester = httpRequester else { + logger.fatalError("Transport Protocol is .http but no HttpRequester provided") + } + return .http(httpService: FogBlockHttpConnection( + config: config, + requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + targetQueue: targetQueue)) } }, transportProtocolOption: config.transportProtocolOption, diff --git a/Sources/Network/Connection/Connections/FogKeyImageConnection.swift b/Sources/Network/Connection/Connections/FogKeyImageConnection.swift index 93f8567a..4b87ab2c 100644 --- a/Sources/Network/Connection/Connections/FogKeyImageConnection.swift +++ b/Sources/Network/Connection/Connections/FogKeyImageConnection.swift @@ -18,6 +18,7 @@ final class FogKeyImageConnection: init( config: AttestedConnectionConfig, channelManager: GrpcChannelManager, + httpRequester: HttpRequester?, targetQueue: DispatchQueue?, rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil @@ -40,7 +41,15 @@ final class FogKeyImageConnection: rng: rng, rngContext: rngContext)) case .http: - return .http(httpService: FogKeyImageHttpConnection()) + guard let requester = httpRequester else { + logger.fatalError("Transport Protocol is .http but no HttpRequester provided") + } + return .http(httpService: FogKeyImageHttpConnection( + config: config, + requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext)) } }, transportProtocolOption: config.transportProtocolOption, diff --git a/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift b/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift index 1ac45250..fd4a16e8 100644 --- a/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift +++ b/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift @@ -18,6 +18,7 @@ final class FogMerkleProofConnection: init( config: AttestedConnectionConfig, channelManager: GrpcChannelManager, + httpRequester: HttpRequester?, targetQueue: DispatchQueue?, rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil @@ -40,7 +41,15 @@ final class FogMerkleProofConnection: rng: rng, rngContext: rngContext)) case .http: - return .http(httpService: FogMerkleProofHttpConnection()) + guard let requester = httpRequester else { + logger.fatalError("Transport Protocol is .http but no HttpRequester provided") + } + return .http(httpService: FogMerkleProofHttpConnection( + config: config, + requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext)) } }, transportProtocolOption: config.transportProtocolOption, diff --git a/Sources/Network/Connection/Connections/FogReportConnection.swift b/Sources/Network/Connection/Connections/FogReportConnection.swift index 51573d9d..f0ae461a 100644 --- a/Sources/Network/Connection/Connections/FogReportConnection.swift +++ b/Sources/Network/Connection/Connections/FogReportConnection.swift @@ -17,6 +17,7 @@ final class FogReportConnection: url: FogUrl, transportProtocolOption: TransportProtocol.Option, channelManager: GrpcChannelManager, + httpRequester: HttpRequester?, targetQueue: DispatchQueue? ) { self.url = url @@ -33,7 +34,13 @@ final class FogReportConnection: channelManager: channelManager, targetQueue: targetQueue)) case .http: - return .http(httpService: FogReportHttpConnection()) + guard let requester = httpRequester else { + logger.fatalError("Transport Protocol is .http but no HttpRequester provided") + } + return .http(httpService: FogReportHttpConnection( + url: url, + requester: RestApiRequester(requester: requester, baseUrl: url.httpBasedUrl), + targetQueue: targetQueue)) } }, transportProtocolOption: transportProtocolOption, diff --git a/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift b/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift index 94048326..1e6b4d5c 100644 --- a/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift +++ b/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift @@ -17,6 +17,7 @@ final class FogUntrustedTxOutConnection: init( config: ConnectionConfig, channelManager: GrpcChannelManager, + httpRequester: HttpRequester?, targetQueue: DispatchQueue? ) { self.config = config @@ -33,7 +34,13 @@ final class FogUntrustedTxOutConnection: channelManager: channelManager, targetQueue: targetQueue)) case .http: - return .http(httpService: FogUntrustedTxOutHttpConnection()) + guard let requester = httpRequester else { + logger.fatalError("Transport Protocol is .http but no HttpRequester provided") + } + return .http(httpService: FogUntrustedTxOutHttpConnection( + config: config, + requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + targetQueue: targetQueue)) } }, transportProtocolOption: config.transportProtocolOption, diff --git a/Sources/Network/Connection/Connections/FogViewConnection.swift b/Sources/Network/Connection/Connections/FogViewConnection.swift index 7a72ca50..5e368626 100644 --- a/Sources/Network/Connection/Connections/FogViewConnection.swift +++ b/Sources/Network/Connection/Connections/FogViewConnection.swift @@ -10,7 +10,7 @@ final class FogViewConnection: Connection, FogViewService { private let config: AttestedConnectionConfig - // private let channelManager: GrpcChannelManager + private let channelManager: GrpcChannelManager private let targetQueue: DispatchQueue? private let rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? private let rngContext: Any? @@ -24,7 +24,7 @@ final class FogViewConnection: rngContext: Any? = nil ) { self.config = config - // self.channelManager = channelManager + self.channelManager = channelManager self.targetQueue = targetQueue self.rng = rng self.rngContext = rngContext @@ -40,13 +40,13 @@ final class FogViewConnection: rng: rng, rngContext: rngContext)) case .http: - let httpClientWrapper = HttpClientWrapper( - config: config, - httpRequester: httpRequester) + guard let requester = httpRequester else { + logger.fatalError("Transport Protocol is .http but no HttpRequester provided") + } return .http( httpService: FogViewHttpConnection( config: config, - client: httpClientWrapper, + requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), targetQueue: targetQueue, rng: rng, rngContext: rngContext)) diff --git a/Sources/Network/HttpConnection/ArbitraryHttpConnection.swift b/Sources/Network/HttpConnection/ArbitraryHttpConnection.swift new file mode 100644 index 00000000..0696937e --- /dev/null +++ b/Sources/Network/HttpConnection/ArbitraryHttpConnection.swift @@ -0,0 +1,79 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + + +class ArbitraryHttpConnection { + private let inner: SerialDispatchLock + + init(url: MobileCoinUrlProtocol, targetQueue: DispatchQueue?) { + let inner = Inner(url: url) + self.inner = .init(inner, targetQueue: targetQueue) + } + + func performCall( + _ call: Call, + request: Call.Request, + completion: @escaping (Result) -> Void + ) { + func performCallCallback(callResult: HttpCallResult) { + inner.accessAsync { + let result = $0.processResponse(callResult: callResult) + switch result { + case .success: + logger.info("Call complete. url: \($0.url)", logFunction: false) + case .failure(let connectionError): + let errorMessage = + "Connection failure. url: \($0.url), error: \(connectionError)" + switch connectionError { + case .connectionFailure, .serverRateLimited: + logger.warning(errorMessage, logFunction: false) + case .authorizationFailure, .invalidServerResponse, + .attestationVerificationFailed, .outdatedClient: + logger.error(errorMessage, logFunction: false) + } + } + completion(result) + } + } + inner.accessAsync { + logger.info("Performing call... url: \($0.url)", logFunction: false) + + let callOptions = $0.requestCallOptions() + call.call(request: request, callOptions: callOptions, completion: performCallCallback) + } + } +} + +extension ArbitraryHttpConnection { + private struct Inner { + let url: MobileCoinUrlProtocol + private let session: ConnectionSession + + init(url: MobileCoinUrlProtocol) { + self.url = url + self.session = ConnectionSession(url: url) + } + + func requestCallOptions() -> HTTPCallOptions { + logger.debug(session.requestHeaders.debugDescription) + return HTTPCallOptions(headers: session.requestHeaders) + } + + func processResponse(callResult: HttpCallResult) + -> Result + { + guard callResult.status.isOk, let response = callResult.response else { + return .failure(.connectionFailure(String(describing: callResult.status))) + } + + if let metadata = callResult.metadata { + session.processResponse(headers: metadata.allHeaderFields) + } + + return .success(response) + } + } +} diff --git a/Sources/Network/HttpConnection/AttestedHttpConnection.swift b/Sources/Network/HttpConnection/AttestedHttpConnection.swift index 48149366..db053a53 100644 --- a/Sources/Network/HttpConnection/AttestedHttpConnection.swift +++ b/Sources/Network/HttpConnection/AttestedHttpConnection.swift @@ -6,7 +6,6 @@ // swiftlint:disable multiline_function_chains operator_usage_whitespace import Foundation -import GRPC import LibMobileCoin import NIO import NIOHPACK @@ -30,16 +29,19 @@ extension AttestedHttpConnectionError: CustomStringConvertible { } class AttestedHttpConnection: ConnectionProtocol { + private let requester: RestApiRequester private let inner: SerialCallbackLock init( client: AttestableHttpClient, + requester: RestApiRequester, config: AttestedConnectionConfigProtocol, targetQueue: DispatchQueue?, rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil ) { - let inner = Inner(client: client, config: config, rng: rng, rngContext: rngContext) + let inner = Inner(client: client, requester: requester, config: config, rng: rng, rngContext: rngContext) + self.requester = requester self.inner = .init(inner, targetQueue: targetQueue) } @@ -112,6 +114,7 @@ extension AttestedHttpConnection { private let url: MobileCoinUrlProtocol private let session: ConnectionSession private let client: AttestableHttpClient + private let requester: RestApiRequester private let attestAke: AttestAke private let responderId: String @@ -121,6 +124,7 @@ extension AttestedHttpConnection { init( client: AttestableHttpClient, + requester: RestApiRequester, config: AttestedConnectionConfigProtocol, rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil @@ -128,6 +132,7 @@ extension AttestedHttpConnection { self.url = config.url self.session = ConnectionSession(config: config) self.client = client + self.requester = requester self.attestAke = AttestAke() self.responderId = config.url.responderId self.attestationVerifier = AttestationVerifier(attestation: config.attestation) @@ -264,7 +269,7 @@ extension AttestedHttpConnection { rngContext: rngContext) doPerformCall( - AuthHttpCallableWrapper(authCallable: client.authCallable), + AuthHttpCallableWrapper(authCallable: client.authCallable, requester: requester), request: request ) { completion( @@ -325,11 +330,17 @@ extension AttestedHttpConnection { request: Call.Request, completion: @escaping (Result) -> Void ) { - call.call(request: request) { + let callOptions = requestCallOptions() + + call.call(request: request, callOptions: callOptions) { completion(self.processResponse(callResult: $0)) } } + private func requestCallOptions() -> HTTPCallOptions { + return HTTPCallOptions(headers: session.requestHeaders) + } + private func processResponse(callResult: HttpCallResult) -> Result { @@ -348,8 +359,8 @@ extension AttestedHttpConnection { .connectionFailure("url: \(url), status: \(callResult.status.code)"))) } - if let initialMetadata = callResult.initialMetadata { - session.processResponse(headers: initialMetadata.allHeaderFields) + if let metadata = callResult.metadata { + session.processResponse(headers: metadata.allHeaderFields) } return .success(response) diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift index c22e95a8..f81326f3 100644 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift @@ -31,7 +31,7 @@ public protocol HTTPClientCall { var options: HTTPCallOptions? { get } /// Initial response metadata. - var initialMetadata: HTTPURLResponse? { get } + var metadata: HTTPURLResponse? { get } /// Status of this call which may be populated by the server or client. /// @@ -49,21 +49,3 @@ public protocol HTTPClientCall { /// succeeded, if not already succeeded). func cancel() } - -//public struct HTTPRestCall : HTTPClientCall { -// -// /// The options used in the URLSession -// public var options: HTTP.CallOptions? -// -// /// Cancel this session if it hasn't already completed. -// public func cancel() { -// -// } -// -// /// The initial metadata returned from the server. -// public var initialMetadata: HTTPURLResponse? -// -// /// The final status of the the session. -// public var status: HTTPStatus? -//} -// diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift index 78bfed93..eae465be 100644 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift @@ -23,7 +23,7 @@ public struct HTTPUnaryCall) -> Void) } +protocol AuthHttpCallee { + func auth( + _ request: Attest_AuthMessage, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall +} + +protocol QueryHttpCallee { + func query( + _ request: Attest_Message, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall +} + +protocol OutputsHttpCallee { + func getOutputs( + _ request: Attest_Message, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall +} + +protocol CheckKeyImagesCallee { + func checkKeyImages( + _ request: Attest_Message, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall +} + struct AuthHttpCallableWrapper: HttpCallable { - typealias Request = Attest_AuthMessage - typealias Response = Attest_AuthMessage - let authCallable: AuthHttpCallable + let requester: RestApiRequester func call( request: Attest_AuthMessage, diff --git a/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift b/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift new file mode 100644 index 00000000..3dca7fd3 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift @@ -0,0 +1,105 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import LibMobileCoin + + +///// A HTTP client. +//public protocol HTTPClient { +// /// The call options to use should the user not provide per-call options. +// var defaultHTTPCallOptions: HTTPCallOptions { get set } +//} +// +//extension HTTPClient { +// public func makeUnaryCall(path: String, request: Request, callOptions: HTTPCallOptions? = nil, responseType: Response.Type = Response.self) -> HTTPUnaryCall where Request : SwiftProtobuf.Message, Response : SwiftProtobuf.Message { +// HTTPUnaryCall(path: path, options: callOptions, requestPayload: request, responseType: responseType) +// } +//} + +//protocol AuthHttpCallableClient: AttestableHttpClient, AuthHttpCallable { +// func auth(_ request: Attest_AuthMessage, callOptions: HTTPCallOptions?) +// -> HTTPUnaryCall +//} +// +//extension AuthHttpCallableClient { +// var authCallable: AuthHttpCallable { +// self +// } +//} +// +//extension AuthHttpCallableClient { +// func auth( +// _ request: Attest_AuthMessage, +// callOptions: HTTPCallOptions?, +// completion: @escaping (HttpCallResult) -> Void +// ) { +// let clientCall = auth(request, callOptions: callOptions) +// requester.makeRequest(call: clientCall) { result in +// switch result { +// case .success(let callResult): +// completion(callResult) +// case .failure(let error): +// logger.error(error.localizedDescription) +// } +// } +// } +//} + +protocol AuthQueryHttpCalleeAndClient : QueryHttpCallee, AuthHttpCallee, HTTPClient {} + +struct AuthHttpCallableClientWrapper: AuthHttpCallableClient, HTTPClient { + public var defaultHTTPCallOptions: HTTPCallOptions { + get { + return client.defaultHTTPCallOptions + } + set { + logger.warning("defaultHTTPOptions set not implemented") + } + } + + let client : WrappedClient + let requester: RestApiRequester + + func auth(_ request: Attest_AuthMessage, callOptions: HTTPCallOptions?) + -> HTTPUnaryCall { + client.auth(request, callOptions: callOptions) + } + + func auth( + _ request: Attest_AuthMessage, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void) { + + let clientCall = auth(request, callOptions: callOptions) + requester.makeRequest(call: clientCall, completion: completion) + } +} + +extension AuthHttpCallableClientWrapper where WrappedClient : QueryHttpCallee { + func query( + _ request: Attest_Message, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall { + client.query(request, callOptions: callOptions) + } +} + +extension AuthHttpCallableClientWrapper where WrappedClient : OutputsHttpCallee { + func getOutputs( + _ request: Attest_Message, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall { + client.getOutputs(request, callOptions: callOptions) + } +} + +extension AuthHttpCallableClientWrapper where WrappedClient : CheckKeyImagesCallee { + func checkKeyImages( + _ request: Attest_Message, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall { + client.checkKeyImages(request, callOptions: callOptions) + } +} diff --git a/Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift b/Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift index 5724011c..b126f5ce 100644 --- a/Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift +++ b/Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift @@ -3,12 +3,13 @@ // import Foundation -import GRPC public protocol HttpCallable { associatedtype Request associatedtype Response + var requester: RestApiRequester { get } + func call( request: Request, callOptions: HTTPCallOptions?, diff --git a/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift b/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift index d38fa4e2..faed6fd5 100644 --- a/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift +++ b/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift @@ -7,8 +7,8 @@ import GRPC import LibMobileCoin protocol AuthHttpCallableClient: AttestableHttpClient, AuthHttpCallable { - func auth(_ request: Attest_AuthMessage, callOptions: CallOptions?) - -> UnaryCall + func auth(_ request: Attest_AuthMessage, callOptions: HTTPCallOptions?) + -> HTTPUnaryCall } extension AuthHttpCallableClient { @@ -20,9 +20,23 @@ extension AuthHttpCallableClient { extension AuthHttpCallableClient { func auth( _ request: Attest_AuthMessage, - callOptions: CallOptions?, - completion: @escaping (UnaryCallResult) -> Void + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void ) { - auth(request, callOptions: callOptions).callResult.whenSuccess(completion) + let clientCall = auth(request, callOptions: callOptions) + requester.makeRequest(call: clientCall, completion: completion) } } + +///// A HTTP client. +//public protocol HTTPClient { +// /// The call options to use should the user not provide per-call options. +// var defaultHTTPCallOptions: HTTPCallOptions { get set } +//} +// +//extension HTTPClient { +// public func makeUnaryCall(path: String, request: Request, callOptions: HTTPCallOptions? = nil, responseType: Response.Type = Response.self) -> HTTPUnaryCall where Request : SwiftProtobuf.Message, Response : SwiftProtobuf.Message { +// HTTPUnaryCall(path: path, options: callOptions, requestPayload: request, responseType: responseType) +// } +//} +// diff --git a/Sources/Network/HttpConnection/HttpClientWrapper.swift b/Sources/Network/HttpConnection/HttpClientWrapper.swift index 2cdc7fa4..63eed695 100644 --- a/Sources/Network/HttpConnection/HttpClientWrapper.swift +++ b/Sources/Network/HttpConnection/HttpClientWrapper.swift @@ -8,49 +8,49 @@ import Foundation import LibMobileCoin import GRPC -final class HttpClientWrapper: AttestableHttpClient { - - private let httpRequester: HttpRequester? - private let headers: [String: String] - private let config: ConnectionConfigProtocol - private let httpMethod = HTTPMethod.POST - var authCallable: AuthHttpCallable { - get { - TestAuthCallable() - } - } - - required init(config: ConnectionConfigProtocol, httpRequester: HttpRequester?) { - self.httpRequester = httpRequester - self.config = config - self.headers = [:] - } - - func request( - body: Data?, - completion: @escaping (Result) -> Void) { - if let requester = httpRequester { - requester.request( - url: config.url.url, - method: httpMethod, - headers: headers, - body: body) { httpResponse in - switch httpResponse { - case .success(let response): - return completion(.success(response.responseData)) - case .failure(let error): - return completion(.failure(error)) - } - } - } else { - return completion( - .failure(InvalidInputError("HttpRequester was not set in the Network config"))) - } - } -} +//final class HttpClientWrapper: AttestableHttpClient { +// +// private let httpRequester: HttpRequester? +// private let headers: [String: String] +// private let config: ConnectionConfigProtocol +// private let httpMethod = HTTPMethod.POST +// var authCallable: AuthHttpCallable { +// get { +// TestAuthCallable() +// } +// } +// +// required init(config: ConnectionConfigProtocol, httpRequester: HttpRequester?) { +// self.httpRequester = httpRequester +// self.config = config +// self.headers = [:] +// } +// +// func request( +// body: Data?, +// completion: @escaping (Result) -> Void) { +// if let requester = httpRequester { +// requester.request( +// url: config.url.url, +// method: httpMethod, +// headers: headers, +// body: body) { httpResponse in +// switch httpResponse { +// case .success(let response): +// return completion(.success(response.responseData)) +// case .failure(let error): +// return completion(.failure(error)) +// } +// } +// } else { +// return completion( +// .failure(InvalidInputError("HttpRequester was not set in the Network config"))) +// } +// } +//} -public struct TestAuthCallable : AuthHttpCallable { - func auth(_ request: Attest_AuthMessage, callOptions: HTTPCallOptions?, completion: @escaping (HttpCallResult) -> Void) { - print("Implement") - } -} +//public struct TestAuthCallable : AuthHttpCallable { +// func auth(_ request: Attest_AuthMessage, callOptions: HTTPCallOptions?, completion: @escaping (HttpCallResult) -> Void) { +// print("Implement") +// } +//} diff --git a/Sources/Network/HttpConnection/HttpConnection.swift b/Sources/Network/HttpConnection/HttpConnection.swift index c91e2402..961234b1 100644 --- a/Sources/Network/HttpConnection/HttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnection.swift @@ -74,13 +74,14 @@ extension HttpConnection { } func requestCallOptions() -> HTTPCallOptions { - HTTPCallOptions(headers: session.requestHeaders) + logger.debug(session.requestHeaders.debugDescription) + return HTTPCallOptions(headers: session.requestHeaders) } func processResponse(callResult: HttpCallResult) -> Result { - guard callResult.status.code != 403 else { + guard [403, 401].contains(callResult.status.code) == false else { return .failure(.authorizationFailure("url: \(url)")) } @@ -88,8 +89,8 @@ extension HttpConnection { return .failure(.connectionFailure("url: \(url), status: \(callResult.status)")) } - if let initialMetadata = callResult.initialMetadata { - session.processResponse(headers: initialMetadata.allHeaderFields) + if let metadata = callResult.metadata { + session.processResponse(headers: metadata.allHeaderFields) } return .success(response) diff --git a/Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift index 38a12565..850b2c00 100644 --- a/Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift @@ -8,14 +8,15 @@ import SwiftProtobuf final class BlockchainHttpConnection: HttpConnection, BlockchainService { private let client: ConsensusCommon_BlockchainAPIRestClient - private let requester: HTTPRequester + private let requester: RestApiRequester init( config: ConnectionConfig, + requester: RestApiRequester, targetQueue: DispatchQueue? ) { self.client = ConsensusCommon_BlockchainAPIRestClient() - self.requester = HTTPRequester(baseUrl: config.url.httpBasedUrl, trustRoots: config.trustRoots) + self.requester = requester super.init(config: config, targetQueue: targetQueue) } @@ -30,7 +31,7 @@ final class BlockchainHttpConnection: HttpConnection, BlockchainService { extension BlockchainHttpConnection { private struct GetLastBlockInfoCall: HttpCallable { let client: ConsensusCommon_BlockchainAPIRestClient - let requester: HTTPRequester + let requester: RestApiRequester func call( request: (), @@ -38,17 +39,7 @@ extension BlockchainHttpConnection { completion: @escaping (HttpCallResult) -> Void ) { let clientCall = client.getLastBlockInfo(Google_Protobuf_Empty()) - requester.makeRequest(call: clientCall) { result in - switch result { - case .success(let callResult): - completion(callResult) - case .failure(let error): - logger.error(error.localizedDescription) - } - } -// let unaryCall = -// client.getLastBlockInfo(Google_Protobuf_Empty(), callOptions: callOptions) -// unaryCall.callResult.whenSuccess(completion) + requester.makeRequest(call: clientCall, completion: completion) } } } diff --git a/Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift index cfe564f5..2ea208a7 100644 --- a/Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift @@ -5,15 +5,58 @@ import Foundation import LibMobileCoin -final class ConsensusHttpConnection: ConnectionProtocol, ConsensusService { +final class ConsensusHttpConnection: AttestedHttpConnection, ConsensusService { + private let client: ConsensusClient_ConsensusClientAPIRestClient + private let requester: RestApiRequester + + init( + config: AttestedConnectionConfig, + requester: RestApiRequester, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + // Solve for shared channel TLS/Certs + self.requester = requester + self.client = ConsensusClient_ConsensusClientAPIRestClient() + super.init( + client: AuthHttpCallableClientWrapper(client: Attest_AttestedApiRestClient(), requester: self.requester), + requester: self.requester, + config: config, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext) + } + func proposeTx( _ tx: External_Tx, completion: @escaping (Result) -> Void ) { - + performAttestedCall( + ProposeTxCall(client: client, requester: requester), + request: tx, + completion: completion) } - - func setAuthorization(credentials: BasicCredentials) { - +} + +extension ConsensusHttpConnection { + private struct ProposeTxCall: AttestedHttpCallable { + typealias InnerRequest = External_Tx + typealias InnerResponse = ConsensusCommon_ProposeTxResponse + + let client: ConsensusClient_ConsensusClientAPIRestClient + let requester: RestApiRequester + + + func call( + request: Attest_Message, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + let clientCall = client.clientTxPropose(request, callOptions: callOptions) + requester.makeRequest(call: clientCall, completion: completion) + } } } + +extension Attest_AttestedApiRestClient: AuthHttpCallee, HTTPClient {} diff --git a/Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift index ec975509..2f04c082 100644 --- a/Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift @@ -1,33 +1,23 @@ // // Copyright (c) 2020-2021 MobileCoin. All rights reserved. // +// swiftlint:disable all import Foundation import LibMobileCoin -//final class FogBlockHttpConnection: ConnectionProtocol, FogBlockService { -// func getBlocks( -// request: FogLedger_BlockRequest, -// completion: @escaping (Result) -> Void -// ) { -// } -// -// func setAuthorization(credentials: BasicCredentials) { -// -// } -//} - final class FogBlockHttpConnection: HttpConnection, FogBlockService { private let client: FogLedger_FogBlockAPIRestClient - private let requester: HTTPRequester + private let requester: RestApiRequester init( config: ConnectionConfig, + requester: RestApiRequester, targetQueue: DispatchQueue? ) { self.client = FogLedger_FogBlockAPIRestClient() - self.requester = HTTPRequester(baseUrl: config.url.httpBasedUrl, trustRoots: config.trustRoots) + self.requester = requester super.init(config: config, targetQueue: targetQueue) } @@ -42,15 +32,15 @@ final class FogBlockHttpConnection: HttpConnection, FogBlockService { extension FogBlockHttpConnection { private struct GetBlocksCall: HttpCallable { let client: FogLedger_FogBlockAPIRestClient - let requester: HTTPRequester + let requester: RestApiRequester func call( request: FogLedger_BlockRequest, callOptions: HTTPCallOptions?, completion: @escaping (HttpCallResult) -> Void ) { - let unaryCall = client.getBlocks(request, callOptions: callOptions) - unaryCall.callResult.whenSuccess(completion) + let clientCall = client.getBlocks(request, callOptions: callOptions) + requester.makeRequest(call: clientCall, completion: completion) } } } diff --git a/Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift index 6f4e55f8..c7125ba6 100644 --- a/Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift @@ -5,14 +5,57 @@ import Foundation import LibMobileCoin -final class FogKeyImageHttpConnection: ConnectionProtocol, FogKeyImageService { + +final class FogKeyImageHttpConnection: AttestedHttpConnection, FogKeyImageService { + private let client: AuthHttpCallableClientWrapper + private let requester : RestApiRequester + + init( + config: AttestedConnectionConfig, + requester: RestApiRequester, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + self.requester = requester + self.client = AuthHttpCallableClientWrapper(client: FogLedger_FogKeyImageAPIRestClient(), requester: self.requester) + super.init( + client: self.client, + requester: self.requester, + config: config, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext) + } + func checkKeyImages( request: FogLedger_CheckKeyImagesRequest, completion: @escaping (Result) -> Void ) { + performAttestedCall( + CheckKeyImagesCall(client: client, requester: self.requester), + request: request, + completion: completion) } - - func setAuthorization(credentials: BasicCredentials) { - +} + +extension FogKeyImageHttpConnection { + private struct CheckKeyImagesCall: AttestedHttpCallable { + typealias InnerRequest = FogLedger_CheckKeyImagesRequest + typealias InnerResponse = FogLedger_CheckKeyImagesResponse + + let client: AuthHttpCallableClientWrapper + let requester: RestApiRequester + + func call( + request: Attest_Message, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + let unaryCall = client.checkKeyImages(request, callOptions: callOptions) + requester.makeRequest(call: unaryCall, completion: completion) + } } } + +extension FogLedger_FogKeyImageAPIRestClient: AuthHttpCallee, CheckKeyImagesCallee, HTTPClient {} diff --git a/Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift index 4e924c55..078f0053 100644 --- a/Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift @@ -5,14 +5,57 @@ import Foundation import LibMobileCoin -final class FogMerkleProofHttpConnection: ConnectionProtocol, FogMerkleProofService { +final class FogMerkleProofHttpConnection: AttestedHttpConnection, FogMerkleProofService { + private let client: AuthHttpCallableClientWrapper + private let requester : RestApiRequester + + init( + config: AttestedConnectionConfig, + requester: RestApiRequester, + targetQueue: DispatchQueue?, + rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, + rngContext: Any? = nil + ) { + self.requester = requester + self.client = AuthHttpCallableClientWrapper(client:FogLedger_FogMerkleProofAPIRestClient(), requester: self.requester) + super.init( + client: self.client, + requester: self.requester, + config: config, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext) + } + func getOutputs( request: FogLedger_GetOutputsRequest, completion: @escaping (Result) -> Void ) { + performAttestedCall( + GetOutputsCall(client: client, requester: self.requester), + request: request, + completion: completion) } - - func setAuthorization(credentials: BasicCredentials) { - +} + +extension FogMerkleProofHttpConnection { + private struct GetOutputsCall: AttestedHttpCallable { + typealias InnerRequest = FogLedger_GetOutputsRequest + typealias InnerResponse = FogLedger_GetOutputsResponse + + let client: AuthHttpCallableClientWrapper + let requester: RestApiRequester + + func call( + request: Attest_Message, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + let unaryCall = client.getOutputs(request, callOptions: callOptions) + requester.makeRequest(call: unaryCall, completion: completion) + } } } + +extension FogLedger_FogMerkleProofAPIRestClient: AuthHttpCallee, OutputsHttpCallee {} + diff --git a/Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift index 67f1799b..0fae3233 100644 --- a/Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift @@ -5,10 +5,36 @@ import Foundation import LibMobileCoin -final class FogReportHttpConnection: FogReportService { +final class FogReportHttpConnection: ArbitraryHttpConnection, FogReportService { + private let client: Report_ReportAPIRestClient + let requester: RestApiRequester + + init(url: FogUrl, requester: RestApiRequester, targetQueue: DispatchQueue?) { + self.client = Report_ReportAPIRestClient() + self.requester = requester + super.init(url: url, targetQueue: targetQueue) + } + func getReports( request: Report_ReportRequest, completion: @escaping (Result) -> Void ) { + performCall(GetReportsCall(client: client, requester: requester), request: request, completion: completion) + } +} + +extension FogReportHttpConnection { + private struct GetReportsCall: HttpCallable { + let client: Report_ReportAPIRestClient + let requester: RestApiRequester + + func call( + request: Report_ReportRequest, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + let unaryCall = client.getReports(request, callOptions: callOptions) + requester.makeRequest(call: unaryCall, completion: completion) + } } } diff --git a/Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift index 5cbfa0a1..7cffd594 100644 --- a/Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift @@ -5,14 +5,40 @@ import Foundation import LibMobileCoin -final class FogUntrustedTxOutHttpConnection: ConnectionProtocol, FogUntrustedTxOutService { +final class FogUntrustedTxOutHttpConnection: HttpConnection, FogUntrustedTxOutService { + private let client: FogLedger_FogUntrustedTxOutApiRestClient + private let requester : RestApiRequester + + init( + config: ConnectionConfig, + requester: RestApiRequester, + targetQueue: DispatchQueue? + ) { + self.client = FogLedger_FogUntrustedTxOutApiRestClient() + self.requester = requester + super.init(config: config, targetQueue: targetQueue) + } + func getTxOuts( request: FogLedger_TxOutRequest, completion: @escaping (Result) -> Void ) { + performCall(GetTxOutsCall(client: client, requester: self.requester), request: request, completion: completion) } - - func setAuthorization(credentials: BasicCredentials) { - +} + +extension FogUntrustedTxOutHttpConnection { + private struct GetTxOutsCall: HttpCallable { + let client: FogLedger_FogUntrustedTxOutApiRestClient + let requester: RestApiRequester + + func call( + request: FogLedger_TxOutRequest, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + let unaryCall = client.getTxOuts(request, callOptions: callOptions) + requester.makeRequest(call: unaryCall, completion: completion) + } } } diff --git a/Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift b/Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift index da8dde29..abb0162e 100644 --- a/Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift +++ b/Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift @@ -6,23 +6,58 @@ import Foundation import LibMobileCoin final class FogViewHttpConnection: AttestedHttpConnection, FogViewService { - + private let client: AuthHttpCallableClientWrapper + private let requester : RestApiRequester + init( config: AttestedConnectionConfig, - client: HttpClientWrapper, + requester: RestApiRequester, targetQueue: DispatchQueue?, rng: (@convention(c) (UnsafeMutableRawPointer?) -> UInt64)? = securityRNG, rngContext: Any? = nil ) { - super.init(client: client, config: config, targetQueue: targetQueue) + self.requester = requester + self.client = AuthHttpCallableClientWrapper(client: FogView_FogViewAPIRestClient(), requester: self.requester) + super.init( + client: self.client, + requester: self.requester, + config: config, + targetQueue: targetQueue, + rng: rng, + rngContext: rngContext) } - + func query( requestAad: FogView_QueryRequestAAD, request: FogView_QueryRequest, completion: @escaping (Result) -> Void ) { - + performAttestedCall( + EnclaveRequestCall(client: client, requester:requester), + requestAad: requestAad, + request: request, + completion: completion) } +} + +extension FogViewHttpConnection { + private struct EnclaveRequestCall: AttestedHttpCallable { + typealias InnerRequestAad = FogView_QueryRequestAAD + typealias InnerRequest = FogView_QueryRequest + typealias InnerResponse = FogView_QueryResponse + let client: AuthHttpCallableClientWrapper + let requester: RestApiRequester + + func call( + request: Attest_Message, + callOptions: HTTPCallOptions?, + completion: @escaping (HttpCallResult) -> Void + ) { + let clientCall = client.query(request, callOptions: callOptions) + requester.makeRequest(call: clientCall, completion: completion) + } + } } + +extension FogView_FogViewAPIRestClient: AuthHttpCallee, QueryHttpCallee, HTTPClient {} diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/attest.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/attest.http.swift new file mode 100644 index 00000000..ca089743 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/attest.http.swift @@ -0,0 +1,90 @@ +// +// DO NOT EDIT. +// +// Generated by the protocol buffer compiler. +// Source: attest.proto +// +// swiftlint:disable all + +// +// Copyright 2018, gRPC Authors All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +import NIO +import SwiftProtobuf +import LibMobileCoin + + +//// A server-authenticated service for SGX enclaves. The responder is the +//// attesting enclave, and the client is unauthenticated. When described +//// within the noise protocol, this is similar to the "IX" style key exchange: +//// +//// ```txt +//// IX: +//// -> e, s +//// <- e, ee, se, s, es +//// -> +//// <- +//// ``` +//// +//// The first two messages are contained within the Auth and AuthResponse +/// +/// Usage: instantiate `Attest_AttestedApiRestClient`, then call methods of this protocol to make API calls. +public protocol Attest_AttestedApiRestClientProtocol: HTTPClient { + var serviceName: String { get } + + func auth( + _ request: Attest_AuthMessage, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall +} + +extension Attest_AttestedApiRestClientProtocol { + public var serviceName: String { + return "attest.AttestedApi" + } + + //// This API call is made when one enclave wants to start a mutually- + //// authenticated key-exchange session with an enclave. + /// + /// - Parameters: + /// - request: Request to send to Auth. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func auth( + _ request: Attest_AuthMessage, + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { + return self.makeUnaryCall( + path: "/attest.AttestedApi/Auth", + request: request, + callOptions: callOptions ?? self.defaultHTTPCallOptions + ) + } +} + +public final class Attest_AttestedApiRestClient: Attest_AttestedApiRestClientProtocol { + public var defaultHTTPCallOptions: HTTPCallOptions + + /// Creates a client for the attest.AttestedApi service. + /// + /// - Parameters: + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. + public init( + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() + ) { + self.defaultHTTPCallOptions = defaultHTTPCallOptions + } +} + diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift index 389d6f75..2a178216 100644 --- a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift @@ -1,6 +1,7 @@ // // Copyright (c) 2020-2021 MobileCoin. All rights reserved. // +// swiftlint:disable all import Foundation import SwiftProtobuf @@ -18,7 +19,7 @@ public protocol ConsensusClient_ConsensusClientAPIRestClientProtocol: HTTPClient extension ConsensusClient_ConsensusClientAPIRestClientProtocol { public var serviceName: String { - return "consensus_client.ConsensusClientAPIRest" + return "consensus_client.ConsensusClientAPI" } //// This APIRest call is made with an encrypted payload for the enclave, @@ -33,7 +34,7 @@ extension ConsensusClient_ConsensusClientAPIRestClientProtocol { callOptions: HTTPCallOptions? = nil ) -> HTTPUnaryCall { return self.makeUnaryCall( - path: "/consensus_client.ConsensusClientAPIRest/ClientTxPropose", + path: "/consensus_client.ConsensusClientAPI/ClientTxPropose", request: request, callOptions: callOptions ?? self.defaultHTTPCallOptions ) diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift index 9f1b81c0..57001256 100644 --- a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift @@ -28,7 +28,7 @@ public protocol ConsensusCommon_BlockchainAPIRestClientProtocol: HTTPClient { extension ConsensusCommon_BlockchainAPIRestClientProtocol { public var serviceName: String { - return "consensus_common.BlockchainAPIRest" + return "consensus_common.BlockchainAPI" } /// Unary call to GetLastBlockInfo @@ -42,7 +42,7 @@ extension ConsensusCommon_BlockchainAPIRestClientProtocol { callOptions: HTTPCallOptions? = nil ) ->HTTPUnaryCall { return self.makeUnaryCall( - path: "/consensus_common.BlockchainAPIRest/GetLastBlockInfo", + path: "/consensus_common.BlockchainAPI/GetLastBlockInfo", request: request, callOptions: callOptions ?? self.defaultHTTPCallOptions ) @@ -59,7 +59,7 @@ extension ConsensusCommon_BlockchainAPIRestClientProtocol { callOptions: HTTPCallOptions? = nil ) ->HTTPUnaryCall { return self.makeUnaryCall( - path: "/consensus_common.BlockchainAPIRest/GetBlocks", + path: "/consensus_common.BlockchainAPI/GetBlocks", request: request, callOptions: callOptions ?? self.defaultHTTPCallOptions ) diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift index 22c136ea..609458ba 100644 --- a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift @@ -4,6 +4,7 @@ // Generated by the protocol buffer compiler. // Source: ledger.proto // +// swiftlint:disable all // // Copyright 2018, gRPC Authors All rights reserved. @@ -20,14 +21,12 @@ // See the License for the specific language governing permissions and // limitations under the License. // -import GRPC -import NIO import SwiftProtobuf import LibMobileCoin -/// Usage: instantiate `FogLedger_FogMerkleProofAPI`, then call methods of this protocol to make API calls. -public protocol FogLedger_FogMerkleProofAPIRestProtocol: HTTPClient { +/// Usage: instantiate `FogLedger_FogMerkleProofAPIRestClient`, then call methods of this protocol to make API calls. +public protocol FogLedger_FogMerkleProofAPIRestClientProtocol: HTTPClient { var serviceName: String { get } func auth( @@ -41,7 +40,7 @@ public protocol FogLedger_FogMerkleProofAPIRestProtocol: HTTPClient { ) -> HTTPUnaryCall } -extension FogLedger_FogMerkleProofAPIRestProtocol { +extension FogLedger_FogMerkleProofAPIRestClientProtocol { public var serviceName: String { return "fog_ledger.FogMerkleProofAPI" } @@ -84,35 +83,22 @@ extension FogLedger_FogMerkleProofAPIRestProtocol { } } -public protocol FogLedger_FogMerkleProofAPIInterceptorFactoryProtocol { - - /// - Returns: Interceptors to use when invoking 'auth'. - func makeAuthInterceptors() -> [ClientInterceptor] - - /// - Returns: Interceptors to use when invoking 'getOutputs'. - func makeGetOutputsInterceptors() -> [ClientInterceptor] -} - -public final class FogLedger_FogMerkleProofAPI: FogLedger_FogMerkleProofAPIRestProtocol { - public let channel: GRPCChannel +public final class FogLedger_FogMerkleProofAPIRestClient: FogLedger_FogMerkleProofAPIRestClientProtocol { public var defaultHTTPCallOptions: HTTPCallOptions /// Creates a client for the fog_ledger.FogMerkleProofAPI service. /// /// - Parameters: - /// - channel: `GRPCChannel` to the service host. /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. public init( - channel: GRPCChannel, defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { - self.channel = channel self.defaultHTTPCallOptions = defaultHTTPCallOptions } } -/// Usage: instantiate `FogLedger_FogKeyImageAPI`, then call methods of this protocol to make API calls. -public protocol FogLedger_FogKeyImageAPIRestProtocol: HTTPClient { +/// Usage: instantiate `FogLedger_FogKeyImageAPIRestClient`, then call methods of this protocol to make API calls. +public protocol FogLedger_FogKeyImageAPIRestClientProtocol: HTTPClient { var serviceName: String { get } func auth( @@ -126,7 +112,7 @@ public protocol FogLedger_FogKeyImageAPIRestProtocol: HTTPClient { ) -> HTTPUnaryCall } -extension FogLedger_FogKeyImageAPIRestProtocol { +extension FogLedger_FogKeyImageAPIRestClientProtocol { public var serviceName: String { return "fog_ledger.FogKeyImageAPI" } @@ -166,35 +152,22 @@ extension FogLedger_FogKeyImageAPIRestProtocol { } } -public protocol FogLedger_FogKeyImageAPIInterceptorFactoryProtocol { - - /// - Returns: Interceptors to use when invoking 'auth'. - func makeAuthInterceptors() -> [ClientInterceptor] - - /// - Returns: Interceptors to use when invoking 'checkKeyImages'. - func makeCheckKeyImagesInterceptors() -> [ClientInterceptor] -} - -public final class FogLedger_FogKeyImageAPI: FogLedger_FogKeyImageAPIRestProtocol { - public let channel: GRPCChannel +public final class FogLedger_FogKeyImageAPIRestClient: FogLedger_FogKeyImageAPIRestClientProtocol { public var defaultHTTPCallOptions: HTTPCallOptions /// Creates a client for the fog_ledger.FogKeyImageAPI service. /// /// - Parameters: - /// - channel: `GRPCChannel` to the service host. /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. public init( - channel: GRPCChannel, defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { - self.channel = channel self.defaultHTTPCallOptions = defaultHTTPCallOptions } } -/// Usage: instantiate `FogLedger_FogBlockAPI`, then call methods of this protocol to make API calls. -public protocol FogLedger_FogBlockAPIRestProtocol: HTTPClient { +/// Usage: instantiate `FogLedger_FogBlockAPIRestClient`, then call methods of this protocol to make API calls. +public protocol FogLedger_FogBlockAPIRestClientProtocol: HTTPClient { var serviceName: String { get } func getBlocks( @@ -203,7 +176,7 @@ public protocol FogLedger_FogBlockAPIRestProtocol: HTTPClient { ) -> HTTPUnaryCall } -extension FogLedger_FogBlockAPIRestProtocol { +extension FogLedger_FogBlockAPIRestClientProtocol { public var serviceName: String { return "fog_ledger.FogBlockAPI" } @@ -228,32 +201,22 @@ extension FogLedger_FogBlockAPIRestProtocol { } } -public protocol FogLedger_FogBlockAPIInterceptorFactoryProtocol { - - /// - Returns: Interceptors to use when invoking 'getBlocks'. - func makeGetBlocksInterceptors() -> [ClientInterceptor] -} - -public final class FogLedger_FogBlockAPI: FogLedger_FogBlockAPIRestProtocol { - public let channel: GRPCChannel +public final class FogLedger_FogBlockAPIRestClient: FogLedger_FogBlockAPIRestClientProtocol { public var defaultHTTPCallOptions: HTTPCallOptions /// Creates a client for the fog_ledger.FogBlockAPI service. /// /// - Parameters: - /// - channel: `GRPCChannel` to the service host. /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. public init( - channel: GRPCChannel, defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { - self.channel = channel self.defaultHTTPCallOptions = defaultHTTPCallOptions } } -/// Usage: instantiate `FogLedger_FogUntrustedTxOutApiClient`, then call methods of this protocol to make API calls. -public protocol FogLedger_FogUntrustedTxOutApiClientProtocol: HTTPClient { +/// Usage: instantiate `FogLedger_FogUntrustedTxOutApiRestClient`, then call methods of this protocol to make API calls. +public protocol FogLedger_FogUntrustedTxOutApiRestClientProtocol: HTTPClient { var serviceName: String { get } func getTxOuts( @@ -262,7 +225,7 @@ public protocol FogLedger_FogUntrustedTxOutApiClientProtocol: HTTPClient { ) -> HTTPUnaryCall } -extension FogLedger_FogUntrustedTxOutApiClientProtocol { +extension FogLedger_FogUntrustedTxOutApiRestClientProtocol { public var serviceName: String { return "fog_ledger.FogUntrustedTxOutApi" } @@ -298,27 +261,16 @@ extension FogLedger_FogUntrustedTxOutApiClientProtocol { } } -public protocol FogLedger_FogUntrustedTxOutApiClientInterceptorFactoryProtocol { - - /// - Returns: Interceptors to use when invoking 'getTxOuts'. - func makeGetTxOutsInterceptors() -> [ClientInterceptor] -} - -public final class FogLedger_FogUntrustedTxOutApiClient: FogLedger_FogUntrustedTxOutApiClientProtocol { - public let channel: GRPCChannel +public final class FogLedger_FogUntrustedTxOutApiRestClient: FogLedger_FogUntrustedTxOutApiRestClientProtocol { public var defaultHTTPCallOptions: HTTPCallOptions /// Creates a client for the fog_ledger.FogUntrustedTxOutApi service. /// /// - Parameters: - /// - channel: `GRPCChannel` to the service host. /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. public init( - channel: GRPCChannel, defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() ) { - self.channel = channel self.defaultHTTPCallOptions = defaultHTTPCallOptions } } - diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/report.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/report.http.swift new file mode 100644 index 00000000..7d715ded --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/report.http.swift @@ -0,0 +1,78 @@ +// +// DO NOT EDIT. +// +// Generated by the protocol buffer compiler. +// Source: report.proto +// +// swiftlint:disable all + +// +// Copyright 2018, gRPC Authors All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +import NIO +import SwiftProtobuf +import LibMobileCoin + + +//// The public API for getting reports +/// +/// Usage: instantiate `Report_ReportAPIRestClient`, then call methods of this protocol to make API calls. +public protocol Report_ReportAPIRestClientProtocol: HTTPClient { + var serviceName: String { get } + + func getReports( + _ request: Report_ReportRequest, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall +} + +extension Report_ReportAPIRestClientProtocol { + public var serviceName: String { + return "report.ReportAPI" + } + + //// Get all available pubkeys, with Intel SGX reports, fog urls, and expiry info + /// + /// - Parameters: + /// - request: Request to send to GetReports. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func getReports( + _ request: Report_ReportRequest, + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { + return self.makeUnaryCall( + path: "/report.ReportAPI/GetReports", + request: request, + callOptions: callOptions ?? self.defaultHTTPCallOptions + ) + } +} + +public final class Report_ReportAPIRestClient: Report_ReportAPIRestClientProtocol { + public var defaultHTTPCallOptions: HTTPCallOptions + + /// Creates a client for the report.ReportAPI service. + /// + /// - Parameters: + /// - channel: `GRPCChannel` to the service host. + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. + public init( + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() + ) { + self.defaultHTTPCallOptions = defaultHTTPCallOptions + } +} + diff --git a/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/view.http.swift b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/view.http.swift new file mode 100644 index 00000000..2d52aed7 --- /dev/null +++ b/Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/view.http.swift @@ -0,0 +1,96 @@ +// +// DO NOT EDIT. +// +// Generated by the protocol buffer compiler. +// Source: view.proto +// +// swiftlint:disable all + +// +// Copyright 2018, gRPC Authors All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +import SwiftProtobuf +import LibMobileCoin + + +/// Usage: instantiate `FogView_FogViewAPIRestClient`, then call methods of this protocol to make API calls. +public protocol FogView_FogViewAPIRestClientProtocol: HTTPClient { + var serviceName: String { get } + + func auth( + _ request: Attest_AuthMessage, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall + + func query( + _ request: Attest_Message, + callOptions: HTTPCallOptions? + ) -> HTTPUnaryCall +} + +extension FogView_FogViewAPIRestClientProtocol { + public var serviceName: String { + return "fog_view.FogViewAPI" + } + + //// This is called to perform IX key exchange with the enclave before calling GetOutputs. + /// + /// - Parameters: + /// - request: Request to send to Auth. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func auth( + _ request: Attest_AuthMessage, + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { + return self.makeUnaryCall( + path: "/fog_view.FogViewAPI/Auth", + request: request, + callOptions: callOptions ?? self.defaultHTTPCallOptions + ) + } + + //// Input should be an encrypted QueryRequest, result is an encrypted QueryResponse + /// + /// - Parameters: + /// - request: Request to send to Query. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func query( + _ request: Attest_Message, + callOptions: HTTPCallOptions? = nil + ) -> HTTPUnaryCall { + return self.makeUnaryCall( + path: "/fog_view.FogViewAPI/Query", + request: request, + callOptions: callOptions ?? self.defaultHTTPCallOptions + ) + } +} + +public final class FogView_FogViewAPIRestClient: FogView_FogViewAPIRestClientProtocol { + public var defaultHTTPCallOptions: HTTPCallOptions + + /// Creates a client for the fog_view.FogViewAPI service. + /// + /// - Parameters: + /// - defaultHTTPCallOptions: Options to use for each service call if the user doesn't provide them. + public init( + defaultHTTPCallOptions: HTTPCallOptions = HTTPCallOptions() + ) { + self.defaultHTTPCallOptions = defaultHTTPCallOptions + } +} + diff --git a/Sources/Network/HttpConnection/HttpRequester.swift b/Sources/Network/HttpConnection/HttpRequester.swift index 5555c587..72fbacfb 100644 --- a/Sources/Network/HttpConnection/HttpRequester.swift +++ b/Sources/Network/HttpConnection/HttpRequester.swift @@ -14,7 +14,7 @@ public protocol HttpRequester { method: HTTPMethod, headers: [String: String]?, body: Data?, - completion: @escaping (HTTPResult) -> Void) + completion: @escaping (Result) -> Void) } public enum HTTPMethod : String { @@ -39,99 +39,86 @@ public struct HTTPResponse { } } -public enum HTTPResult { - case success(response: HTTPResponse) - case failure(error: Error) -} - // - Add relative path component toe NetworkedMessage and then combine at runtime. -public class HTTPRequester { - public static let defaultConfiguration : URLSessionConfiguration = { - let config = URLSessionConfiguration.default - config.timeoutIntervalForRequest = 30 - config.timeoutIntervalForResource = 30 - return config - }() - - let configuration : URLSessionConfiguration +public class RestApiRequester { + let requester: HttpRequester let baseUrl: URL let trustRoots: [NIOSSLCertificate]? let prefix: String = "gw" + var challengeDelegate: URLSessionDelegate? - public init(baseUrl: URL, trustRoots: [NIOSSLCertificate]?, configuration: URLSessionConfiguration = HTTPRequester.defaultConfiguration) { - self.configuration = configuration + public init(requester: HttpRequester, baseUrl: URL, trustRoots: [NIOSSLCertificate]? = []) { + self.requester = requester self.baseUrl = baseUrl self.trustRoots = trustRoots + self.challengeDelegate = ConnectionSessionTrust(url: baseUrl, trustRoots: trustRoots ?? []) } } public protocol Requester { -// func makeRequest(call: T, completion: @escaping (Result) -> Void) - func makeRequest(call: T, completion: @escaping (Result, Error>) -> Void) + func makeRequest(call: T, completion: @escaping (HttpCallResult) -> Void) } -extension HTTPRequester : Requester { - private func completeURLFromPath(_ path: String) -> URL? { - URL(string: path, relativeTo: URL(string: prefix, relativeTo: baseUrl)) +extension RestApiRequester : Requester { + private func completeURL(path: String) -> URL? { + .prefix(baseUrl, pathComponents:[prefix, path]) } -// public func makeRequest(call: T, completion: @escaping (Result, Error>) -> Void) { - public func makeRequest(call: T, completion: @escaping (Result, Error>) -> Void) { - let session = URLSession(configuration: configuration) - - guard let url = completeURLFromPath(call.path) else { - completion(.failure(InvalidInputError("Invalid URL"))) + public func makeRequest(call: T, completion: @escaping (HttpCallResult) -> Void) { + guard let url = completeURL(path: call.path) else { + completion(HttpCallResult(status: HTTPStatus(code: 1, message: "could not construct URL"))) return } - - var request = URLRequest(url: url) - request.httpMethod = call.method.rawValue + + var request = URLRequest(url: url.absoluteURL) request.addProtoHeaders() + request.addHeaders(call.options?.headers ?? [:]) do { - request.httpBody = try call.requestPayload?.serializedData() ?? Google_Protobuf_Empty().serializedData() - logger.debug("MC HTTP Request: \(call.requestPayload?.prettyPrintJSON() ?? "")") + request.httpBody = try call.requestPayload?.serializedData() } catch let error { - logger.debug(error.localizedDescription) + completion(HttpCallResult(status: HTTPStatus(code: 1, message: error.localizedDescription))) } - session.dataTask(with: request) { data, response, error in - if let error = error { - completion(.failure(error)) - return - } - - guard let response = response as? HTTPURLResponse else { - completion(.failure(NetworkingError.noResponse)) - return - } - - guard (200...299).contains(response.statusCode) else { - completion(.failure(HTTPResponseStatusCodeError(response.statusCode))) - return - } - - guard let data = data else { - completion(.failure(NetworkingError.noData)) - return - } - - do { - let responsePayload = try T.ResponsePayload.init(serializedData: data) - logger.debug("Resposne Proto as JSON: \((try? responsePayload.jsonString()) ?? "Unable to print JSON")") + requester.request(url: url, method: call.method, headers: request.allHTTPHeaderFields, body: request.httpBody) { result in + switch result { + case .failure(let error): + completion(HttpCallResult(status: HTTPStatus(code: 1, message: error.localizedDescription))) + case .success(let httpResponse): + let response = httpResponse.httpUrlResponse + + logger.info("Http Request url: \(url)") + logger.info("Status code: \(response.statusCode)") - // let result = HttpCallResult(status: HTTPStatus(code: response.statusCode, message: ""), initialMetadata: response, response: responsePayload) - let result = HttpCallResult(status: HTTPStatus(code: response.statusCode, message: ""), initialMetadata: response, response: responsePayload) - completion(.success(result)) - } catch { - completion(.failure(error)) + let responsePayload : T.ResponsePayload? = { + guard let data = httpResponse.responseData, + let responsePayload = try? T.ResponsePayload.init(serializedData: data) + else { + return nil + } + return responsePayload + }() + + let result = HttpCallResult(status: HTTPStatus(code: response.statusCode, message: ""), metadata: response, response: responsePayload) + completion(result) } - }.resume() + } } } +fileprivate extension URL { + static func prefix(_ url: URL, pathComponents: [String]) -> URL? { + let prunedComponents = pathComponents.map({ $0.hasPrefix("/") ? String($0.dropFirst()) : $0}) + var components = URLComponents() + components.scheme = url.scheme + components.host = url.host + components.path = "/" + (url.pathComponents + prunedComponents).joined(separator: "/") + return components.url + } +} + fileprivate extension URLRequest { mutating func addProtoHeaders() { let contentType = HTTPHeadersConstants.CONTENT_TYPE_PROTOBUF @@ -140,6 +127,12 @@ fileprivate extension URLRequest { let accept = HTTPHeadersConstants.ACCEPT_PROTOBUF self.addValue(accept.value, forHTTPHeaderField: accept.fieldName) } + + mutating func addHeaders(_ headers: [String:String]) { + headers.forEach { headerFieldName, value in + self.setValue(value, forHTTPHeaderField: headerFieldName) + } + } } struct HTTPHeadersConstants { @@ -163,6 +156,7 @@ public enum HTTPResponseStatusCodeError : Error { case unauthorized case badRequest case forbidden + case notFound case unprocessableEntity case internalServerError case invalidResponseFromExternal @@ -174,6 +168,7 @@ public enum HTTPResponseStatusCodeError : Error { case 400: self = .badRequest case 401: self = .unauthorized case 403: self = .forbidden + case 404: self = .notFound case 422: self = .unprocessableEntity case 500: self = .internalServerError case 502: self = .invalidResponseFromExternal @@ -186,6 +181,7 @@ public enum HTTPResponseStatusCodeError : Error { case .badRequest: return 400 case .unauthorized: return 401 case .forbidden: return 403 + case .notFound: return 404 case .unprocessableEntity: return 422 case .internalServerError: return 500 case .invalidResponseFromExternal: return 502 @@ -195,11 +191,16 @@ public enum HTTPResponseStatusCodeError : Error { } extension HTTPResponseStatusCodeError : CustomStringConvertible { + public var localizedDescription: String { + return description + } + public var description: String { switch self { case .badRequest: return "The request is malformed (ex. missing or incorrect parameters)" case .unauthorized: return "Failed to provide proper authentication with the request." case .forbidden: return "The action in the request is not allowed." + case .notFound: return "Not Found" case .unprocessableEntity: return "The server understands the content type of the request entity, and the syntax of the request entity is correct, but it was unable to process the contained instructions." case .internalServerError: return "Unhandled exception from one of the other services: the Database, FTX, or the Full Service Wallet." case .invalidResponseFromExternal: return "The server was acting as a gateway or proxy and received an invalid response from the upstream server (ie. one of the other services: the Database, FTX, or the Full Service Wallet.)" @@ -238,3 +239,41 @@ extension NetworkingError: CustomStringConvertible { } } } + +//public class MyURLSessionDelegate: NSObject, URLSessionDelegate { +// public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { +// // `NSURLAuthenticationMethodClientCertificate` +// // indicates the server requested a client certificate. +// if challenge.protectionSpace.authenticationMethod +// != NSURLAuthenticationMethodClientCertificate { +// completionHandler(.performDefaultHandling, nil) +// return +// } +// +// guard let file = Bundle(for: HTTPAccessURLSessionDelegate.self).url(forResource: p12Filename, withExtension: "p12"), +// let p12Data = try? Data(contentsOf: file) else { +// // Loading of the p12 file's data failed. +// completionHandler(.performDefaultHandling, nil) +// return +// } +// +// // Interpret the data in the P12 data blob with +// // a little helper class called `PKCS12`. +// let password = "MyP12Password" // Obviously this should be stored or entered more securely. +// let p12Contents = PKCS12(pkcs12Data: p12Data, password: password) +// guard let identity = p12Contents.identity else { +// // Creating a PKCS12 never fails, but interpretting th contained data can. So again, no identity? We fall back to default. +// completionHandler(.performDefaultHandling, nil) +// return +// } +// +// // In my case, and as Apple recommends, +// // we do not pass the certificate chain into +// // the URLCredential used to respond to the challenge. +// let credential = URLCredential(identity: identity, +// certificates: nil, +// persistence: .none) +// challenge.sender?.use(credential, for: challenge) +// completionHandler(.useCredential, credential) +// } +//} diff --git a/Sources/Network/NetworkConfig.swift b/Sources/Network/NetworkConfig.swift index 7bdd74ed..47a3a686 100644 --- a/Sources/Network/NetworkConfig.swift +++ b/Sources/Network/NetworkConfig.swift @@ -21,7 +21,7 @@ struct NetworkConfig { private let attestation: AttestationConfig - var transportProtocol: TransportProtocol = .grpc + var transportProtocol: TransportProtocol = .http var consensusTrustRoots: [NIOSSLCertificate]? var fogTrustRoots: [NIOSSLCertificate]? @@ -30,7 +30,7 @@ struct NetworkConfig { var fogUserAuthorization: BasicCredentials? var httpRequester: HttpRequester? - + init(consensusUrl: ConsensusUrl, fogUrl: FogUrl, attestation: AttestationConfig) { self.consensusUrl = consensusUrl self.fogUrl = fogUrl diff --git a/Sources/Network/Service/DefaultServiceProvider.swift b/Sources/Network/Service/DefaultServiceProvider.swift index 0b3295a7..b925a993 100644 --- a/Sources/Network/Service/DefaultServiceProvider.swift +++ b/Sources/Network/Service/DefaultServiceProvider.swift @@ -18,16 +18,18 @@ final class DefaultServiceProvider: ServiceProvider { init(networkConfig: NetworkConfig, targetQueue: DispatchQueue?) { let channelManager = GrpcChannelManager() - let inner = Inner(channelManager: channelManager, targetQueue: targetQueue) + let inner = Inner(channelManager: channelManager, httpRequester: networkConfig.httpRequester, targetQueue: targetQueue) self.inner = .init(inner, targetQueue: targetQueue) self.consensus = ConsensusConnection( config: networkConfig.consensus, channelManager: channelManager, + httpRequester: networkConfig.httpRequester, targetQueue: targetQueue) self.blockchain = BlockchainConnection( config: networkConfig.blockchain, channelManager: channelManager, + httpRequester: networkConfig.httpRequester, targetQueue: targetQueue) self.view = FogViewConnection( config: networkConfig.fogView, @@ -37,18 +39,22 @@ final class DefaultServiceProvider: ServiceProvider { self.merkleProof = FogMerkleProofConnection( config: networkConfig.fogMerkleProof, channelManager: channelManager, + httpRequester: networkConfig.httpRequester, targetQueue: targetQueue) self.keyImage = FogKeyImageConnection( config: networkConfig.fogKeyImage, channelManager: channelManager, + httpRequester: networkConfig.httpRequester, targetQueue: targetQueue) self.block = FogBlockConnection( config: networkConfig.fogBlock, channelManager: channelManager, + httpRequester: networkConfig.httpRequester, targetQueue: targetQueue) self.untrustedTxOut = FogUntrustedTxOutConnection( config: networkConfig.fogUntrustedTxOut, channelManager: channelManager, + httpRequester: networkConfig.httpRequester, targetQueue: targetQueue) } @@ -94,16 +100,19 @@ final class DefaultServiceProvider: ServiceProvider { } } +// TODO extension DefaultServiceProvider { private struct Inner { private let targetQueue: DispatchQueue? private let channelManager: GrpcChannelManager + private let httpRequester: HttpRequester? private var reportUrlToReportConnection: [GrpcChannelConfig: FogReportConnection] = [:] private(set) var transportProtocolOption: TransportProtocol.Option - init(channelManager: GrpcChannelManager, targetQueue: DispatchQueue?) { + init(channelManager: GrpcChannelManager, httpRequester: HttpRequester?, targetQueue: DispatchQueue?) { self.targetQueue = targetQueue + self.httpRequester = httpRequester self.channelManager = channelManager self.transportProtocolOption = TransportProtocol.grpc.option } @@ -115,6 +124,7 @@ extension DefaultServiceProvider { url: fogReportUrl, transportProtocolOption: transportProtocolOption, channelManager: channelManager, + httpRequester: httpRequester, targetQueue: targetQueue) reportUrlToReportConnection[config] = reportConnection return reportConnection diff --git a/Sources/Transaction/Receipt.swift b/Sources/Transaction/Receipt.swift index a628ff52..778160ce 100644 --- a/Sources/Transaction/Receipt.swift +++ b/Sources/Transaction/Receipt.swift @@ -64,7 +64,9 @@ public struct Receipt { } func matchesTxOut(_ txOut: TxOutProtocol) -> Bool { - txOutPublicKeyTyped == txOut.publicKey + logger.debug("self.commitment: \n\n\(commitment.hexEncodedString(options: Data32.HexEncodingOptions.upperCase))\n") + logger.debug("txOut: \n\n\(txOut.commitment.hexEncodedString(options: Data32.HexEncodingOptions.upperCase))\n") + return txOutPublicKeyTyped == txOut.publicKey && commitment == txOut.commitment && maskedValue == txOut.maskedValue } @@ -78,7 +80,6 @@ public struct Receipt { func unmaskValue(accountKey: AccountKey) -> Result { guard let value = TxOutUtils.value( - commitment: commitment, maskedValue: maskedValue, publicKey: txOutPublicKeyTyped, viewPrivateKey: accountKey.viewPrivateKey) @@ -103,7 +104,6 @@ public struct Receipt { } guard let value = TxOutUtils.value( - commitment: commitment, maskedValue: maskedValue, publicKey: txOutPublicKeyTyped, viewPrivateKey: accountKey.viewPrivateKey) @@ -164,3 +164,28 @@ extension External_Receipt { self.tombstoneBlock = receipt.txTombstoneBlockIndex } } + + +extension Data32 { + struct HexEncodingOptions: OptionSet { + let rawValue: Int + static let upperCase = HexEncodingOptions(rawValue: 1 << 0) + } + + func hexEncodedString(options: HexEncodingOptions = []) -> String { + let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx" + return self.map { String(format: format, $0) }.joined() + } +} + +extension Data { + struct HexEncodingOptions: OptionSet { + let rawValue: Int + static let upperCase = HexEncodingOptions(rawValue: 1 << 0) + } + + func hexEncodedString(options: HexEncodingOptions = []) -> String { + let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx" + return self.map { String(format: format, $0) }.joined() + } +} diff --git a/Sources/Transaction/TransactionSubmitter.swift b/Sources/Transaction/TransactionSubmitter.swift index 662f2798..34e013f7 100644 --- a/Sources/Transaction/TransactionSubmitter.swift +++ b/Sources/Transaction/TransactionSubmitter.swift @@ -59,6 +59,8 @@ struct TransactionSubmitter { return .failure(.feeError()) case .tombstoneBlockTooFar: return .failure(.tombstoneBlockTooFar()) + case .missingMemo: + return .failure(.missingMemo("Missing memo")) case .containsSpentKeyImage, .containsExistingOutputPublicKey: // This exact Tx might have already been submitted (and succeeded), or else the // inputs were already spent by another Tx. diff --git a/Sources/Utils/HTTP/HttpCallResult.swift b/Sources/Utils/HTTP/HttpCallResult.swift index 5a0b84ba..8f5543e9 100644 --- a/Sources/Utils/HTTP/HttpCallResult.swift +++ b/Sources/Utils/HTTP/HttpCallResult.swift @@ -10,107 +10,20 @@ import NIOHPACK public struct HttpCallResult { let status: HTTPStatus - let initialMetadata: HTTPURLResponse? + let metadata: HTTPURLResponse? let response: ResponsePayload? } extension HttpCallResult { init( - status: GRPCStatus, - initialMetadata: HTTPURLResponse?, - response: ResponsePayload? + status: HTTPStatus ) { // TODO REMOVE - self.init(status: HTTPStatus(grpcStatus: status), initialMetadata: initialMetadata, response: response) + self.init(status: status, metadata: nil, response: nil) } } -protocol HttpClientCall { - /// The type of the request message for the call. - associatedtype RequestPayload - - /// The type of the response message for the call. - associatedtype ResponsePayload - - /// The event loop this call is running on. - var eventLoop: NIOCore.EventLoop { get } - - /// The options used to make the RPC. - var options: GRPC.CallOptions { get } - - /// HTTP/2 stream that requests and responses are sent and received on. - var subchannel: NIOCore.EventLoopFuture { get } - - /// Initial response metadata. - var initialMetadata: NIOCore.EventLoopFuture { get } - - /// Status of this call which may be populated by the server or client. - /// - /// The client may populate the status if, for example, it was not possible to connect to the service. - /// - /// Note: despite `GRPCStatus` conforming to `Error`, the value will be __always__ delivered as a __success__ - /// result even if the status represents a __negative__ outcome. This future will __never__ be fulfilled - /// with an error. - var status: NIOCore.EventLoopFuture { get } - - /// Trailing response metadata. - var trailingMetadata: NIOCore.EventLoopFuture { get } - - /// Cancel the current call. - /// - /// Closes the HTTP/2 stream once it becomes available. Additional writes to the channel will be ignored. - /// Any unfulfilled promises will be failed with a cancelled status (excepting `status` which will be - /// succeeded, if not already succeeded). - func cancel(promise: NIOCore.EventLoopPromise?) - - var response: NIOCore.EventLoopFuture { get } -} - -//struct HttpResponseClientCall : HttpClientCall { -// var response: EventLoopFuture -// -// var eventLoop: EventLoop -// -// var options: CallOptions -// -// var subchannel: EventLoopFuture -// -// var initialMetadata: EventLoopFuture -// -// var status: EventLoopFuture -// -// var trailingMetadata: EventLoopFuture -// -// func cancel(promise: EventLoopPromise?) { -// -// } -// -// typealias RequestPayload = Int -// -// typealias ResponsePayload = Int -// -// var callResult: EventLoopFuture> { -// var resolvedInitialMetadata: HPACKHeaders? -// initialMetadata.whenSuccess { resolvedInitialMetadata = $0 } -// var resolvedResponse: ResponsePayload? -// response.whenSuccess { resolvedResponse = $0 } -// var resolvedTrailingMetadata: HPACKHeaders? -// trailingMetadata.whenSuccess { resolvedTrailingMetadata = $0 } -// -// return status.flatMap { status in -// self.eventLoop.makeSucceededFuture( -// HttpCallResult( -// status: status, -// initialMetadata: resolvedInitialMetadata, -// response: resolvedResponse, -// trailingMetadata: resolvedTrailingMetadata)) -// } -// } -//} - - - -/// Encapsulates the result of a gRPC call. +/// Encapsulates the result of a HTTP call. public struct HTTPStatus : Error { /// The status code of the RPC. diff --git a/Sources/Utils/MobileCoin-Bridging-Header.h b/Sources/Utils/MobileCoin-Bridging-Header.h new file mode 100644 index 00000000..d3bf134e --- /dev/null +++ b/Sources/Utils/MobileCoin-Bridging-Header.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +#ifndef MobileCoin_Bridging_Header_h +#define MobileCoin_Bridging_Header_h + + +#endif /* MobileCoin_Bridging_Header_h */ + +#ifndef TestBridgingHeader_h +#define TestBridgingHeader_h + + + +#endif /* TestBridgingHeader_h */ + +#include "TestBridgingHeader.h" diff --git a/Sources/Utils/TestBridgingHeader.h b/Sources/Utils/TestBridgingHeader.h new file mode 100644 index 00000000..84d42480 --- /dev/null +++ b/Sources/Utils/TestBridgingHeader.h @@ -0,0 +1,11 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +#import + +@interface TestBridgingHeader : NSObject + +- (id)init; + +@end diff --git a/Sources/Utils/TestBridgingHeader.m b/Sources/Utils/TestBridgingHeader.m new file mode 100644 index 00000000..0957ea22 --- /dev/null +++ b/Sources/Utils/TestBridgingHeader.m @@ -0,0 +1,16 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +#import + +#include "TestBridgingHeader.h" + +@implementation TestBridgingHeader + +- (id)init +{ + return self; +} + +@end diff --git a/Tests/Common/Fixtures/Network/NetworkPreset.swift b/Tests/Common/Fixtures/Network/NetworkPreset.swift index ff1538e2..7e4a39bf 100644 --- a/Tests/Common/Fixtures/Network/NetworkPreset.swift +++ b/Tests/Common/Fixtures/Network/NetworkPreset.swift @@ -108,7 +108,7 @@ extension NetworkPreset { return "mc://node1.test.mobilecoin.com" case .alpha, .mobiledev, .master, .build, .demo, .diogenes, .drakeley, .eran: - return "mc://consensus.\(self).mobilecoin.com" + return "mc://node1.\(self).mobilecoin.com" } } var fogUrl: String { @@ -133,13 +133,13 @@ extension NetworkPreset { "709ab90621e3a8d9eb26ed9e2830e091beceebd55fb01c5d7c31d27e83b9b0d1" private static let testNetConsensusMrEnclaveHex = - "9268c3220a5260e51e4b586f00e4677fed2b80380f1eeaf775af60f8e880fde8" + "9659ea738275b3999bf1700398b60281be03af5cb399738a89b49ea2496595af" private static let testNetFogViewMrEnclaveHex = - "4e598799faa4bb08a3bd55c0bcda7e1d22e41151d0c591f6c2a48b3562b0881e" + "e154f108c7758b5aa7161c3824c176f0c20f63012463bf3cc5651e678f02fb9e" private static let testNetFogLedgerMrEnclaveHex = - "7330c9987f21b91313b39dcdeaa7da8da5ca101c929f5740c207742c762e6dcd" + "768f7bea6171fb83d775ee8485e4b5fcebf5f664ca7e8b9ceef9c7c21e9d9bf3" private static let testNetFogReportMrEnclaveHex = - "185875464ccd67a879d58181055383505a719b364b12d56d9bef90a40bed07ca" + "a4764346f91979b4906d4ce26102228efe3aba39216dec1e7d22e6b06f919f11" private static let devMrSignerHex = "7ee5e29d74623fdbc6fbf1454be6f3bb0b86c12366b7b478ad13353e44de8411" @@ -309,26 +309,40 @@ extension NetworkPreset { } final class TestHttpRequester: HttpRequester { + let configuration : URLSessionConfiguration = { + let config = URLSessionConfiguration.default + config.timeoutIntervalForRequest = 30 + config.timeoutIntervalForResource = 30 + return config + }() + func request( url: URL, method: HTTPMethod, headers: [String: String]?, body: Data?, - completion: @escaping (HTTPResult) -> Void + completion: @escaping (Result) -> Void ) { - let task = URLSession.shared.dataTask(with: url) {data, response, error in + var request = URLRequest(url: url.absoluteURL) + request.httpMethod = method.rawValue + headers?.forEach({ key, value in + request.setValue(value, forHTTPHeaderField: key) + }) + + request.httpBody = body + + let session = URLSession(configuration: configuration) + let task = session.dataTask(with: request) {data, response, error in if let error = error { - completion(.failure(error: error)) + completion(.failure(error)) return } - guard let response = response as? HTTPURLResponse, - (200...299).contains(response.statusCode) else { - completion(.failure(error: ConnectionError.invalidServerResponse(""))) + guard let response = response as? HTTPURLResponse else { + completion(.failure(ConnectionError.invalidServerResponse("No Response"))) return } let httpResponse = HTTPResponse(httpUrlResponse: response, responseData: data) - completion(.success(response: httpResponse)) - + completion(.success(httpResponse)) } task.resume() } diff --git a/Tests/Common/Mocks/Network/MockFogService.swift b/Tests/Common/Mocks/Network/MockFogService.swift index 32e5e428..5976f8f4 100644 --- a/Tests/Common/Mocks/Network/MockFogService.swift +++ b/Tests/Common/Mocks/Network/MockFogService.swift @@ -103,11 +103,11 @@ extension MockFogService { } } - var blockServiceBlocks: [FogLedger_Block] { + var blockServiceBlocks: [FogLedger_BlockData] { var cummulativeTxOutCount: UInt64 = 0 return blockServiceTxOuts.enumerated().map { index, txOuts in cummulativeTxOutCount += UInt64(txOuts.count) - var block = FogLedger_Block() + var block = FogLedger_BlockData() block.index = UInt64(index) block.globalTxoCount = cummulativeTxOutCount block.outputs = txOuts.map { External_TxOut($0) } diff --git a/Tests/Integration/IntegrationTestFixtures.swift b/Tests/Integration/IntegrationTestFixtures.swift index c43a1cab..31901f8a 100644 --- a/Tests/Integration/IntegrationTestFixtures.swift +++ b/Tests/Integration/IntegrationTestFixtures.swift @@ -105,7 +105,9 @@ extension IntegrationTestFixtures { accountKey: AccountKey, config: MobileCoinClient.Config ) throws -> MobileCoinClient { - let client = try MobileCoinClient.make(accountKey: accountKey, config: config).get() + var mutableConfig = config + mutableConfig.httpRequester = TestHttpRequester() + let client = try MobileCoinClient.make(accountKey: accountKey, config: mutableConfig).get() if let consensusCredentials = network.consensusCredentials { client.setConsensusBasicAuthorization( username: consensusCredentials.username, diff --git a/Tests/Integration/Network/Connection/ConsensusConnectionIntTests.swift b/Tests/Integration/Network/Connection/ConsensusConnectionIntTests.swift index 5834a5d0..d982c224 100644 --- a/Tests/Integration/Network/Connection/ConsensusConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/ConsensusConnectionIntTests.swift @@ -164,6 +164,7 @@ extension ConsensusConnectionIntTests { ConsensusConnection( config: networkConfig.consensus, channelManager: GrpcChannelManager(), + httpRequester: networkConfig.httpRequester, targetQueue: DispatchQueue.main) } } diff --git a/Tests/Integration/Network/Connection/FogBlockConnectionIntTests.swift b/Tests/Integration/Network/Connection/FogBlockConnectionIntTests.swift index 0451c71f..8efd56e7 100644 --- a/Tests/Integration/Network/Connection/FogBlockConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/FogBlockConnectionIntTests.swift @@ -156,6 +156,7 @@ extension FogBlockConnectionIntTests { FogBlockConnection( config: networkConfig.fogBlock, channelManager: GrpcChannelManager(), + httpRequester: TestHttpRequester(), targetQueue: DispatchQueue.main) } } diff --git a/Tests/Integration/Network/Connection/FogKeyImageConnectionIntTests.swift b/Tests/Integration/Network/Connection/FogKeyImageConnectionIntTests.swift index 74d0dead..32fdc298 100644 --- a/Tests/Integration/Network/Connection/FogKeyImageConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/FogKeyImageConnectionIntTests.swift @@ -121,6 +121,7 @@ extension FogKeyImageConnectionIntTests { FogKeyImageConnection( config: networkConfig.fogKeyImage, channelManager: GrpcChannelManager(), + httpRequester: TestHttpRequester(), targetQueue: DispatchQueue.main) } } diff --git a/Tests/Integration/Network/Connection/FogMerkleProofConnectionIntTests.swift b/Tests/Integration/Network/Connection/FogMerkleProofConnectionIntTests.swift index 68eb8732..84aaee90 100644 --- a/Tests/Integration/Network/Connection/FogMerkleProofConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/FogMerkleProofConnectionIntTests.swift @@ -160,6 +160,7 @@ extension FogMerkleProofConnectionIntTests { FogMerkleProofConnection( config: networkConfig.fogMerkleProof, channelManager: GrpcChannelManager(), + httpRequester: TestHttpRequester(), targetQueue: DispatchQueue.main) } } diff --git a/Tests/Integration/Network/Connection/FogReportConnectionIntTests.swift b/Tests/Integration/Network/Connection/FogReportConnectionIntTests.swift index dbe42d9e..71488be0 100644 --- a/Tests/Integration/Network/Connection/FogReportConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/FogReportConnectionIntTests.swift @@ -32,8 +32,9 @@ extension FogReportConnectionIntTests { let url = try FogUrl.make(string: IntegrationTestFixtures.network.fogReportUrl).get() return FogReportConnection( url: url, - transportProtocolOption: .grpc, + transportProtocolOption: .http, channelManager: GrpcChannelManager(), + httpRequester: TestHttpRequester(), targetQueue: DispatchQueue.main) } } diff --git a/Tests/Integration/Network/Connection/FogUntrustedTxOutConnectionIntTests.swift b/Tests/Integration/Network/Connection/FogUntrustedTxOutConnectionIntTests.swift index 942ff13a..a1bcbacf 100644 --- a/Tests/Integration/Network/Connection/FogUntrustedTxOutConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/FogUntrustedTxOutConnectionIntTests.swift @@ -62,6 +62,7 @@ extension FogUntrustedTxOutConnectionIntTests { FogUntrustedTxOutConnection( config: networkConfig.fogUntrustedTxOut, channelManager: GrpcChannelManager(), + httpRequester: TestHttpRequester(), targetQueue: DispatchQueue.main) } } diff --git a/Tests/Integration/Network/Connection/FogViewConnectionIntTests.swift b/Tests/Integration/Network/Connection/FogViewConnectionIntTests.swift index 1de33e7b..a218e2e3 100644 --- a/Tests/Integration/Network/Connection/FogViewConnectionIntTests.swift +++ b/Tests/Integration/Network/Connection/FogViewConnectionIntTests.swift @@ -250,7 +250,7 @@ extension FogViewConnectionIntTests { FogViewConnection( config: networkConfig.fogView, channelManager: GrpcChannelManager(), - httpRequester: nil, + httpRequester: TestHttpRequester(), targetQueue: DispatchQueue.main) } } diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 2fc988be..90506e12 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 2fc988beaf2cf51efb8bcf1bef99ce12e2a6e9b9 +Subproject commit 90506e12f70f1ac895e1521cf58204958ec1a599 From 6fdda47e3c9e339fcc2186d0dbba85bb1fdc47c5 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Sat, 4 Sep 2021 06:30:29 -0700 Subject: [PATCH 18/53] uptick dependency versions --- MobileCoin.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MobileCoin.podspec b/MobileCoin.podspec index a95b2b3e..59c503d2 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -30,9 +30,9 @@ Pod::Spec.new do |s| subspec.dependency "LibMobileCoin", "~> 1.1.1" - subspec.dependency "gRPC-Swift", "~> 1.0" + subspec.dependency "gRPC-Swift", "~> 1.3" subspec.dependency "Logging", "~> 1.4" - subspec.dependency "SwiftNIO", "~> 2.22" + subspec.dependency "SwiftNIO", "~> 2.28" subspec.dependency "SwiftNIOHPACK", "~> 1.16" subspec.dependency "SwiftNIOHTTP1", "~> 2.18" subspec.dependency "SwiftProtobuf", "~> 1.5" From 498e6568e3605195b198e85e010396e98351654f Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Sat, 4 Sep 2021 06:59:50 -0700 Subject: [PATCH 19/53] delete lock file, remove version requirements from podspec for testing --- Example/Podfile.lock | 178 ------------------------------------------- MobileCoin.podspec | 8 +- 2 files changed, 4 insertions(+), 182 deletions(-) delete mode 100644 Example/Podfile.lock diff --git a/Example/Podfile.lock b/Example/Podfile.lock deleted file mode 100644 index 61c0b51b..00000000 --- a/Example/Podfile.lock +++ /dev/null @@ -1,178 +0,0 @@ -PODS: - - CGRPCZlib (1.0.0) - - CNIOAtomics (2.27.0) - - CNIOBoringSSL (2.10.5) - - CNIOBoringSSLShims (2.10.5): - - CNIOBoringSSL (= 2.10.5) - - CNIODarwin (2.27.0) - - CNIOHTTPParser (2.27.0) - - CNIOLinux (2.27.0) - - CNIOWindows (2.27.0) - - gRPC-Swift (1.0.0): - - CGRPCZlib (= 1.0.0) - - Logging (< 2.0.0, >= 1.4.0) - - SwiftNIO (< 3.0.0, >= 2.22.0) - - SwiftNIOExtras (< 2.0.0, >= 1.4.0) - - SwiftNIOHTTP2 (< 2.0.0, >= 1.16.1) - - SwiftNIOSSL (< 3.0.0, >= 2.8.0) - - SwiftNIOTransportServices (< 2.0.0, >= 1.6.0) - - SwiftProtobuf (< 2.0.0, >= 1.9.0) - - Keys (1.0.1) - - LibMobileCoin (1.1.1): - - gRPC-Swift (~> 1.0) - - SwiftProtobuf (~> 1.5) - - Logging (1.4.0) - - MobileCoin (1.1.1): - - MobileCoin/Core (= 1.1.1) - - MobileCoin/Core (1.1.1): - - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1.1) - - Logging (~> 1.4) - - SwiftLint - - SwiftNIO (~> 2.22) - - SwiftNIOHPACK (~> 1.16) - - SwiftNIOHTTP1 (~> 2.18) - - SwiftProtobuf (~> 1.5) - - MobileCoin/Core/IntegrationTests (1.1.1): - - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1.1) - - Logging (~> 1.4) - - SwiftLint - - SwiftNIO (~> 2.22) - - SwiftNIOHPACK (~> 1.16) - - SwiftNIOHTTP1 (~> 2.18) - - SwiftProtobuf (~> 1.5) - - MobileCoin/Core/PerformanceTests (1.1.1): - - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1.1) - - Logging (~> 1.4) - - SwiftLint - - SwiftNIO (~> 2.22) - - SwiftNIOHPACK (~> 1.16) - - SwiftNIOHTTP1 (~> 2.18) - - SwiftProtobuf (~> 1.5) - - MobileCoin/Core/Tests (1.1.1): - - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1.1) - - Logging (~> 1.4) - - SwiftLint - - SwiftNIO (~> 2.22) - - SwiftNIOHPACK (~> 1.16) - - SwiftNIOHTTP1 (~> 2.18) - - SwiftProtobuf (~> 1.5) - - SwiftLint (0.43.1) - - SwiftNIO (2.27.0): - - CNIODarwin (= 2.27.0) - - CNIOLinux (= 2.27.0) - - CNIOWindows (= 2.27.0) - - SwiftNIOConcurrencyHelpers (= 2.27.0) - - SwiftNIOConcurrencyHelpers (2.27.0): - - CNIOAtomics (= 2.27.0) - - SwiftNIOExtras (1.8.0): - - SwiftNIO (< 3, >= 2.9.0) - - SwiftNIOFoundationCompat (2.27.0): - - SwiftNIO (= 2.27.0) - - SwiftNIOHPACK (1.16.3): - - SwiftNIO (< 3, >= 2.18.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.18.0) - - SwiftNIOHTTP1 (< 3, >= 2.18.0) - - SwiftNIOHTTP1 (2.27.0): - - CNIOHTTPParser (= 2.27.0) - - SwiftNIO (= 2.27.0) - - SwiftNIOConcurrencyHelpers (= 2.27.0) - - SwiftNIOHTTP2 (1.16.3): - - SwiftNIO (< 3, >= 2.18.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.18.0) - - SwiftNIOHPACK (= 1.16.3) - - SwiftNIOHTTP1 (< 3, >= 2.18.0) - - SwiftNIOTLS (< 3, >= 2.18.0) - - SwiftNIOSSL (2.10.5): - - CNIOBoringSSL (= 2.10.5) - - CNIOBoringSSLShims (= 2.10.5) - - SwiftNIO (< 3, >= 2.15.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.15.0) - - SwiftNIOTLS (< 3, >= 2.15.0) - - SwiftNIOTLS (2.27.0): - - SwiftNIO (= 2.27.0) - - SwiftNIOTransportServices (1.9.2): - - SwiftNIO (< 3, >= 2.19.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.19.0) - - SwiftNIOFoundationCompat (< 3, >= 2.19.0) - - SwiftNIOTLS (< 3, >= 2.19.0) - - SwiftProtobuf (1.15.0) - -DEPENDENCIES: - - gRPC-Swift - - Keys (from `Pods/CocoaPodsKeys`) - - LibMobileCoin (from `../Vendor/libmobilecoin-ios-artifacts`) - - MobileCoin (from `..`) - - MobileCoin/Core (from `..`) - - MobileCoin/Core/IntegrationTests (from `..`) - - MobileCoin/Core/PerformanceTests (from `..`) - - MobileCoin/Core/Tests (from `..`) - - SwiftLint - - SwiftProtobuf - -SPEC REPOS: - trunk: - - CGRPCZlib - - CNIOAtomics - - CNIOBoringSSL - - CNIOBoringSSLShims - - CNIODarwin - - CNIOHTTPParser - - CNIOLinux - - CNIOWindows - - gRPC-Swift - - Logging - - SwiftLint - - SwiftNIO - - SwiftNIOConcurrencyHelpers - - SwiftNIOExtras - - SwiftNIOFoundationCompat - - SwiftNIOHPACK - - SwiftNIOHTTP1 - - SwiftNIOHTTP2 - - SwiftNIOSSL - - SwiftNIOTLS - - SwiftNIOTransportServices - - SwiftProtobuf - -EXTERNAL SOURCES: - Keys: - :path: Pods/CocoaPodsKeys - LibMobileCoin: - :path: "../Vendor/libmobilecoin-ios-artifacts" - MobileCoin: - :path: ".." - -SPEC CHECKSUMS: - CGRPCZlib: b0c9d704a12fa667f1824ffff20688f191945989 - CNIOAtomics: 43316aa185f4bd639aa0a9cd49741151bbe8de7f - CNIOBoringSSL: 7ff9c35139a115f93269915b9555044d741b2ac9 - CNIOBoringSSLShims: 6edde63429e353ba78992b2d4d1b0627752a4a43 - CNIODarwin: 9eb3c09e9f3fc5ed47cecdd032aad926df81e3a6 - CNIOHTTPParser: c6051552c5f332e4ec0756581e5cbd5632ca24e6 - CNIOLinux: 79227941d64216792c3c59238b0106b9e0df25bc - CNIOWindows: f2baa102255e986467578337ffa2f777cb6bdf7f - gRPC-Swift: 77154009a019e97f8c4bd8f2bb75fe9726801157 - Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: 5a070cacfba08e9a1dec3462c9b632785d0ed0a4 - Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: d9d636ae8ebe8aef9ddc44107c615f5bb19bf5de - SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 - SwiftNIO: 81d33ce8c500b7e41b6cdde5f2f12330b9750219 - SwiftNIOConcurrencyHelpers: 23fc68bac541a465162d7225d2c743edd2f1012c - SwiftNIOExtras: aa561b71020cd6844f722cf4513fb176c577414d - SwiftNIOFoundationCompat: 0e52ac0e2c9b7b60ff9141eebb64f5a82d974118 - SwiftNIOHPACK: 38e855a72ae0c5176485ddd039b3933b99daa2b7 - SwiftNIOHTTP1: 846277d7fc7661fba655540e529d7ba3c728ca50 - SwiftNIOHTTP2: de7eff9d32fd347338f85b86c6fd0e13c3fbd1a0 - SwiftNIOSSL: 6a1f0499a5319e823eae0b6f053ecb502bcce3f5 - SwiftNIOTLS: 4f8df225f03393f08e0b47b4d876ae38167f8a27 - SwiftNIOTransportServices: 896c9a4ac98698d32aa2feea7657ade219ae80bb - SwiftProtobuf: 3320217e9d8fb75f36b40282e78c482640fd75dd - -PODFILE CHECKSUM: 21810a12546c9ea22d94f5e3fe7d63c8dc089fcf - -COCOAPODS: 1.9.3 diff --git a/MobileCoin.podspec b/MobileCoin.podspec index 59c503d2..d5fea735 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -32,10 +32,10 @@ Pod::Spec.new do |s| subspec.dependency "gRPC-Swift", "~> 1.3" subspec.dependency "Logging", "~> 1.4" - subspec.dependency "SwiftNIO", "~> 2.28" - subspec.dependency "SwiftNIOHPACK", "~> 1.16" - subspec.dependency "SwiftNIOHTTP1", "~> 2.18" - subspec.dependency "SwiftProtobuf", "~> 1.5" + subspec.dependency "SwiftNIO" + subspec.dependency "SwiftNIOHPACK" + subspec.dependency "SwiftNIOHTTP1" + subspec.dependency "SwiftProtobuf" subspec.test_spec do |test_spec| test_spec.source_files = "Tests/{Unit,Common}/**/*.swift" From 99d6e9fa6c2bf322df7a44082d8ee08d7491d451 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Sun, 5 Sep 2021 23:39:42 -0700 Subject: [PATCH 20/53] working w/ arch specific binaries (not stripped) --- Example/Example.xcodeproj/project.pbxproj | 5 + Example/Podfile.lock | 202 ++++++++++++++++++++++ Vendor/libmobilecoin-ios-artifacts | 2 +- 3 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 Example/Podfile.lock diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index bea58e5b..60ea70e9 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -364,6 +364,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 05E35D1FAC2827984EE8B421 /* Pods-Example.debug.xcconfig */; buildSettings = { + "ARCHS[sdk=iphonesimulator*]" = x86_64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\""; @@ -386,6 +387,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 3AF40DB60A0ADA2CB879AE38 /* Pods-Example.release.xcconfig */; buildSettings = { + "ARCHS[sdk=iphonesimulator*]" = x86_64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\""; @@ -397,6 +399,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.mobilecoin.Example; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -463,6 +466,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = FC106CAA4E993C2D6301C5CA /* Pods-Example.testable release.xcconfig */; buildSettings = { + "ARCHS[sdk=iphonesimulator*]" = x86_64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\""; @@ -474,6 +478,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.mobilecoin.Example; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; diff --git a/Example/Podfile.lock b/Example/Podfile.lock new file mode 100644 index 00000000..aa31277f --- /dev/null +++ b/Example/Podfile.lock @@ -0,0 +1,202 @@ +PODS: + - _NIODataStructures (2.32.0) + - CGRPCZlib (1.3.0) + - CNIOAtomics (2.32.0) + - CNIOBoringSSL (2.14.1) + - CNIOBoringSSLShims (2.14.1): + - CNIOBoringSSL (= 2.14.1) + - CNIODarwin (2.32.0) + - CNIOHTTPParser (2.32.0) + - CNIOLinux (2.32.0) + - CNIOWindows (2.32.0) + - gRPC-Swift (1.3.0): + - CGRPCZlib (= 1.3.0) + - Logging (< 2.0.0, >= 1.4.0) + - SwiftNIO (< 3.0.0, >= 2.28.0) + - SwiftNIOExtras (< 2.0.0, >= 1.4.0) + - SwiftNIOHTTP2 (< 2.0.0, >= 1.16.1) + - SwiftNIOSSL (< 3.0.0, >= 2.14.0) + - SwiftNIOTransportServices (< 2.0.0, >= 1.6.0) + - SwiftProtobuf (< 2.0.0, >= 1.9.0) + - Keys (1.0.1) + - LibMobileCoin (1.1.1): + - gRPC-Swift (~> 1.0) + - SwiftProtobuf (~> 1.5) + - Logging (1.4.0) + - MobileCoin (1.1.1): + - MobileCoin/Core (= 1.1.1) + - MobileCoin/Core (1.1.1): + - gRPC-Swift (~> 1.3) + - LibMobileCoin (~> 1.1.1) + - Logging (~> 1.4) + - SwiftLint + - SwiftNIO + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftProtobuf + - MobileCoin/Core/IntegrationTests (1.1.1): + - gRPC-Swift (~> 1.3) + - LibMobileCoin (~> 1.1.1) + - Logging (~> 1.4) + - SwiftLint + - SwiftNIO + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftProtobuf + - MobileCoin/Core/PerformanceTests (1.1.1): + - gRPC-Swift (~> 1.3) + - LibMobileCoin (~> 1.1.1) + - Logging (~> 1.4) + - SwiftLint + - SwiftNIO + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftProtobuf + - MobileCoin/Core/Tests (1.1.1): + - gRPC-Swift (~> 1.3) + - LibMobileCoin (~> 1.1.1) + - Logging (~> 1.4) + - SwiftLint + - SwiftNIO + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftProtobuf + - SwiftLint (0.43.1) + - SwiftNIO (2.32.0): + - SwiftNIOCore (= 2.32.0) + - SwiftNIOEmbedded (= 2.32.0) + - SwiftNIOPosix (= 2.32.0) + - SwiftNIOConcurrencyHelpers (2.32.0): + - CNIOAtomics (= 2.32.0) + - SwiftNIOCore (2.32.0): + - CNIOLinux (= 2.32.0) + - SwiftNIOConcurrencyHelpers (= 2.32.0) + - SwiftNIOEmbedded (2.32.0): + - _NIODataStructures (= 2.32.0) + - SwiftNIOCore (= 2.32.0) + - SwiftNIOExtras (1.10.0): + - SwiftNIO (< 3, >= 2.30.0) + - SwiftNIOFoundationCompat (2.32.0): + - SwiftNIO (= 2.32.0) + - SwiftNIOCore (= 2.32.0) + - SwiftNIOHPACK (1.18.1): + - SwiftNIO (< 3, >= 2.30.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.30.0) + - SwiftNIOHTTP1 (< 3, >= 2.30.0) + - SwiftNIOHTTP1 (2.32.0): + - CNIOHTTPParser (= 2.32.0) + - SwiftNIO (= 2.32.0) + - SwiftNIOConcurrencyHelpers (= 2.32.0) + - SwiftNIOCore (= 2.32.0) + - SwiftNIOHTTP2 (1.18.1): + - SwiftNIO (< 3, >= 2.30.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.30.0) + - SwiftNIOHPACK (= 1.18.1) + - SwiftNIOHTTP1 (< 3, >= 2.30.0) + - SwiftNIOTLS (< 3, >= 2.30.0) + - SwiftNIOPosix (2.32.0): + - _NIODataStructures (= 2.32.0) + - CNIODarwin (= 2.32.0) + - CNIOLinux (= 2.32.0) + - CNIOWindows (= 2.32.0) + - SwiftNIOConcurrencyHelpers (= 2.32.0) + - SwiftNIOCore (= 2.32.0) + - SwiftNIOSSL (2.14.1): + - CNIOBoringSSL (= 2.14.1) + - CNIOBoringSSLShims (= 2.14.1) + - SwiftNIO (< 3, >= 2.30.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.30.0) + - SwiftNIOTLS (< 3, >= 2.30.0) + - SwiftNIOTLS (2.32.0): + - SwiftNIO (= 2.32.0) + - SwiftNIOCore (= 2.32.0) + - SwiftNIOTransportServices (1.11.1): + - SwiftNIO (< 3, >= 2.32.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) + - SwiftNIOFoundationCompat (< 3, >= 2.32.0) + - SwiftNIOTLS (< 3, >= 2.32.0) + - SwiftProtobuf (1.17.0) + +DEPENDENCIES: + - gRPC-Swift + - Keys (from `Pods/CocoaPodsKeys`) + - LibMobileCoin (from `../Vendor/libmobilecoin-ios-artifacts`) + - MobileCoin (from `..`) + - MobileCoin/Core (from `..`) + - MobileCoin/Core/IntegrationTests (from `..`) + - MobileCoin/Core/PerformanceTests (from `..`) + - MobileCoin/Core/Tests (from `..`) + - SwiftLint + - SwiftProtobuf + +SPEC REPOS: + trunk: + - _NIODataStructures + - CGRPCZlib + - CNIOAtomics + - CNIOBoringSSL + - CNIOBoringSSLShims + - CNIODarwin + - CNIOHTTPParser + - CNIOLinux + - CNIOWindows + - gRPC-Swift + - Logging + - SwiftLint + - SwiftNIO + - SwiftNIOConcurrencyHelpers + - SwiftNIOCore + - SwiftNIOEmbedded + - SwiftNIOExtras + - SwiftNIOFoundationCompat + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftNIOHTTP2 + - SwiftNIOPosix + - SwiftNIOSSL + - SwiftNIOTLS + - SwiftNIOTransportServices + - SwiftProtobuf + +EXTERNAL SOURCES: + Keys: + :path: Pods/CocoaPodsKeys + LibMobileCoin: + :path: "../Vendor/libmobilecoin-ios-artifacts" + MobileCoin: + :path: ".." + +SPEC CHECKSUMS: + _NIODataStructures: e63beb6bfebffbd4399e514b7ecaf3f96cd8671c + CGRPCZlib: 858fb2c33706c84959695f32ce8852746c3a8c3d + CNIOAtomics: 9a2bb6949fab36db580f9973e36813bf0744cace + CNIOBoringSSL: fbf8a722a81aa837c9cfae06da6b532f5eff7097 + CNIOBoringSSLShims: ad7c2c665a5426b29526a11af1b084764fef80d4 + CNIODarwin: 6c3b7847a6a2691ae9f97eac75103fe06f61fe4c + CNIOHTTPParser: 4d469972144001aace68635ae33009c6b97c377f + CNIOLinux: d33b1366a209d566a0a81eaecac6283a40ecc840 + CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc + gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 + Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 + LibMobileCoin: 7d75fcab019e579023ebdb67094d917a65a725d2 + Logging: beeb016c9c80cf77042d62e83495816847ef108b + MobileCoin: 4875ea3a0bb05288cfc827eabe59cc090226de08 + SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 + SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a + SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d + SwiftNIOCore: 33d188a3d66eb65010bba8c4e7ea3efeabf757f7 + SwiftNIOEmbedded: d9b5cc8e3fc22b057501047ba3c8561c88d21544 + SwiftNIOExtras: 12c3902de56e7ff1e13b503f25f91f6241e6c070 + SwiftNIOFoundationCompat: 77058ddb6d30bfcda27b82f55bf9f004131917bc + SwiftNIOHPACK: cc0189da98884147f27d4c077345b7c0995e9d27 + SwiftNIOHTTP1: 6c68f7ae14f67941d67c2056c7d9d3b727993f12 + SwiftNIOHTTP2: de65e456e4fadd68c8612afd8f12c45da2b183f6 + SwiftNIOPosix: 745b539a2067e5159d5de54e77860bae9e281e3a + SwiftNIOSSL: ac352ffa568767772767057b85fd5cf7fffe7254 + SwiftNIOTLS: e26c48fdc92b753860349d75e1c49855f4125655 + SwiftNIOTransportServices: a10d05256d0c37566266896d0b14b6725c0ee60e + SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 + +PODFILE CHECKSUM: a0d081de36bb0e26c2f240e65e5e63f9f111ec19 + +COCOAPODS: 1.9.3 diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 90506e12..43f3f9a5 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 90506e12f70f1ac895e1521cf58204958ec1a599 +Subproject commit 43f3f9a5c084b6b75ea7510ec046970fa5605230 From 74b26b3120ebd7c1dc000457066557e695d75467 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Mon, 6 Sep 2021 21:19:05 -0700 Subject: [PATCH 21/53] update libmobilecoin --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 43f3f9a5..96eb45de 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 43f3f9a5c084b6b75ea7510ec046970fa5605230 +Subproject commit 96eb45de5aa5eb439f2b477e2f8ca4eb2ecaf2c4 From 108b17e745f9d3404fd88b41c042edc156de857e Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Mon, 6 Sep 2021 22:13:27 -0700 Subject: [PATCH 22/53] not working WIP --- Example/Podfile | 6 +++--- Example/Podfile.lock | 4 ++-- MobileCoin.podspec | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index 2d624adf..01f93d94 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -31,9 +31,9 @@ target 'Example' do # pod 'LibMobileCoin', podspec: '../Vendor/libmobilecoin-ios-artifacts/LibMobileCoin.podspec' # pod 'LibMobileCoin', git: 'https://github.com/mobilecoinofficial/libmobilecoin-ios-artifacts.git' - pod 'gRPC-Swift', binary: true - pod 'SwiftProtobuf', binary: true - pod 'SwiftLint', binary: true + pod 'gRPC-Swift' + pod 'SwiftProtobuf' + pod 'SwiftLint' end post_install do |installer| diff --git a/Example/Podfile.lock b/Example/Podfile.lock index aa31277f..7717ed5b 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -178,7 +178,7 @@ SPEC CHECKSUMS: CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: 7d75fcab019e579023ebdb67094d917a65a725d2 + LibMobileCoin: 65952ae03077e788e93225df9c56cdced9cba8d9 Logging: beeb016c9c80cf77042d62e83495816847ef108b MobileCoin: 4875ea3a0bb05288cfc827eabe59cc090226de08 SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 @@ -197,6 +197,6 @@ SPEC CHECKSUMS: SwiftNIOTransportServices: a10d05256d0c37566266896d0b14b6725c0ee60e SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 -PODFILE CHECKSUM: a0d081de36bb0e26c2f240e65e5e63f9f111ec19 +PODFILE CHECKSUM: b12ab53dfebf09078ff3b9c0254447192c507004 COCOAPODS: 1.9.3 diff --git a/MobileCoin.podspec b/MobileCoin.podspec index d5fea735..94b53a43 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -78,8 +78,6 @@ Pod::Spec.new do |s| "SUPPORTS_MACCATALYST" => "NO", # The LibMobileCoin vendored binary doesn't include support for 32-bit # architectures or for arm64 iphonesimulator. - "VALID_ARCHS[sdk=iphoneos*]" => "arm64", - "VALID_ARCHS[sdk=iphonesimulator*]" => "x86_64", } unless ENV["MC_ENABLE_WARN_LONG_COMPILE_TIMES"].nil? From ed9721cc20c18af8df07a412338ed0641c465b48 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Mon, 6 Sep 2021 22:39:17 -0700 Subject: [PATCH 23/53] wip trying to get prem1 working --- Example/Podfile.lock | 12 ++++++------ MobileCoin.podspec | 2 +- Vendor/libmobilecoin-ios-artifacts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 7717ed5b..8564b0e8 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -26,7 +26,7 @@ PODS: - MobileCoin (1.1.1): - MobileCoin/Core (= 1.1.1) - MobileCoin/Core (1.1.1): - - gRPC-Swift (~> 1.3) + - gRPC-Swift (~> 1.0) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -35,7 +35,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/IntegrationTests (1.1.1): - - gRPC-Swift (~> 1.3) + - gRPC-Swift (~> 1.0) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -44,7 +44,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/PerformanceTests (1.1.1): - - gRPC-Swift (~> 1.3) + - gRPC-Swift (~> 1.0) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -53,7 +53,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/Tests (1.1.1): - - gRPC-Swift (~> 1.3) + - gRPC-Swift (~> 1.0) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -178,9 +178,9 @@ SPEC CHECKSUMS: CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: 65952ae03077e788e93225df9c56cdced9cba8d9 + LibMobileCoin: c28117f06bde6db1bc105a5faf6e974e594c510d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: 4875ea3a0bb05288cfc827eabe59cc090226de08 + MobileCoin: 97ac88ed276ec7277a3549e89f3c1f1c92cf8f50 SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d diff --git a/MobileCoin.podspec b/MobileCoin.podspec index 94b53a43..d1b98cfd 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -30,7 +30,7 @@ Pod::Spec.new do |s| subspec.dependency "LibMobileCoin", "~> 1.1.1" - subspec.dependency "gRPC-Swift", "~> 1.3" + subspec.dependency "gRPC-Swift", "~> 1.0" subspec.dependency "Logging", "~> 1.4" subspec.dependency "SwiftNIO" subspec.dependency "SwiftNIOHPACK" diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 96eb45de..6a377e19 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 96eb45de5aa5eb439f2b477e2f8ca4eb2ecaf2c4 +Subproject commit 6a377e193de01ed1b08563628984268f2e1e2c0f From e87bdea2d004656819b2ad1b22c9b2f2d0ca6141 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Mon, 6 Sep 2021 23:40:43 -0700 Subject: [PATCH 24/53] working solution --- Example/Podfile | 9 +++++++++ Example/Podfile.lock | 14 +++++++------- MobileCoin.podspec | 4 ++++ Vendor/libmobilecoin-ios-artifacts | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index 01f93d94..991dc657 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -82,4 +82,13 @@ post_install do |installer| config.build_settings["OTHER_LDFLAGS"] << ' -framework "Keys"' end end + + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + # config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf' + # config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' +#config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' +# config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "i386" + end + end end diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 8564b0e8..e247d9bc 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -26,7 +26,7 @@ PODS: - MobileCoin (1.1.1): - MobileCoin/Core (= 1.1.1) - MobileCoin/Core (1.1.1): - - gRPC-Swift (~> 1.0) + - gRPC-Swift (~> 1.3) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -35,7 +35,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/IntegrationTests (1.1.1): - - gRPC-Swift (~> 1.0) + - gRPC-Swift (~> 1.3) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -44,7 +44,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/PerformanceTests (1.1.1): - - gRPC-Swift (~> 1.0) + - gRPC-Swift (~> 1.3) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -53,7 +53,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/Tests (1.1.1): - - gRPC-Swift (~> 1.0) + - gRPC-Swift (~> 1.3) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -178,9 +178,9 @@ SPEC CHECKSUMS: CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: c28117f06bde6db1bc105a5faf6e974e594c510d + LibMobileCoin: 0f1f6ce1ba112959c7e018eeef2d45f06443f8f1 Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: 97ac88ed276ec7277a3549e89f3c1f1c92cf8f50 + MobileCoin: 4dda50c47d836bb4858ed3d2088b850b56caed1f SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d @@ -197,6 +197,6 @@ SPEC CHECKSUMS: SwiftNIOTransportServices: a10d05256d0c37566266896d0b14b6725c0ee60e SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 -PODFILE CHECKSUM: b12ab53dfebf09078ff3b9c0254447192c507004 +PODFILE CHECKSUM: c51b390c09b12209c2d081ce4b9ed0617c74427e COCOAPODS: 1.9.3 diff --git a/MobileCoin.podspec b/MobileCoin.podspec index d1b98cfd..536810ef 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -78,6 +78,10 @@ Pod::Spec.new do |s| "SUPPORTS_MACCATALYST" => "NO", # The LibMobileCoin vendored binary doesn't include support for 32-bit # architectures or for arm64 iphonesimulator. + "VALID_ARCHS[sdk=iphoneos*]" => "arm64", + "VALID_ARCHS[sdk=iphonesimulator*]" => "x86_64", + "EXCLUDED_ARCHS[sdk=iphoneos*]" => "armv7", + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" => "i386 arm64" } unless ENV["MC_ENABLE_WARN_LONG_COMPILE_TIMES"].nil? diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 6a377e19..b9c24dd7 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 6a377e193de01ed1b08563628984268f2e1e2c0f +Subproject commit b9c24dd715beca4b700ebe08d3044e2013352e6a From 0f5d556b2e9db2377fb74380cea6cc6f00a0c3d5 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Mon, 6 Sep 2021 23:58:26 -0700 Subject: [PATCH 25/53] remove extra arch exclusions --- Example/Podfile | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index 991dc657..01f93d94 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -82,13 +82,4 @@ post_install do |installer| config.build_settings["OTHER_LDFLAGS"] << ' -framework "Keys"' end end - - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - # config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf' - # config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' -#config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' -# config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "i386" - end - end end From 2d988e895a68556c9cf77bc090de957dac9c3fe0 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 7 Sep 2021 21:36:13 -0700 Subject: [PATCH 26/53] Update commitment code to use correct solution. remove some debug --- Sources/Ledger/KnownTxOut.swift | 15 +++++++-------- Sources/Ledger/PartialTxOut.swift | 15 +++++++-------- Sources/Ledger/TxOutUtils.swift | 13 ++++++++----- Sources/Transaction/Receipt.swift | 5 ++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Sources/Ledger/KnownTxOut.swift b/Sources/Ledger/KnownTxOut.swift index 9626514c..39ac51e1 100644 --- a/Sources/Ledger/KnownTxOut.swift +++ b/Sources/Ledger/KnownTxOut.swift @@ -12,18 +12,16 @@ struct KnownTxOut: TxOutProtocol { init?(_ ledgerTxOut: LedgerTxOut, accountKey: AccountKey) { guard let value = ledgerTxOut.value(accountKey: accountKey), - let keyImage = ledgerTxOut.keyImage(accountKey: accountKey) + let keyImage = ledgerTxOut.keyImage(accountKey: accountKey), + let commitment = TxOutUtils.reconstructCommitment( + maskedValue: ledgerTxOut.maskedValue, + publicKey: ledgerTxOut.publicKey, + viewPrivateKey:accountKey.viewPrivateKey) else { return nil } - - guard let commitment = TxOutUtils.sharedSecret(publicKey: ledgerTxOut.publicKey, viewPrivateKey:accountKey.viewPrivateKey) else { - return nil - } - logger.warning("self.commitment: \n\n\(commitment.data.hexEncodedString(options: Data.HexEncodingOptions.upperCase))\n") - self.commitment = commitment.data32 - + self.commitment = commitment self.ledgerTxOut = ledgerTxOut self.value = value self.keyImage = keyImage @@ -39,3 +37,4 @@ struct KnownTxOut: TxOutProtocol { extension KnownTxOut: Equatable {} extension KnownTxOut: Hashable {} + diff --git a/Sources/Ledger/PartialTxOut.swift b/Sources/Ledger/PartialTxOut.swift index debc5bc9..ddd08edd 100644 --- a/Sources/Ledger/PartialTxOut.swift +++ b/Sources/Ledger/PartialTxOut.swift @@ -55,19 +55,18 @@ extension PartialTxOut { // } // init?(_ txOutRecord: FogView_TxOutRecord, viewKey: RistrettoPrivate) { -// let commitment = Data32(txOutRecord.txOutAmountCommitmentData) ?? Data32() guard let targetKey = RistrettoPublic(txOutRecord.txOutTargetKeyData), - let publicKey = RistrettoPublic(txOutRecord.txOutPublicKeyData) + let publicKey = RistrettoPublic(txOutRecord.txOutPublicKeyData), + let commitment = TxOutUtils.reconstructCommitment( + maskedValue: txOutRecord.txOutAmountMaskedValue, + publicKey: publicKey, + viewPrivateKey: viewKey) else { return nil } - - guard let commitment = TxOutUtils.sharedSecret(publicKey: publicKey, viewPrivateKey: viewKey) else { - logger.warning("nil") - return nil - } + self.init( - commitment: commitment.data32, + commitment: commitment, maskedValue: txOutRecord.txOutAmountMaskedValue, targetKey: targetKey, publicKey: publicKey) diff --git a/Sources/Ledger/TxOutUtils.swift b/Sources/Ledger/TxOutUtils.swift index d82e73a0..2b903faf 100644 --- a/Sources/Ledger/TxOutUtils.swift +++ b/Sources/Ledger/TxOutUtils.swift @@ -59,14 +59,17 @@ enum TxOutUtils { } } - static func sharedSecret( + static func reconstructCommitment( + maskedValue: UInt64, publicKey: RistrettoPublic, viewPrivateKey: RistrettoPrivate - ) -> RistrettoPublic? { - publicKey.asMcBuffer { publicKeyBufferPtr in + ) -> Data32? { + var mcAmount = McTxOutAmount(masked_value: maskedValue) + return publicKey.asMcBuffer { publicKeyBufferPtr in viewPrivateKey.asMcBuffer { viewPrivateKeyPtr in switch Data32.make(withMcMutableBuffer: { bufferPtr, errorPtr in - mc_tx_out_shared_secret( + mc_tx_out_reconstruct_commitment( + &mcAmount, publicKeyBufferPtr, viewPrivateKeyPtr, bufferPtr, @@ -76,7 +79,7 @@ enum TxOutUtils { // Safety: It's safe to skip validation because // mc_tx_out_get_subaddress_spend_public_key should always return a valid // RistrettoPublic on success. - return RistrettoPublic(skippingValidation: bytes) + return bytes as Data32 case .failure(let error): switch error.errorCode { case .invalidInput: diff --git a/Sources/Transaction/Receipt.swift b/Sources/Transaction/Receipt.swift index 778160ce..570de630 100644 --- a/Sources/Transaction/Receipt.swift +++ b/Sources/Transaction/Receipt.swift @@ -1,4 +1,5 @@ // + // Copyright (c) 2020-2021 MobileCoin. All rights reserved. // @@ -64,8 +65,6 @@ public struct Receipt { } func matchesTxOut(_ txOut: TxOutProtocol) -> Bool { - logger.debug("self.commitment: \n\n\(commitment.hexEncodedString(options: Data32.HexEncodingOptions.upperCase))\n") - logger.debug("txOut: \n\n\(txOut.commitment.hexEncodedString(options: Data32.HexEncodingOptions.upperCase))\n") return txOutPublicKeyTyped == txOut.publicKey && commitment == txOut.commitment && maskedValue == txOut.maskedValue @@ -113,7 +112,7 @@ public struct Receipt { return value } - + enum ReceivedStatus { case notReceived(knownToBeNotReceivedBlockCount: UInt64?) case received(block: BlockMetadata) From 2409b5566ed2324d46e565a96ec642331fc4d5a9 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 7 Sep 2021 21:41:25 -0700 Subject: [PATCH 27/53] remove comments and debug code --- Sources/Ledger/LedgerTxOut.swift | 15 --------------- Sources/Ledger/PartialTxOut.swift | 14 -------------- Sources/Ledger/TxOutProtocol.swift | 2 +- 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/Sources/Ledger/LedgerTxOut.swift b/Sources/Ledger/LedgerTxOut.swift index 461082ae..53dd4364 100644 --- a/Sources/Ledger/LedgerTxOut.swift +++ b/Sources/Ledger/LedgerTxOut.swift @@ -17,21 +17,6 @@ struct LedgerTxOut: TxOutProtocol { } var commitment: Data32 { txOut.commitment } - - /* - public static RistrettoPublic getSharedSecret( - @NonNull RistrettoPrivate viewPrivateKey, - @NonNull RistrettoPublic txOutPublicKey - ) throws TransactionBuilderException { - Logger.i(TAG, "Retrieving shared secret", null, "txOut public:", txOutPublicKey); - try { - long rustObj = get_shared_secret(viewPrivateKey, txOutPublicKey); - return RistrettoPublic.fromJNI(rustObj); - } catch(Exception ex) { - throw new TransactionBuilderException(ex.getLocalizedMessage(), ex); - } - } - */ var maskedValue: UInt64 { txOut.maskedValue } var targetKey: RistrettoPublic { txOut.targetKey } var publicKey: RistrettoPublic { txOut.publicKey } diff --git a/Sources/Ledger/PartialTxOut.swift b/Sources/Ledger/PartialTxOut.swift index ddd08edd..08f4a197 100644 --- a/Sources/Ledger/PartialTxOut.swift +++ b/Sources/Ledger/PartialTxOut.swift @@ -40,20 +40,6 @@ extension PartialTxOut { publicKey: publicKey) } -// init?(_ txOut: FogView_FogTxOut) { -// guard let commitment = Data32(txOut.amount.commitment.data), -// let targetKey = RistrettoPublic(txOut.targetKey.data), -// let publicKey = RistrettoPublic(txOut.publicKey.data) -// else { -// return nil -// } -// self.init( -// commitment: commitment, -// maskedValue: txOut.amount.maskedValue, -// targetKey: targetKey, -// publicKey: publicKey) -// } -// init?(_ txOutRecord: FogView_TxOutRecord, viewKey: RistrettoPrivate) { guard let targetKey = RistrettoPublic(txOutRecord.txOutTargetKeyData), let publicKey = RistrettoPublic(txOutRecord.txOutPublicKeyData), diff --git a/Sources/Ledger/TxOutProtocol.swift b/Sources/Ledger/TxOutProtocol.swift index 4fd2f4ed..22495d14 100644 --- a/Sources/Ledger/TxOutProtocol.swift +++ b/Sources/Ledger/TxOutProtocol.swift @@ -6,7 +6,7 @@ import Foundation import LibMobileCoin protocol TxOutProtocol { - var commitment: Data32 { get } // Deprecate ?? + var commitment: Data32 { get } var maskedValue: UInt64 { get } var targetKey: RistrettoPublic { get } var publicKey: RistrettoPublic { get } From dea08e6859e064822c4adabd8e8c135cff3a594e Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 7 Sep 2021 21:49:33 -0700 Subject: [PATCH 28/53] remove Cert Pinning WIP class --- .../Connection/AttestedConnection.swift | 54 ------- Sources/Network/Connection/Connection.swift | 2 +- .../Connection/ConnectionSession.swift | 153 ------------------ 3 files changed, 1 insertion(+), 208 deletions(-) delete mode 100644 Sources/Network/Connection/AttestedConnection.swift diff --git a/Sources/Network/Connection/AttestedConnection.swift b/Sources/Network/Connection/AttestedConnection.swift deleted file mode 100644 index 6c7dd5a1..00000000 --- a/Sources/Network/Connection/AttestedConnection.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) 2020-2021 MobileCoin. All rights reserved. -// - -import Foundation - -//class AttestedConnection { -// private let inner: SerialDispatchLock -// -// init(connectionOptionWrapper: ConnectionOptionWrapper, targetQueue: DispatchQueue?) { -// let inner = Inner(connectionOptionWrapper: connectionOptionWrapper) -// self.inner = .init(inner, targetQueue: targetQueue) -// } -// -// func setConnectionOptionWrapper(_ connectionOptionWrapper: ConnectionOptionWrapper) { -// inner.accessAsync { $0.connectionOptionWrapper = connectionOptionWrapper } -// } -// -// func setAuthorization(credentials: BasicCredentials) { -// inner.accessAsync { $0.setAuthorization(credentials: credentials) } -// } -//} -// -//extension AttestedConnection { -// private struct Inner { -// var connectionOptionWrapper: ConnectionOptionWrapper { -// didSet { -// if let credentials = authorizationCredentials { -// switch connectionOptionWrapper { -// case .grpc(grpcService: let grpcService): -// grpcService.setAuthorization(credentials: credentials) -// case .http(httpService: let httpService): -// httpService.setAuthorization(credentials: credentials) -// } -// } -// } -// } -// private var authorizationCredentials: BasicCredentials? -// -// init(connectionOptionWrapper: ConnectionOptionWrapper) { -// self.connectionOptionWrapper = connectionOptionWrapper -// } -// -// mutating func setAuthorization(credentials: BasicCredentials) { -// self.authorizationCredentials = credentials -// switch connectionOptionWrapper { -// case .grpc(grpcService: let grpcService): -// grpcService.setAuthorization(credentials: credentials) -// case .http(httpService: let httpService): -// httpService.setAuthorization(credentials: credentials) -// } -// } -// } -//} diff --git a/Sources/Network/Connection/Connection.swift b/Sources/Network/Connection/Connection.swift index 26993234..97102f4d 100644 --- a/Sources/Network/Connection/Connection.swift +++ b/Sources/Network/Connection/Connection.swift @@ -25,7 +25,7 @@ class Connection Void) { - completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)) - } - // indicates the server requested a client certificate. -// guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate else { -// logger.info("No cert needed") -// completionHandler(.performDefaultHandling, nil) -// return -// } - -// guard let trust = challenge.protectionSpace.serverTrust else { -// logger.info("no server trust") -// completionHandler(.performDefaultHandling, nil) -// return -// } -// -//// let isServerTrusted = SecTrustEvaluateWithError(serverTrust, nil) -// -// guard let host = url.host else { -// completionHandler(.performDefaultHandling, nil) -// return -// } -// -// -// guard let ourCertData = Data(base64Encoded: String.trustRootsB64) else { //, options: Data.Base64DecodingOptions.ignoreUnknownCharacters) else { -// completionHandler(.performDefaultHandling, nil) -// return -// } -// -// guard let certificate = SecCertificateCreateWithData(nil, ourCertData as CFData) else { -// completionHandler(.performDefaultHandling, nil) -// return -// } -// -//// // use certificate e.g. copy the public key -//// let publicKey = SecCertificateCopyKey(certificate)! -//// -//// guard let publicKeySec = SecKeyCreateWithData(ourCertData as! CFData, attributesRSAPub as CFDictionary, &error) else { -//// completionHandler(.performDefaultHandling, nil) -//// return -//// } -// let policy = SecPolicyCreateSSL(true, (host as CFString)) -// let basicPolicy = SecPolicyCreateBasicX509() -// let manualTrust = UnsafeMutablePointer.allocate(capacity: 1) -// if let serverCertificate = SecTrustGetCertificateAtIndex(trust, 0) { -// let certArray = Array(arrayLiteral:serverCertificate, certificate) -// let status = SecTrustCreateWithCertificates(certArray as AnyObject, policy, manualTrust) -// -// print(serverCertificate) -// print(certificate) -// print(certificate == serverCertificate) -// -// guard status == errSecSuccess else { return } -// -//// let trust = optionalTrust! -// -//// if let pointee = manualTrust.pointee, -//// let key = SecTrustCopyPublicKey(pointee) { -//// trustRoots.compactMap({ root in -//// try? root.extractPublicKey().toSPKIBytes() -//// }).forEach({print($0)}) -//// -//// print(key) -//// if pinnedKeys().contains(serverCertificateKey) { -//// completionHandler(.useCredential, URLCredential(trust: trust)) -//// return -//// } -//// } -// } -//// guard let file = Bundle(for: HTTPAccessURLSessionDelegate.self).url(forResource: p12Filename, withExtension: "p12"), -//// let p12Data = try? Data(contentsOf: file) else { -//// // Loading of the p12 file's data failed. -//// completionHandler(.performDefaultHandling, nil) -//// return -//// } -//// -//// // Interpret the data in the P12 data blob with -//// // a little helper class called `PKCS12`. -//// let password = "MyP12Password" // Obviously this should be stored or entered more securely. -//// let p12Contents = PKCS12(pkcs12Data: p12Data, password: password) -//// guard let identity = p12Contents.identity else { -//// // Creating a PKCS12 never fails, but interpretting th contained data can. So again, no identity? We fall back to default. -//// completionHandler(.performDefaultHandling, nil) -//// return -//// } -// -// // In my case, and as Apple recommends, -// // we do not pass the certificate chain into -// // the URLCredential used to respond to the challenge. -//// let credential = URLCredential(identity: identity, -//// certificates: nil, -//// persistence: .none) -//// challenge.sender?.use(credential, for: challenge) -//// completionHandler(.useCredential, credential) -// } -} - -extension String { - static let trustRootsB64 = - /// MobileCoin-managed Consensus and Fog services use Let's Encrypt with an intermediate - /// certificate that's cross-signed by IdenTrust's "DST Root CA X3": https://crt.sh/?d=8395 - """ - MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQKExtEaWdpdGF\ - sIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDT\ - IxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU\ - 1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxr\ - MMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoO\ - ifooUMM0RoOEqOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK\ - 3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40du\ - tolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB\ - /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqGSIb3DQEBBQUAA4I\ - BAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8fa\ - XbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ip\ - xZzR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wC\ - CZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ - """ -} - - -/* - all our keys are x509 certs - - certs include lots of info AND Public key - - certs have public and private key - - Im CA, gives me his certificate, then as CA I sign it, I hash his certificate and encrypt with my private key of my certificate. - - anyone who can decrypt their cert using the CA public key, and they can compare the hash of the leaf cert with the decrypted has using the CA public key. - - leaf certificate stored on device - - server will send you its certificate, usually sends the whole chain except root which is in the system. - - instead of including leaf cert, we include CA certificate. - - consensus TLS connection - - negotiate encryption key - - */ From 08cb5ec506c79a1f994253e7d3e3073930396712 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 7 Sep 2021 22:05:50 -0700 Subject: [PATCH 29/53] HTTP Requester Cleanup --- .../Connections/BlockchainConnection.swift | 2 +- .../Connections/ConsensusConnection.swift | 2 +- .../Connections/FogBlockConnection.swift | 2 +- .../Connections/FogKeyImageConnection.swift | 2 +- .../FogMerkleProofConnection.swift | 2 +- .../FogUntrustedTxOutConnection.swift | 2 +- .../Connections/FogViewConnection.swift | 2 +- .../AttestedHttpConnection.swift | 2 +- .../HttpConnection/HTTPInterface/HTTP.swift | 11 ---- .../HTTPInterface/HTTPCallOptions.swift | 7 +-- .../HTTPInterface/HTTPClient.swift | 7 ++- .../HTTPInterface/HTTPClientCall.swift | 16 +----- .../HTTPInterface/HTTPMethod.swift | 14 +++++ .../HTTPInterface/HTTPUnaryCall.swift | 7 +-- .../HttpConnection/HttpClientWrapper.swift | 56 ------------------- .../HttpConnection/HttpRequester.swift | 50 ----------------- 16 files changed, 35 insertions(+), 149 deletions(-) delete mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTP.swift create mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift delete mode 100644 Sources/Network/HttpConnection/HttpClientWrapper.swift diff --git a/Sources/Network/Connection/Connections/BlockchainConnection.swift b/Sources/Network/Connection/Connections/BlockchainConnection.swift index b5f3ecee..d6c01281 100644 --- a/Sources/Network/Connection/Connections/BlockchainConnection.swift +++ b/Sources/Network/Connection/Connections/BlockchainConnection.swift @@ -39,7 +39,7 @@ final class BlockchainConnection: } return .http(httpService: BlockchainHttpConnection( config: config, - requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + requester: RestApiRequester(requester: requester, baseUrl: config.url.httpBasedUrl), targetQueue: targetQueue)) } }, diff --git a/Sources/Network/Connection/Connections/ConsensusConnection.swift b/Sources/Network/Connection/Connections/ConsensusConnection.swift index c59d717d..7c48a2e9 100644 --- a/Sources/Network/Connection/Connections/ConsensusConnection.swift +++ b/Sources/Network/Connection/Connections/ConsensusConnection.swift @@ -46,7 +46,7 @@ final class ConsensusConnection: } return .http(httpService: ConsensusHttpConnection( config: config, - requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + requester: RestApiRequester(requester: requester, baseUrl: config.url.httpBasedUrl), targetQueue: targetQueue, rng: rng, rngContext: rngContext)) diff --git a/Sources/Network/Connection/Connections/FogBlockConnection.swift b/Sources/Network/Connection/Connections/FogBlockConnection.swift index 7fa7d220..58eaf7b7 100644 --- a/Sources/Network/Connection/Connections/FogBlockConnection.swift +++ b/Sources/Network/Connection/Connections/FogBlockConnection.swift @@ -38,7 +38,7 @@ final class FogBlockConnection: } return .http(httpService: FogBlockHttpConnection( config: config, - requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + requester: RestApiRequester(requester: requester, baseUrl: config.url.httpBasedUrl), targetQueue: targetQueue)) } }, diff --git a/Sources/Network/Connection/Connections/FogKeyImageConnection.swift b/Sources/Network/Connection/Connections/FogKeyImageConnection.swift index 4b87ab2c..30a6c096 100644 --- a/Sources/Network/Connection/Connections/FogKeyImageConnection.swift +++ b/Sources/Network/Connection/Connections/FogKeyImageConnection.swift @@ -46,7 +46,7 @@ final class FogKeyImageConnection: } return .http(httpService: FogKeyImageHttpConnection( config: config, - requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + requester: RestApiRequester(requester: requester, baseUrl: config.url.httpBasedUrl), targetQueue: targetQueue, rng: rng, rngContext: rngContext)) diff --git a/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift b/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift index fd4a16e8..801b13c3 100644 --- a/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift +++ b/Sources/Network/Connection/Connections/FogMerkleProofConnection.swift @@ -46,7 +46,7 @@ final class FogMerkleProofConnection: } return .http(httpService: FogMerkleProofHttpConnection( config: config, - requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + requester: RestApiRequester(requester: requester, baseUrl: config.url.httpBasedUrl), targetQueue: targetQueue, rng: rng, rngContext: rngContext)) diff --git a/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift b/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift index 1e6b4d5c..9ab42518 100644 --- a/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift +++ b/Sources/Network/Connection/Connections/FogUntrustedTxOutConnection.swift @@ -39,7 +39,7 @@ final class FogUntrustedTxOutConnection: } return .http(httpService: FogUntrustedTxOutHttpConnection( config: config, - requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + requester: RestApiRequester(requester: requester, baseUrl: config.url.httpBasedUrl), targetQueue: targetQueue)) } }, diff --git a/Sources/Network/Connection/Connections/FogViewConnection.swift b/Sources/Network/Connection/Connections/FogViewConnection.swift index 5e368626..e53da896 100644 --- a/Sources/Network/Connection/Connections/FogViewConnection.swift +++ b/Sources/Network/Connection/Connections/FogViewConnection.swift @@ -46,7 +46,7 @@ final class FogViewConnection: return .http( httpService: FogViewHttpConnection( config: config, - requester: RestApiRequester(requester: requester, baseUrl:config.url.httpBasedUrl), + requester: RestApiRequester(requester: requester, baseUrl: config.url.httpBasedUrl), targetQueue: targetQueue, rng: rng, rngContext: rngContext)) diff --git a/Sources/Network/HttpConnection/AttestedHttpConnection.swift b/Sources/Network/HttpConnection/AttestedHttpConnection.swift index db053a53..62aeefd8 100644 --- a/Sources/Network/HttpConnection/AttestedHttpConnection.swift +++ b/Sources/Network/HttpConnection/AttestedHttpConnection.swift @@ -338,7 +338,7 @@ extension AttestedHttpConnection { } private func requestCallOptions() -> HTTPCallOptions { - return HTTPCallOptions(headers: session.requestHeaders) + HTTPCallOptions(headers: session.requestHeaders) } private func processResponse(callResult: HttpCallResult) diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTP.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTP.swift deleted file mode 100644 index a23bb3a5..00000000 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTP.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) 2020-2021 MobileCoin. All rights reserved. -// - -import Foundation -import SwiftProtobuf - - -public enum HTTP { -// public typealias CallOptions = URLSessionConfiguration -} diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift index 186ad14b..1f4495f2 100644 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift @@ -4,13 +4,12 @@ import Foundation - public struct HTTPCallOptions { var headers: [String : String] - var timeoutIntervalForRequest : TimeInterval? = nil - var timeoutIntervalForResource : TimeInterval? = nil - + var timeoutIntervalForRequest : TimeInterval? + var timeoutIntervalForResource : TimeInterval? } + extension HTTPCallOptions { public init() { self.init(headers: [:], timeoutIntervalForRequest: 30, timeoutIntervalForResource: 30) diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift index c4fcf5e3..8b1ec974 100644 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift @@ -12,7 +12,12 @@ public protocol HTTPClient { } extension HTTPClient { - public func makeUnaryCall(path: String, request: Request, callOptions: HTTPCallOptions? = nil, responseType: Response.Type = Response.self) -> HTTPUnaryCall where Request : SwiftProtobuf.Message, Response : SwiftProtobuf.Message { + public func makeUnaryCall( + path: String, + request: Request, + callOptions: HTTPCallOptions? = nil, + responseType: Response.Type = Response.self + ) -> HTTPUnaryCall where Request : SwiftProtobuf.Message, Response : SwiftProtobuf.Message { HTTPUnaryCall(path: path, options: callOptions, requestPayload: request, responseType: responseType) } } diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift index f81326f3..1f1498a5 100644 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift @@ -30,22 +30,10 @@ public protocol HTTPClientCall { /// The options used to make the session. var options: HTTPCallOptions? { get } - /// Initial response metadata. + /// Response metadata. var metadata: HTTPURLResponse? { get } - /// Status of this call which may be populated by the server or client. + /// Status of this call. /// - /// The client may populate the status if, for example, it was not possible to connect to the service. - /// - /// Note: despite `GRPCStatus` conforming to `Error`, the value will be __always__ delivered as a __success__ - /// result even if the status represents a __negative__ outcome. This future will __never__ be fulfilled - /// with an error. var status: HTTPStatus? { get } - - /// Cancel the current call. - /// - /// Closes the HTTP/2 stream once it becomes available. Additional writes to the channel will be ignored. - /// Any unfulfilled promises will be failed with a cancelled status (excepting `status` which will be - /// succeeded, if not already succeeded). - func cancel() } diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift new file mode 100644 index 00000000..4fd020ba --- /dev/null +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift @@ -0,0 +1,14 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + +public enum HTTPMethod : String { + case GET = "GET" + case POST = "POST" + case PUT = "PUT" + case HEAD = "HEAD" + case PATCH = "PATCH" + case DELETE = "DELETE" +} diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift index eae465be..04a74196 100644 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift @@ -19,11 +19,8 @@ public struct HTTPUnaryCall) -> Void) { -// if let requester = httpRequester { -// requester.request( -// url: config.url.url, -// method: httpMethod, -// headers: headers, -// body: body) { httpResponse in -// switch httpResponse { -// case .success(let response): -// return completion(.success(response.responseData)) -// case .failure(let error): -// return completion(.failure(error)) -// } -// } -// } else { -// return completion( -// .failure(InvalidInputError("HttpRequester was not set in the Network config"))) -// } -// } -//} - -//public struct TestAuthCallable : AuthHttpCallable { -// func auth(_ request: Attest_AuthMessage, callOptions: HTTPCallOptions?, completion: @escaping (HttpCallResult) -> Void) { -// print("Implement") -// } -//} diff --git a/Sources/Network/HttpConnection/HttpRequester.swift b/Sources/Network/HttpConnection/HttpRequester.swift index 72fbacfb..211fd02c 100644 --- a/Sources/Network/HttpConnection/HttpRequester.swift +++ b/Sources/Network/HttpConnection/HttpRequester.swift @@ -17,15 +17,6 @@ public protocol HttpRequester { completion: @escaping (Result) -> Void) } -public enum HTTPMethod : String { - case GET = "GET" - case POST = "POST" - case PUT = "PUT" - case HEAD = "HEAD" - case PATCH = "PATCH" - case DELETE = "DELETE" -} - public struct HTTPResponse { public let httpUrlResponse: HTTPURLResponse public let responseData: Data? @@ -39,8 +30,6 @@ public struct HTTPResponse { } } -// - Add relative path component toe NetworkedMessage and then combine at runtime. - public class RestApiRequester { let requester: HttpRequester let baseUrl: URL @@ -52,7 +41,6 @@ public class RestApiRequester { self.requester = requester self.baseUrl = baseUrl self.trustRoots = trustRoots - self.challengeDelegate = ConnectionSessionTrust(url: baseUrl, trustRoots: trustRoots ?? []) } } @@ -239,41 +227,3 @@ extension NetworkingError: CustomStringConvertible { } } } - -//public class MyURLSessionDelegate: NSObject, URLSessionDelegate { -// public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { -// // `NSURLAuthenticationMethodClientCertificate` -// // indicates the server requested a client certificate. -// if challenge.protectionSpace.authenticationMethod -// != NSURLAuthenticationMethodClientCertificate { -// completionHandler(.performDefaultHandling, nil) -// return -// } -// -// guard let file = Bundle(for: HTTPAccessURLSessionDelegate.self).url(forResource: p12Filename, withExtension: "p12"), -// let p12Data = try? Data(contentsOf: file) else { -// // Loading of the p12 file's data failed. -// completionHandler(.performDefaultHandling, nil) -// return -// } -// -// // Interpret the data in the P12 data blob with -// // a little helper class called `PKCS12`. -// let password = "MyP12Password" // Obviously this should be stored or entered more securely. -// let p12Contents = PKCS12(pkcs12Data: p12Data, password: password) -// guard let identity = p12Contents.identity else { -// // Creating a PKCS12 never fails, but interpretting th contained data can. So again, no identity? We fall back to default. -// completionHandler(.performDefaultHandling, nil) -// return -// } -// -// // In my case, and as Apple recommends, -// // we do not pass the certificate chain into -// // the URLCredential used to respond to the challenge. -// let credential = URLCredential(identity: identity, -// certificates: nil, -// persistence: .none) -// challenge.sender?.use(credential, for: challenge) -// completionHandler(.useCredential, credential) -// } -//} From de821596e035201bbf28b798dbeef90041e644a6 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 7 Sep 2021 22:14:15 -0700 Subject: [PATCH 30/53] gs --- .../HTTPInterface/HTTPResponse.swift | 18 +++ .../HttpConnection/HttpRequester.swift | 122 +----------------- 2 files changed, 20 insertions(+), 120 deletions(-) create mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTPResponse.swift diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPResponse.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPResponse.swift new file mode 100644 index 00000000..41eab65f --- /dev/null +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPResponse.swift @@ -0,0 +1,18 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + +public struct HTTPResponse { + public let httpUrlResponse: HTTPURLResponse + public let responseData: Data? + + public var statusCode: Int { + httpUrlResponse.statusCode + } + + public var allHeaderFields: [AnyHashable: Any] { + httpUrlResponse.allHeaderFields + } +} diff --git a/Sources/Network/HttpConnection/HttpRequester.swift b/Sources/Network/HttpConnection/HttpRequester.swift index 211fd02c..822d19e2 100644 --- a/Sources/Network/HttpConnection/HttpRequester.swift +++ b/Sources/Network/HttpConnection/HttpRequester.swift @@ -17,19 +17,6 @@ public protocol HttpRequester { completion: @escaping (Result) -> Void) } -public struct HTTPResponse { - public let httpUrlResponse: HTTPURLResponse - public let responseData: Data? - - public var statusCode: Int { - httpUrlResponse.statusCode - } - - public var allHeaderFields: [AnyHashable: Any] { - httpUrlResponse.allHeaderFields - } -} - public class RestApiRequester { let requester: HttpRequester let baseUrl: URL @@ -109,10 +96,10 @@ fileprivate extension URL { fileprivate extension URLRequest { mutating func addProtoHeaders() { - let contentType = HTTPHeadersConstants.CONTENT_TYPE_PROTOBUF + let contentType = (fieldName:"Content-Type", value:"application/x-protobuf") self.setValue(contentType.value, forHTTPHeaderField: contentType.fieldName) - let accept = HTTPHeadersConstants.ACCEPT_PROTOBUF + let accept = (fieldName:"Accept", value:"application/x-protobuf") self.addValue(accept.value, forHTTPHeaderField: accept.fieldName) } @@ -122,108 +109,3 @@ fileprivate extension URLRequest { } } } - -struct HTTPHeadersConstants { - static var ACCEPT_PROTOBUF = (fieldName:"Accept", value:"application/x-protobuf") - static var CONTENT_TYPE_PROTOBUF = (fieldName:"Content-Type", value:"application/x-protobuf") -} - -extension Message { - func prettyPrintJSON() -> String { - guard let jsonData = try? self.jsonUTF8Data(), - let data = try? JSONSerialization.jsonObject(with: jsonData, options: []), - let object = try? JSONSerialization.data(withJSONObject: data, options: [.prettyPrinted]), - let prettyPrintedString = String(data: object, encoding: String.Encoding.utf8) else { - return "Unable to pretty print json" - } - return prettyPrintedString - } -} - -public enum HTTPResponseStatusCodeError : Error { - case unauthorized - case badRequest - case forbidden - case notFound - case unprocessableEntity - case internalServerError - case invalidResponseFromExternal - case unknown(Int) - - // TODO add other HTTP errors here - init(_ code: Int) { - switch code { - case 400: self = .badRequest - case 401: self = .unauthorized - case 403: self = .forbidden - case 404: self = .notFound - case 422: self = .unprocessableEntity - case 500: self = .internalServerError - case 502: self = .invalidResponseFromExternal - default: self = .unknown(code) - } - } - - var value : Int? { - switch self { - case .badRequest: return 400 - case .unauthorized: return 401 - case .forbidden: return 403 - case .notFound: return 404 - case .unprocessableEntity: return 422 - case .internalServerError: return 500 - case .invalidResponseFromExternal: return 502 - default: return nil - } - } -} - -extension HTTPResponseStatusCodeError : CustomStringConvertible { - public var localizedDescription: String { - return description - } - - public var description: String { - switch self { - case .badRequest: return "The request is malformed (ex. missing or incorrect parameters)" - case .unauthorized: return "Failed to provide proper authentication with the request." - case .forbidden: return "The action in the request is not allowed." - case .notFound: return "Not Found" - case .unprocessableEntity: return "The server understands the content type of the request entity, and the syntax of the request entity is correct, but it was unable to process the contained instructions." - case .internalServerError: return "Unhandled exception from one of the other services: the Database, FTX, or the Full Service Wallet." - case .invalidResponseFromExternal: return "The server was acting as a gateway or proxy and received an invalid response from the upstream server (ie. one of the other services: the Database, FTX, or the Full Service Wallet.)" - case .unknown(let code): return "HTTP Response code \(code)" - } - } -} - -extension HTTPResponseStatusCodeError : Equatable { - public static func == (lhs: HTTPResponseStatusCodeError, rhs: HTTPResponseStatusCodeError) -> Bool { - switch (lhs, rhs) { - case (.unknown(let lhsValue), .unknown(let rhsValue)): - return lhsValue == rhsValue - default: - return lhs.value ?? -1 == rhs.value ?? -1 - } - } -} - -public enum NetworkingError: Error { - case unknownDecodingError - case noResponseStatus - case noResponse - case unknown - case noData -} - -extension NetworkingError: CustomStringConvertible { - public var description : String { - switch self { - case .noResponseStatus: return "Response status not explicitly set in proto response" - case .noResponse: return "URLResponse object is nil" - case .unknownDecodingError: return "Unknown decoding error" - case .unknown: return "Unknown netowrking error" - case .noData: return "No data in resposne" - } - } -} From 34f84d212742c25df06f59641d4fc69e0a5721b4 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 7 Sep 2021 22:14:42 -0700 Subject: [PATCH 31/53] Cleanup HttpRequester remove unused and unecc. code. Breakout types into their own files --- Sources/Network/HttpConnection/HttpRequester.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Network/HttpConnection/HttpRequester.swift b/Sources/Network/HttpConnection/HttpRequester.swift index 822d19e2..53985ed1 100644 --- a/Sources/Network/HttpConnection/HttpRequester.swift +++ b/Sources/Network/HttpConnection/HttpRequester.swift @@ -24,14 +24,14 @@ public class RestApiRequester { let prefix: String = "gw" var challengeDelegate: URLSessionDelegate? - public init(requester: HttpRequester, baseUrl: URL, trustRoots: [NIOSSLCertificate]? = []) { + init(requester: HttpRequester, baseUrl: URL, trustRoots: [NIOSSLCertificate]? = []) { self.requester = requester self.baseUrl = baseUrl self.trustRoots = trustRoots } } -public protocol Requester { +protocol Requester { func makeRequest(call: T, completion: @escaping (HttpCallResult) -> Void) } From e17468ccb9e77a9646c518366bb98a223e03e410 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 7 Sep 2021 22:29:46 -0700 Subject: [PATCH 32/53] Tighten up HTTP errors --- .../HTTPInterface/HTTPStatus.swift | 62 ++++++++++++++++ Sources/Utils/HTTP/HttpCallResult.swift | 73 ------------------- 2 files changed, 62 insertions(+), 73 deletions(-) create mode 100644 Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift new file mode 100644 index 00000000..3584993d --- /dev/null +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift @@ -0,0 +1,62 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation +import GRPC + +/// Encapsulates the result of a HTTP call. +public struct HTTPStatus : Error { + + /// The REST status code + public var code: Int + + /// The status message + public var message: String? + + /// Whether the status is '.ok'. + public var isOk: Bool { + (200...299).contains(code) + } + + /// The default status to return for succeeded calls. + /// + /// - Important: This should *not* be used when checking whether a returned status has an 'ok' + /// status code. Use `HTTPStatus.isOk` or check the code directly. + public static let ok: HTTPStatus = .init(code: 200, message: "Success") + + /// "Internal server error" status. + public static let processingError: HTTPStatus = .init(code: 500, message: "Error") +} + +extension HTTPStatus : CustomStringConvertible { + public var description : String { + codeDescription + (message ?? "") + } + + private var codeDescription : String { + switch code { + case 1: + return "Unknown Error: " + case 200: + return "Success: " + case 400: + return "Invalid Arguments: " + case 403: + return "Unauthorized: " + case 404: + return "Not Found: " + case 500: + return "Error: " + case 501: + return "Unimplemented: " + case 503: + return "Unavailable: " + default: + return "" + } + } +} + + + diff --git a/Sources/Utils/HTTP/HttpCallResult.swift b/Sources/Utils/HTTP/HttpCallResult.swift index 8f5543e9..3ed2a9f7 100644 --- a/Sources/Utils/HTTP/HttpCallResult.swift +++ b/Sources/Utils/HTTP/HttpCallResult.swift @@ -23,76 +23,3 @@ extension HttpCallResult { } } -/// Encapsulates the result of a HTTP call. -public struct HTTPStatus : Error { - - /// The status code of the RPC. - public var code: Int - - /// The status message of the RPC. - public var message: String? - - /// Whether the status is '.ok'. - public var isOk: Bool { - (200...299).contains(code) - } - - /// The default status to return for succeeded calls. - /// - /// - Important: This should *not* be used when checking whether a returned status has an 'ok' - /// status code. Use `HTTPStatus.isOk` or check the code directly. - public static let ok: HTTPStatus = .init(code: 200, message: "Success") - - /// "Internal server error" status. - public static let processingError: HTTPStatus = .init(code: 500, message: "Error") -} - -extension HTTPStatus { - init(grpcStatus: GRPCStatus) { - self.init(code: grpcStatus.isOk ? 200 : 500, message: grpcStatus.message) - } - - func temp(code: GRPCStatus.Code) -> Int{ - switch code { - case .ok: - return 200 - case .cancelled: - return 500 - case .unknown: - return 500 - case .invalidArgument: - return 400 - case .deadlineExceeded: - return 504 - case .notFound: - return 404 - case .alreadyExists: - return 409 - case .permissionDenied: - return 403 - case .resourceExhausted: - return 400 - case .failedPrecondition: - return 412 - case .aborted: - return 500 - case .outOfRange: - return 400 - case .unimplemented: - return 501 - case .internalError: - return 500 - case .unavailable: - return 503 - case .dataLoss: - return 500 - case .unauthenticated: - return 403 - default: - return 500 - } - } -} - - - From df0ad0181d9050aac37d1c84e3d9c0aca231e431 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 7 Sep 2021 22:32:38 -0700 Subject: [PATCH 33/53] More cleanup for SwiftLintgs --- .../HttpConnection/HTTPInterface/HTTPMethod.swift | 12 ++++++------ .../HttpConnection/HTTPInterface/HTTPStatus.swift | 7 ++----- Sources/Utils/HTTP/HttpCallResult.swift | 1 - 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift index 4fd020ba..91e581c9 100644 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift @@ -5,10 +5,10 @@ import Foundation public enum HTTPMethod : String { - case GET = "GET" - case POST = "POST" - case PUT = "PUT" - case HEAD = "HEAD" - case PATCH = "PATCH" - case DELETE = "DELETE" + case GET + case POST + case PUT + case HEAD + case PATCH + case DELETE } diff --git a/Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift b/Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift index 3584993d..04937b93 100644 --- a/Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift +++ b/Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift @@ -30,11 +30,11 @@ public struct HTTPStatus : Error { } extension HTTPStatus : CustomStringConvertible { - public var description : String { + public var description: String { codeDescription + (message ?? "") } - private var codeDescription : String { + private var codeDescription: String { switch code { case 1: return "Unknown Error: " @@ -57,6 +57,3 @@ extension HTTPStatus : CustomStringConvertible { } } } - - - diff --git a/Sources/Utils/HTTP/HttpCallResult.swift b/Sources/Utils/HTTP/HttpCallResult.swift index 3ed2a9f7..066faf3d 100644 --- a/Sources/Utils/HTTP/HttpCallResult.swift +++ b/Sources/Utils/HTTP/HttpCallResult.swift @@ -18,7 +18,6 @@ extension HttpCallResult { init( status: HTTPStatus ) { - // TODO REMOVE self.init(status: status, metadata: nil, response: nil) } } From bc4887f445432c4c4b16d8622c7ff6109ff10112 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Wed, 8 Sep 2021 16:36:05 -0700 Subject: [PATCH 34/53] match libmobilecoin repo --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index b9c24dd7..6c951921 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit b9c24dd715beca4b700ebe08d3044e2013352e6a +Subproject commit 6c951921ac2f7536b3ab5ecf995f73651a490b20 From 6d7935cfc4b12195cda1a2cf565de82e33bddf16 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Mon, 13 Sep 2021 23:41:40 -0700 Subject: [PATCH 35/53] reset back to m1/compressed commitment working and then keep all new network robustness cleanup --- .../Connection/AttestedCallError.swift | 24 +++ .../GrpcCallable/AttestedGrpcCallable.swift | 18 -- .../HttpCallable/AttestedHttpCallable.swift | 18 -- .../AuthHttpCallableClientWrapper.swift | 42 +---- .../HttpClient/AuthHttpCallableClient.swift | 13 -- Sources/Transaction/Receipt.swift | 27 +-- Sources/Utils/MobileCoin-Bridging-Header.h | 18 -- Sources/Utils/TestBridgingHeader.h | 11 -- Sources/Utils/TestBridgingHeader.m | 16 -- TERMS-OF-USE.md | 170 ++++++------------ 10 files changed, 82 insertions(+), 275 deletions(-) create mode 100644 Sources/Network/Connection/AttestedCallError.swift delete mode 100644 Sources/Utils/MobileCoin-Bridging-Header.h delete mode 100644 Sources/Utils/TestBridgingHeader.h delete mode 100644 Sources/Utils/TestBridgingHeader.m diff --git a/Sources/Network/Connection/AttestedCallError.swift b/Sources/Network/Connection/AttestedCallError.swift new file mode 100644 index 00000000..854a2637 --- /dev/null +++ b/Sources/Network/Connection/AttestedCallError.swift @@ -0,0 +1,24 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +import Foundation + +enum AttestedCallError: Error { + case aeadError(AeadError) + case invalidInput(String) +} + +extension AttestedCallError: CustomStringConvertible { + var description: String { + "Attested call error: " + { + switch self { + case .aeadError(let innerError): + return "\(innerError)" + case .invalidInput(let reason): + return "Invalid input: \(reason)" + } + }() + } +} + diff --git a/Sources/Network/GrpcConnection/GrpcCallable/AttestedGrpcCallable.swift b/Sources/Network/GrpcConnection/GrpcCallable/AttestedGrpcCallable.swift index dbee7797..103f6536 100644 --- a/Sources/Network/GrpcConnection/GrpcCallable/AttestedGrpcCallable.swift +++ b/Sources/Network/GrpcConnection/GrpcCallable/AttestedGrpcCallable.swift @@ -6,24 +6,6 @@ import Foundation import LibMobileCoin import SwiftProtobuf -enum AttestedCallError: Error { - case aeadError(AeadError) - case invalidInput(String) -} - -extension AttestedCallError: CustomStringConvertible { - var description: String { - "Attested call error: " + { - switch self { - case .aeadError(let innerError): - return "\(innerError)" - case .invalidInput(let reason): - return "Invalid input: \(reason)" - } - }() - } -} - protocol AttestedGrpcCallable: GrpcCallable { associatedtype InnerRequestAad = () associatedtype InnerRequest diff --git a/Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift b/Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift index bc810437..c0b2e497 100644 --- a/Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift +++ b/Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift @@ -6,24 +6,6 @@ import Foundation import LibMobileCoin import SwiftProtobuf -//enum AttestedCallError: Error { -// case aeadError(AeadError) -// case invalidInput(String) -//} -// -//extension AttestedCallError: CustomStringConvertible { -// var description: String { -// "Attested call error: " + { -// switch self { -// case .aeadError(let innerError): -// return "\(innerError)" -// case .invalidInput(let reason): -// return "Invalid input: \(reason)" -// } -// }() -// } -//} - protocol AttestedHttpCallable: HttpCallable { associatedtype InnerRequestAad = () associatedtype InnerRequest diff --git a/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift b/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift index 3dca7fd3..6f950240 100644 --- a/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift +++ b/Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift @@ -1,52 +1,12 @@ // // Copyright (c) 2020-2021 MobileCoin. All rights reserved. // +// swiftlint:disable all import Foundation import LibMobileCoin -///// A HTTP client. -//public protocol HTTPClient { -// /// The call options to use should the user not provide per-call options. -// var defaultHTTPCallOptions: HTTPCallOptions { get set } -//} -// -//extension HTTPClient { -// public func makeUnaryCall(path: String, request: Request, callOptions: HTTPCallOptions? = nil, responseType: Response.Type = Response.self) -> HTTPUnaryCall where Request : SwiftProtobuf.Message, Response : SwiftProtobuf.Message { -// HTTPUnaryCall(path: path, options: callOptions, requestPayload: request, responseType: responseType) -// } -//} - -//protocol AuthHttpCallableClient: AttestableHttpClient, AuthHttpCallable { -// func auth(_ request: Attest_AuthMessage, callOptions: HTTPCallOptions?) -// -> HTTPUnaryCall -//} -// -//extension AuthHttpCallableClient { -// var authCallable: AuthHttpCallable { -// self -// } -//} -// -//extension AuthHttpCallableClient { -// func auth( -// _ request: Attest_AuthMessage, -// callOptions: HTTPCallOptions?, -// completion: @escaping (HttpCallResult) -> Void -// ) { -// let clientCall = auth(request, callOptions: callOptions) -// requester.makeRequest(call: clientCall) { result in -// switch result { -// case .success(let callResult): -// completion(callResult) -// case .failure(let error): -// logger.error(error.localizedDescription) -// } -// } -// } -//} - protocol AuthQueryHttpCalleeAndClient : QueryHttpCallee, AuthHttpCallee, HTTPClient {} struct AuthHttpCallableClientWrapper: AuthHttpCallableClient, HTTPClient { diff --git a/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift b/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift index faed6fd5..f80cba2b 100644 --- a/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift +++ b/Sources/Network/HttpConnection/HttpClient/AuthHttpCallableClient.swift @@ -27,16 +27,3 @@ extension AuthHttpCallableClient { requester.makeRequest(call: clientCall, completion: completion) } } - -///// A HTTP client. -//public protocol HTTPClient { -// /// The call options to use should the user not provide per-call options. -// var defaultHTTPCallOptions: HTTPCallOptions { get set } -//} -// -//extension HTTPClient { -// public func makeUnaryCall(path: String, request: Request, callOptions: HTTPCallOptions? = nil, responseType: Response.Type = Response.self) -> HTTPUnaryCall where Request : SwiftProtobuf.Message, Response : SwiftProtobuf.Message { -// HTTPUnaryCall(path: path, options: callOptions, requestPayload: request, responseType: responseType) -// } -//} -// diff --git a/Sources/Transaction/Receipt.swift b/Sources/Transaction/Receipt.swift index 570de630..663cf604 100644 --- a/Sources/Transaction/Receipt.swift +++ b/Sources/Transaction/Receipt.swift @@ -65,7 +65,7 @@ public struct Receipt { } func matchesTxOut(_ txOut: TxOutProtocol) -> Bool { - return txOutPublicKeyTyped == txOut.publicKey + txOutPublicKeyTyped == txOut.publicKey && commitment == txOut.commitment && maskedValue == txOut.maskedValue } @@ -163,28 +163,3 @@ extension External_Receipt { self.tombstoneBlock = receipt.txTombstoneBlockIndex } } - - -extension Data32 { - struct HexEncodingOptions: OptionSet { - let rawValue: Int - static let upperCase = HexEncodingOptions(rawValue: 1 << 0) - } - - func hexEncodedString(options: HexEncodingOptions = []) -> String { - let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx" - return self.map { String(format: format, $0) }.joined() - } -} - -extension Data { - struct HexEncodingOptions: OptionSet { - let rawValue: Int - static let upperCase = HexEncodingOptions(rawValue: 1 << 0) - } - - func hexEncodedString(options: HexEncodingOptions = []) -> String { - let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx" - return self.map { String(format: format, $0) }.joined() - } -} diff --git a/Sources/Utils/MobileCoin-Bridging-Header.h b/Sources/Utils/MobileCoin-Bridging-Header.h deleted file mode 100644 index d3bf134e..00000000 --- a/Sources/Utils/MobileCoin-Bridging-Header.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) 2020-2021 MobileCoin. All rights reserved. -// - -#ifndef MobileCoin_Bridging_Header_h -#define MobileCoin_Bridging_Header_h - - -#endif /* MobileCoin_Bridging_Header_h */ - -#ifndef TestBridgingHeader_h -#define TestBridgingHeader_h - - - -#endif /* TestBridgingHeader_h */ - -#include "TestBridgingHeader.h" diff --git a/Sources/Utils/TestBridgingHeader.h b/Sources/Utils/TestBridgingHeader.h deleted file mode 100644 index 84d42480..00000000 --- a/Sources/Utils/TestBridgingHeader.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) 2020-2021 MobileCoin. All rights reserved. -// - -#import - -@interface TestBridgingHeader : NSObject - -- (id)init; - -@end diff --git a/Sources/Utils/TestBridgingHeader.m b/Sources/Utils/TestBridgingHeader.m deleted file mode 100644 index 0957ea22..00000000 --- a/Sources/Utils/TestBridgingHeader.m +++ /dev/null @@ -1,16 +0,0 @@ -// -// Copyright (c) 2020-2021 MobileCoin. All rights reserved. -// - -#import - -#include "TestBridgingHeader.h" - -@implementation TestBridgingHeader - -- (id)init -{ - return self; -} - -@end diff --git a/TERMS-OF-USE.md b/TERMS-OF-USE.md index 2b88aea2..1ed75ba9 100644 --- a/TERMS-OF-USE.md +++ b/TERMS-OF-USE.md @@ -1,190 +1,132 @@ -**MobileCoins are not offered or sold to U.S. Persons or entities or other Prohibited Persons regardless of their location. Purchasers of MobileCoins may not transact, transfers, or trade MobileCoins in the United States or with U.S. Persons or entities, or persons or entities present in the United States.** +# **TERMS OF USE** **FOR MOBILECOINS AND MOBILECOIN WALLETS** -# TERMS OF USE FOR MOBILECOINS AND MOBILECOIN WALLETS - -The MobileCoin Network operates utilizing an open source software protocol commonly known as the MobileCoin protocol. The MobileCoin protocol is designed to enable holders of digital tokens known as MobileCoins to send and receive peer-to-peer payments securely and privately through a digital wallet that is capable of sending and receiving MobileCoins (MobileCoin Wallets). MobileCoins enable a simple, secure, and private medium of exchange for consumers in countries of operation to manage and move their money using personal mobile devices and a currency of equivalent value across countries. +The MobileCoin Network uses an open source software protocol commonly known as the MobileCoin protocol. The MobileCoin protocol is designed to enable holders of digital tokens known as MobileCoins to send and receive peer-to-peer payments securely and privately through a digital wallet that can send and receive MobileCoins (MobileCoin Wallets). MobileCoins and MobileCoin Wallets enable a simple, secure, and private medium of exchange for consumers in countries of operation to manage and move their money using a currency of equivalent value across countries. These Terms of Use for MobileCoins and MobileCoin Wallets (Terms) govern: + - MobileCoins and their use and transfer; and - MobileCoin Wallets and their access and use. -Please read these Terms carefully before you start to use any MobileCoins and any MobileCoin Wallet. By acquiring or otherwise obtaining MobileCoins, using or transferring MobileCoins or obtaining, accessing or using a MobileCoin Wallet, you acknowledge that you have read, understand, and completely agree to be bound by these Terms. You also agree to require any transferee of your MobileCoins and any holder of a MobileCoin Wallet facilitated by you to be subject to these Terms. These Terms may be enforced against you by MobileCoin TS Ltd. or other authorized entities (which are collectively referred to in these Terms as the Compliance Entities). These Terms may be amended, changed, or updated by the Compliance Entities at any time and without prior notice to you by posting at the MobileCoin TS Ltd. Website at http://www.buymobilecoin.com/. Your continued use of any MobileCoins and any MobileCoin Wallets following the posting of any amendment, change, or update means that you accept and agree to the amended, changed, or updated Terms. These Terms are first effective as of November 23, 2020. +Please read these Terms carefully before you start to use any MobileCoins and any MobileCoin Wallet. By acquiring or otherwise obtaining MobileCoins, using or transferring MobileCoins or obtaining, accessing or using a MobileCoin Wallet, you acknowledge that you have read, understand, and completely agree to be bound by these Terms. You also agree to require any transferee of your MobileCoins and any holder of a MobileCoin Wallet facilitated by you to be subject to these Terms. These Terms may be enforced against you by MobileCoin TS Ltd., MobileCoin U.S., LLC or other authorized entities (which are collectively referred to in these Terms as the Compliance Entities). These Terms may be amended, changed, or updated by the Compliance Entities at any time and without prior notice to you by posting at [www.buymobilecoin.us](https://www.buymobilecoin.us/). Your continued use of any MobileCoins and any MobileCoin Wallets following the posting of any amendment, change, or update means that you accept and agree to the amended, changed, or updated Terms. These Terms are first effective as of August 17, 2021 and supersede any previous versions. -Access or use of any MobileCoin Wallets or use or transfer of any MobileCoins is void where such access, use or transfer is prohibited by, would constitute a violation of, or would be subject to penalties under applicable laws, and will not be the basis for the assertion or recognition of any interest, right, remedy, power, or privilege. Please also consult the Terms of Sale and Access and Use of the Site, available at the MobileCoin TS Ltd. website at http://www.buymobilecoin.com/. Information on the way personal information is handled is included in the Privacy Policy, available at http://www.buymobilecoin.com/. +Access or use of any MobileCoin Wallets or use or transfer of any MobileCoins is void where such access, use or transfer is prohibited by, would constitute a violation of, or would be subject to penalties under applicable laws. Such access or use of MobileCoin Wallets or use or transfer of any MobileCoins which is void will not be the basis for the assertion or recognition of any interest, right, remedy, power, or privilege. \[Please also consult the applicable Terms of Sale and Access and Use of the Site, available at the MobileCoin U.S. LLC website at [www.buymobilecoin.us](https://www.buymobilecoin.us/) or the MobileCoin TS Ltd. website at [www.buymobilecoin.com](https://www.buymobilecoin.com). Information on the way personal information is handled is included in the appropriate Privacy Policy, available at [www.buymobilecoin.us](https://www.buymobilecoin.us/) or [www.buymobilecoin.com](https://www.buymobilecoin.com/).\] -## Limitations on Access or Use of MobileCoin Wallets and Use and Transfer of MobileCoins +## **Limitations on Access or Use of MobileCoin Wallets and Use and Transfer of MobileCoins** -The right to access or use MobileCoin Wallets and use or transfer MobileCoins is a personal, restricted, non-exclusive, non-transferable, non-sublicensable, revocable, limited license, and it is subject to the limitations and obligations in these Terms. Every **Prohibited Person** and **U.S. Person** is strictly prohibited from directly or indirectly transacting, transferring, holding, owning, accessing or using any MobileCoins and any MobileCoin Wallets in any way. - -You are a **Prohibited Person** if you are: -1. an individual or entity present in or subject to the jurisdiction of any jurisdiction in which the distribution or offer of or transaction in MobileCoins is unlawful or who is restricted or prohibited by applicable law, including without limitation, anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, and economic sanctions laws, from purchasing or otherwise obtaining MobileCoins or transacting in MobileCoins; +The right to access or use MobileCoin Wallets and use or transfer MobileCoins is a personal, restricted, non-exclusive, non-sublicensable, revocable, limited license, and it is subject to the limitations and obligations in these Terms. Every Prohibited Person is strictly prohibited from directly or indirectly transacting, transferring, holding, owning, accessing or using any MobileCoins and any MobileCoin Wallets in any way. -2. an individual or entity present in or subject to the jurisdiction of Cuba, Democratic People’s Republic of Korea (North Korea), Iran, Syria or Crimea (a region of Ukraine annexed by the Russian Federation) (a Prohibited Jurisdiction); - -3. a government or government official of any Prohibited Jurisdiction or of Venezuela or any subdivision thereof; - -4. an individual or entity subject to asset freezing or blocking sanctions imposed by the United Nations, British Virgin Islands, United Kingdom, European Union, or United States or any entity owned 50 percent or more by one or more such persons (a Sanctioned Person); +You are a Prohibited Person if you are: +1. an individual or entity present in or subject to the jurisdiction of any jurisdiction in which the distribution or offer of or transaction in MobileCoins is unlawful or who is restricted or prohibited by applicable law, including without limitation, anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, and economic sanctions laws, from purchasing or otherwise obtaining MobileCoins or transacting in MobileCoins; +2. an individual or entity present in or subject to the jurisdiction of Cuba, Democratic People's Republic of Korea (North Korea), Iran, Syria or Crimea (a region of Ukraine annexed by the Russian Federation) (a Prohibited Jurisdiction); +3. a government or government official of any Prohibited Jurisdiction or of Venezuela or any subdivision thereof; +4. an individual or entity subject to asset freezing or blocking sanctions imposed by the United Nations, British Virgin Islands, United Kingdom, European Union, or United States or any entity owned 50 percent or more by one or more such persons (a Sanctioned Person); 5. a person under 18 years of age; or - 6. any other individual or entity whose dealings in MobileCoins or use of a MobileCoin Wallet could expose the Compliance Entities to civil or criminal liability or cause the Compliance Entities to engage in sanctionable conduct. -You are a **“U.S. Person”** if you are: -1. (i) a U.S. citizen, (ii) a U.S. lawful permanent resident, protected individual or asylee under the U.S. Immigration and Nationality Act, (iii) an individual present in the U.S. in a non-immigrant status which carries an allowable admission period exceeding 6 months, (iv) an individual or entity present in the U.S., or (v) an individual or entity acting for the financial or other benefit of or on behalf of any U.S. Person; - -2. a corporation, partnership, or other entity established or organized in or under the laws of the United States; - -3. a corporation, partnership, or other entity formed by a U.S. Person principally for the purpose of investing in securities, unless it is organized or incorporated, and owned, by accredited investors who are not natural persons, estates or trusts; - -4. an estate of which any executor or administrator is a U.S. Person (unless this executor or administrator is a professional fiduciary and shares with a non-U.S. Person investment discretion with respect to the assets of an estate that is governed by foreign law); - -5. a trust if the trustee is a U.S. Person (unless this trustee is a professional fiduciary and shares with a non-U.S. Person investment discretion with respect to the trust assets and no beneficiary of the trust (and no settlor if the trust is revocable) is a U.S. Person); - -6. an agency or branch of a non-U.S. entity located in the U.S.; +## **MobileCoin Wallets** -7. a non-discretionary account or similar account held by a dealer or other fiduciary for the benefit or account of a U.S. Person; +No MobileCoin Wallet may be operated for and no order or transaction in a MobileCoin Wallet may be used for the financial or other benefit of or on behalf of a Prohibited Person. Persons, whether or not Prohibited Persons, are prohibited from operating a MobileCoin Wallet in any way or otherwise transacting on or using any MobileCoins and any MobileCoin Wallets while they or any individual (including any fiduciary, dealer, trustee, executor or administrator), agency or branch operating their MobileCoin Wallet on their behalf is present in any jurisdiction in which MobileCoins are unlawful. -8. any discretionary account or similar account held by a dealer or other fiduciary organized, incorporated, or resident in the U.S. (held for the exclusive benefit or account of non-U.S. Persons); or - -9. any government or government official of the United States. - -In these Terms, United States or U.S. means the several states of the United States of America, the District of Columbia, Puerto Rico, the Virgin Islands, and the insular possessions of the United States of America. - -## MobileCoin Wallets - -No MobileCoin Wallet may be operated for and no order or transaction in a MobileCoin Wallet may be for the financial or other benefit of or on behalf of a Prohibited Person or U.S. Person. Persons, whether or not Prohibited Persons, are prohibited from operating a MobileCoin Wallet in any way or otherwise transacting on or using any MobileCoins and any MobileCoin Wallets while they or any individual (including any fiduciary, dealer, trustee, executor or administrator), agency or branch operating their MobileCoin Wallet on their behalf is present in the United States or any jurisdiction in which MobileCoins are unlawful. - -Certain software comprising MobileCoin Wallets is available to the public without charge on an open source basis. This software is provided “as is” and “as available,” without warranty of any kind. However, MobileCoin Wallets linked to a Signal mobile messaging application or any other mobile messaging applications may integrate software from a third party. MobileCoin Wallets must be accessed through a telephone, computer or other equipment as well as a network connection through telecommunication lines or other utility. None of these components of the MobileCoin Wallet is provided or controlled by the Compliance Entities. The Compliance Entities and their Associates are not responsible for the accuracy or reliability of any open-source software or of any software, hardware, information, or advice provided by third parties or for their privacy and security policies and procedures. +Certain software comprising MobileCoin Wallets is available to the public without charge on an open source basis. This software is provided "as is" without warranty of any kind. However, MobileCoin Wallets linked to a mobile messaging application may integrate software from a third party. MobileCoin Wallets must be accessed through a telephone, computer or other equipment as well as a network connection through telecommunication lines or other utility. None of these components of the MobileCoin Wallet is provided or controlled by the Compliance Entities. The Compliance Entities are not responsible for the accuracy or reliability of any open-source software or of any software, hardware, information, or advice provided by third parties or for their privacy and security policies and procedures. Access to and use of your MobileCoin Wallet may from time to time be unavailable, delayed, limited or slowed due to failures of hardware, software, utility services or other causes outside the control of the Compliance Entities. You may suffer losses as a result of these delays and limitations. You assume all risks associated with the operation, performance and security of a MobileCoin Wallet. You are responsible for maintaining the security of your MobileCoin Wallet and any password or other security designed to limit access. -In addition to these Terms, you may be bound by any additional terms required by your third-party providers. These third parties’ terms may apply to your use of the MobileCoin Wallets. Please be aware that these Terms do not govern third parties’ relationships with you. These third parties, and not any Compliance Entity, are responsible for any product or service warranties, whether express or implied by law, provided to you. +In addition to these Terms, you may be bound by any additional terms required by your third-party providers. These third parties' terms may apply to your use of the MobileCoin Wallets. Please be aware that these Terms do not govern third parties' relationships with you. These third parties, and not any Compliance Entity, are responsible for any product or service warranties, whether express or implied by law, provided to you. -## Nature of MobileCoins and Transactions in MobileCoins +## **Nature of MobileCoins and Transactions in MobileCoins** -MobileCoins are digital tokens. Digital tokens such as MobileCoins are not legal tender, are not backed by any government, and are not insured. MobileCoins do not provide you with any ownership of any physical asset or ownership or other interest or rights of any form with respect to the Compliance Entities or any affiliate or its revenue or assets, including any voting, distribution, redemption, liquidation, proprietary (including all forms of intellectual property), or other financial or legal rights. MobileCoins are distributed and offered on an as-is, where-is basis and, without limiting the generality of the foregoing, are offered without any representation as to merchantability or fitness for any particular purpose. +MobileCoins are digital tokens. Digital tokens such as MobileCoins are not legal tender, are not backed by any government, and are not insured. MobileCoins do not provide you with any ownership of any physical asset or ownership or other interest or rights of any form with respect to the Compliance Entities or any affiliate or its revenue or assets, including any voting, distribution, redemption, liquidation, proprietary (including all forms of intellectual property), or other financial or legal rights. MobileCoins are distributed and offered on an as-is, and, are offered without any representation as to merchantability or fitness for any particular purpose. -You accept that the Compliance Entities may be required to share your user information with other contractual third parties, including financial institutions, or as required under applicable laws or demanded upon a lawful request by any government. When information includes personal data under European Union law, the terms of the Privacy Policy will apply. Please consult the Privacy Policy available at the MobileCoin TS Ltd. website at http://www.buymobilecoin.com/. +You accept that the Compliance Entities may be required to share your user information with other contractual third parties, including financial institutions, or as required under applicable laws or demanded upon a lawful request by any government. When information includes personal data under European Union law and/or California law, the terms of the Privacy Policy will apply. Please consult the appropriate Privacy Policy available at [www.buymobilecoin.us](https://www.buymobilecoin.us/) and [www.buymobilecoin.com](https://www.buymobilecoin.com/). -You accept all consequences of sending MobileCoins. MobileCoin transactions are not reversible. Once you send MobileCoins to an address, whether intentionally or by a fraudulent or accidental transaction, you accept the risk that you may lose access to, and any claim on, those MobileCoins indefinitely or permanently. +You accept all consequences of sending MobileCoins. MobileCoin transactions are not reversible or refundable. Once you send MobileCoins to an address, whether intentionally or by a fraudulent or accidental transaction, you accept the risk that you may lose access to, and any claim on, those MobileCoins indefinitely or permanently. -## Prohibited Uses and Transfers of MobileCoins and Uses of MobileCoin Wallets +## **Prohibited Uses and Transfers of MobileCoins and Uses of MobileCoin Wallets** You may not: -- use or transfer MobileCoins or access or use a MobileCoin Wallet in order to disguise the origin or nature of illicit proceeds of, or to further, any breach of applicable laws, or to transact or deal in any contraband funds, property, or proceeds; +- use or transfer MobileCoins or access or use a MobileCoin Wallet for any illegal purposes; +- use or transfer MobileCoins or access or use a MobileCoin Wallet in order to disguise the origin or nature of illicit proceeds of, or to further, any breach of applicable laws, or to transact or deal in any contraband funds, property, or proceeds; - use or transfer MobileCoins or access or use a MobileCoin Wallet if such conduct is prohibited, penalized, or otherwise sanctionable under any applicable laws, including without limitation anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, and economic sanctions laws or would expose the Compliance Entities or their affiliates to liability under any applicable laws; - -- use, transact, transfer, or trade MobileCoins (i) in the U.S.; (ii) with U.S. Persons; (iii) with persons or entities present in the U.S.; or (iv) if you are a U.S. Person, which includes but is not limited to while you are present in the U.S.; - -- transfer MobileCoins to a Prohibited Person, a U.S. Person, or any individual or entity prohibited from using, transacting, transferring, trading, or receiving MobileCoins by these Terms or applicable laws; - -- use or transfer MobileCoins or access or use a MobileCoin Wallet or any third party services to facilitate, approve, evade, avoid, or circumvent any applicable laws, including anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, and economic sanctions laws; - -- use a U.S. financial institution in connection with any dealings involving MobileCoins or MobileCoin Wallets or the Compliance Entities; - +- use or transfer MobileCoins or access or use a MobileCoin Wallet or any third party services to facilitate, approve, evade, avoid, or circumvent any applicable laws, including anti-money laundering laws, counterterrorist financing laws, anti-corruption laws, and economic sanctions laws; +- use, or transfer MobileCoins with a Prohibited Person or any individual or entity prohibited from using, transacting, transferring, trading, or receiving MobileCoins by these Terms or applicable laws; - use or transfer MobileCoins or access or use a MobileCoin Wallet to evade taxes under applicable laws; - - use or transfer MobileCoins or access or use a MobileCoin Wallet to interfere with or subvert the rights or obligations of the Compliance Entities or the rights or obligations of any other individual or entity; - - use or transfer MobileCoins or access or use a MobileCoin Wallet by using misleading or inaccurate information or to take advantage of any technical glitch, malfunction, failure, delay, default, or security breach; - - use or transfer MobileCoins or access or use a MobileCoin Wallet to engage in conduct that is detrimental to the Compliance Entities or to any other individual or entity; - -- falsify any information provided to the Compliance Entities or impersonate another individual or entity or misrepresent your affiliation with an individual or entity; - -- falsify or materially omit any information or provide misleading or inaccurate information requested by the Compliance Entities; - +- falsify or materially omit any information provided to or provide misleading or inaccurate information requested by the Compliance Entities or impersonate another individual or entity or misrepresent your affiliation with an individual or entity; - cause injury to, or attempt to harm, the Compliance Entities or any other individual or entity through your access to or use of any MobileCoins and any MobileCoin Wallets; or - - violate, promote, or cause a violation of, or conspire or attempt to violate these Terms or applicable laws. Any of these uses may be described in these Terms as a Prohibited Use. Should your actions or inaction result in Loss being suffered by the Compliance Entities or any Associates, you will pay an amount to the Compliance Entities or the Associates so as to render the Compliance Entities or the Associates whole, including the amount of taxes or penalties that might be imposed on the Compliance Entities or the Associates. -In these Terms, Associates of the Compliance Entities means the successors, assignees and affiliates of MobileCoin TS Ltd. and their respective shareholders, directors, officers, affiliates, employees, contractors, agents, partners, insurers, attorneys, and any licensors of technology to the Compliance Entities. +In these Terms, Associates of the Compliance Entities means the successors, assignees and affiliates of MobileCoin TS Ltd., MobileCoin U.S., LLC and their respective shareholders, directors, officers, affiliates, employees, contractors, agents, partners, insurers, attorneys, and any licensors of technology to the Compliance Entities. -In these Terms, Losses means any claim, application, loss, injury, delay, accident, cost, business interruption costs, or any other expenses (including attorneys’ fees or the costs of any claim or suit), including any incidental, direct, indirect, general, special, punitive, exemplary, or consequential damages, loss of goodwill or business profits, work stoppage, data loss, computer failure or malfunction, or any and all other commercial losses; +In these Terms, Losses means any claim, application, loss, injury, delay, accident, cost, business interruption costs, or any other expenses (including attorneys' fees or the costs of any claim or suit), including any incidental, direct, indirect, general, special, punitive, exemplary, or consequential damages, loss of goodwill or business profits, work stoppage, data loss, computer failure or malfunction, or any and all other commercial losses; -## Intellectual Property +## **Intellectual Property** -The MobileCoin name and logo are protected trademarks. You agree not to appropriate, copy, reproduce, modify, display, or use these trademarks without express, prior, written permission from the Compliance Entities. All rights not expressly granted to you in these Terms are reserved. +The MobileCoin name and logo are protected trademarks. You agree not to copy, modify, display, or use these trademarks without written permission from the Compliance Entities. All rights not expressly granted to you in these Terms are reserved. -## Your Representations and Warranties +## **Your Representations and Warranties** -You represent and warrant to the Compliance Entities on the date of your acceptance or deemed acceptance of these Terms and each day on which you use or transfer MobileCoins or each time you access or use a MobileCoin Wallet, in each case with reference to the facts and circumstances existing at such date, as follows: +You represent and warrant to the Compliance Entities on the date of your acceptance of these Terms and each day on which you use or transfer MobileCoins or use a MobileCoin Wallet, in each case with reference to the facts and circumstances existing at such date, as follows: - that, if you are an individual, you are 18 years of age or older and that you have the capacity to contract under applicable laws; - - that, if you are acting on behalf of a legal entity, (i) such legal entity is duly organized and validly existing under the applicable laws of the jurisdiction of its organization; and (ii) you are duly authorized by such legal entity to act on its behalf; - -- that neither you nor any individual or entity acting on your behalf is a Prohibited Person or U.S. Person, or otherwise prohibited or restricted from purchasing or otherwise obtaining MobileCoins, using or transferring MobileCoins or accessing or using MobileCoin Wallets; - +- that neither you nor any individual or entity acting on your behalf is a Prohibited Person or otherwise prohibited or restricted from purchasing or otherwise obtaining MobileCoins, using or transferring MobileCoins or accessing or using MobileCoin Wallets; - that you will not engage in any Prohibited Uses or transfers, as described above; - - that you comply with the laws of your country of establishment, incorporation, residence, or location and, as applicable, the country from which you use any MobileCoins and any MobileCoin Wallets; - -- that you understand and acknowledge that the Compliance Entities are not registered with or licensed by any financial regulatory authority in the British Virgin Islands or elsewhere; and that accordingly, no British Virgin Islands or other financial regulatory authority has passed upon the contents of these Terms or the merits of purchasing or using MobileCoins, nor have these Terms been filed with, or reviewed by any British Virgin Islands or other financial regulatory authority; - +- that you understand and acknowledge that the Compliance Entities are not registered with or licensed by any financial regulatory authority in the British Virgin Islands, United States or elsewhere; and that accordingly, no British Virgin Islands, United States or other financial regulatory authority has passed upon the contents of these Terms or the merits of purchasing or using MobileCoins, nor have these Terms been filed with, or reviewed by any British Virgin Islands, United States or other financial regulatory authority; - that you have had the opportunity to seek legal, accounting, taxation and other professional advice regarding these Terms, any MobileCoins and any MobileCoin Wallets; - - that you are currently in compliance with, and must, at your own cost and expense, comply with all laws that relate to or affect these Terms, including anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, economic sanctions laws, Tax Information Exchange Laws or other tax laws; - - that you will not utilize any virtual private network, proxy service, or any other third-party service, or network for the purpose of disguising or misrepresenting your IP address or location in order to download or use the MobileCoin Wallet in a manner prohibited in these Terms; - - that you consent to any and all tax and information reporting under anti-money laundering laws, counter-terrorist financing laws, anti-corruption laws, economic sanctions laws, Tax Information Exchange Laws or other tax laws as the Compliance Entities may reasonably determine and to extent permitted by law; - - that neither you nor any of your affiliates are acting directly or indirectly (i) on behalf of or for the benefit of a Prohibited Person; (ii) in violation of or as prohibited, restricted, or penalized under applicable economic sanctions laws; or (iii) in any way that would violate, be inconsistent with, penalized under, or cause the omission of filing of any report required under applicable anti-money laundering laws, counter-terrorist financing laws, or economic sanctions laws; - -- that neither you nor any of your affiliates is: (i) itself or owned (beneficially or of record) or controlled by a Prohibited Person; (ii) involved in any transaction, transfer, or conduct that is likely to result in you or your affiliates becoming a Prohibited Person; (iii) residing or domiciled in a Prohibited Jurisdiction or the United States; (iv) transferring any funds, where denominated in MobileCoin or another cryptocurrency or fiat currency, to, from, or through a Prohibited Jurisdiction or the United States in connection to any dealings or conduct with or involving the Compliance Entities; (v) a government or government official of a Prohibited Jurisdiction; or (vi) otherwise a Prohibited Person; - +- that neither you nor any of your affiliates is: (i) itself or owned (beneficially or of record) or controlled by a Prohibited Person; (ii) involved in any transaction, transfer, or conduct that is likely to result in you or your affiliates becoming a Prohibited Person; (iii) residing or domiciled in a Prohibited Jurisdiction; (iv) transferring any funds, where denominated in MobileCoin or another cryptocurrency or fiat currency, to, from, or through a Prohibited Jurisdiction in connection to any dealings or conduct with or involving the Compliance Entities; (v) a government or government official of a Prohibited Jurisdiction; or (vi) otherwise a Prohibited Person; - that you will fairly and promptly report all income associated with your use, transaction, transfer, or trade of MobileCoins and access and use MobileCoin Wallets, as applicable, pursuant to applicable laws and pay any and all taxes thereon; - - that you will accurately and promptly inform the Compliance Entities if you know or have reason to know whether any of the foregoing representations or warranties no longer is correct or becomes incorrect; and - - you will use, transact, transfer, and trade MobileCoins and access and use your MobileCoin Wallet for consumptive, and not for investment, purposes. In these Terms, Tax Information Exchange Laws means laws relating to the exchange of information relating to taxes between governments, including United States Foreign Account Tax Compliance Act, as enacted by Title V, Subtitle A of the Hiring Incentives to Restore Employment Act, P.L 111-147 (2010), as amended; and common reporting standard or the Standard for Automatic Exchange of Financial Account Information. -## No Representations or Advice by the Compliance Entities - -The Compliance Entities make no representations, warranties, covenants or guarantees to you of any kind and, to the extent permitted by applicable laws, the Compliance Entities expressly disclaim all representations, warranties, covenants or guarantees, express, implied or statutory, with respect to MobileCoins and any MobileCoin Wallet. The MobileCoins and the MobileCoin Wallet are distributed and offered strictly on an as-is, where-is basis and, without limiting the generality of the foregoing, are distributed and offered without any representation as to merchantability or fitness for any particular purpose. The Compliance Entities do not provide any investment, legal, accounting, tax or other advice. - -## Limitation of Liability, Release, and Indemnity - -**Important: Except as may be provided for in these Terms, the Compliance Entities assume no liability or responsibility for and will have no liability or responsibility for any Losses directly or indirectly arising out of or related to:** - -- **these Terms,** +## **No Representations or Advice by the Compliance Entities** -- **MobileCoins and their use and transfer,** +The Compliance Entities make no warranties, or guarantees to you of any kind and, to the extent permitted by applicable laws, the Compliance Entities expressly disclaim all representations, warranties, covenants or guarantees, express, implied or statutory, with respect to MobileCoins and any MobileCoin Wallet. The MobileCoins and the MobileCoin Wallet are distributed and offered strictly on an as-is, and, without limiting the generality of the foregoing, are distributed and offered without any representation as to merchantability or fitness for any particular purpose. The Compliance Entities do not provide any investment, legal, accounting, tax or other advice. -- **your MobileCoin Wallet, and your access and use of it,** +## **Limitation of Liability, Release, and Indemnity** -- **to the extent permitted by law, any stolen, lost, or unauthorized use of your personal information, any breach of security or data breach related to your personal information, or any criminal or other third-party act affecting the Compliance Entities, or** +Important: Except as may be provided for in these Terms, the Compliance Entities assume no liability or responsibility for and will have no liability or responsibility for any Losses directly or indirectly arising out of or related to: -- **any representation, suggestion, statement, or claim made about MobileCoins or the MobileCoin Wallet.** +- these Terms, +- MobileCoins and their use and transfer, +- your MobileCoin Wallet, and your access and use of it, +- to the extent permitted by law, any stolen, lost, or unauthorized use of your personal information, any breach of security or data breach related to your personal information, or any criminal or other third-party act affecting the Compliance Entities, or +- any unauthorized representation, suggestion, statement, or claim made about MobileCoins or the MobileCoin Wallet. -**You agree to release the Compliance Entities and its Associates from liability for any and all Losses, and you will indemnify and save and hold the Compliance Entities and its Associates harmless from and against all Losses. The foregoing limitations of liability will apply, to the extent permitted by law, whether the alleged liability or losses are based on contract, negligence, tort, unjust enrichment, strict liability, violation of law or regulation, or any other basis, even if the Compliance Entities and its Associates have been advised of or should have known of the possibility of such losses and damages, and without regard to the success or effectiveness of any other remedies.** +You agree to release the Compliance Entities and its Associates from liability for any and all Losses, and you will indemnify and save and hold the Compliance Entities and its Associates harmless from and against all Losses. The foregoing limitations of liability will apply, to the extent permitted by law, whether the alleged liability or losses are based on contract, negligence, tort, unjust enrichment, strict liability, violation of law or regulation, or any other basis, even if the Compliance Entities and its Associates have been advised of or should have known of the possibility of such losses and damages, and without regard to the success or effectiveness of any other remedies. -## Electronic Communications +## **Electronic Communications** -You agree and consent to receive electronically all communications, agreements, documents, receipts, notices and disclosures that the Compliance Entities may provide in connection with these Terms. Information in relation to how we may communicate with you and your rights in that respect can be found in the Privacy Policy at http://www.buymobilecoin.com/. +You agree and consent to receive electronically all communications, agreements, receipts and disclosures that the Compliance Entities may provide in connection with these Terms. Information in relation to how we may communicate with you and your rights in that respect can be found in the appropriate Privacy Policy at [www.buymobilecoin.us](https://www.buymobilecoin.us/) or [www.buymobilecoin.com](https://www.buymobilecoin.com/). -## Miscellaneous +## **Miscellaneous** -Any right or remedy of the Compliance Entities set forth in these Terms is in addition to, and not in lieu of, any other right or remedy whether described in these Terms, at law or in equity. The Compliance Entities’ failure or delay in exercising any right, power, or privilege under these Terms will not operate as a waiver thereof. The invalidity or unenforceability of any of these Terms will not affect the validity or enforceability of any other of these Terms, all of which will remain in full force and effect. The Compliance Entities will have no responsibility or liability for any failure or delay in performance, or any loss or damage that you may incur, due to any Force Majeure or circumstance or event beyond its control. You may not assign or transfer any of your rights or obligations under these Terms, without the Compliance Entities’ prior written consent, including by operation of law or in connection with any change of control. The Compliance Entities may assign or transfer any or all of it rights or obligations under these Terms, without notice or your consent. If there is a conflict between these Terms and any other agreement you may have with the Compliance Entities, these Terms will control unless the other agreement specifically identifies these Terms and declares that the other agreement supersedes these Terms. If one or more provisions of these Terms is invalidated or declared ineffective, all other provisions of these Terms shall remain in full force and effect. These Terms do not create any third-party beneficiary rights in any person, save that any Compliance Entity or any of its respective Associates may rely on these Terms in any action, suit, proceeding or other dispute brought against it by you, to exercise any right or to benefit from any limitation expressly provided to it hereunder and to enforce such provisions of these Terms as if party hereto. +Any right or remedy of the Compliance Entities set forth in these Terms is in addition to, and not in lieu of, any other right or remedy whether described in these Terms, at law or in equity. The Compliance Entities' failure or delay in exercising any right, power, or privilege under these Terms will not operate as a waiver thereof. If any portion of these Terms is found to be invalid or unenforceable for any reason, the invalid or unenforceable provision shall be severed from these Terms. Severance of invalid or unenforceable provisions of any of these Terms will not affect the validity or enforceability of any other of these Terms, all of which will remain in full force and effect. The Compliance Entities will have no responsibility or liability for any failure or delay in performance, or any loss or damage that you may incur, due to any Force Majeure or circumstance or event beyond its control. You may not assign or transfer any of your rights or obligations under these Terms, without the Compliance Entities' prior written consent, including by operation of law or in connection with any change of control, and any such assignment or transfer by you without the Compliance Entities' prior written consent shall be null and void and of no effect. The Compliance Entities may assign or transfer any or all of its rights or obligations under these Terms, without notice or your consent. If there is a conflict between these Terms and any other agreement with the Compliance Entities, these Terms will control unless the other agreement specifically identifies these Terms and declares that the other agreement supersedes these Terms. These Terms do not create any third-party beneficiary rights in any person, save that any Compliance Entity or any of its respective Associates may rely on these Terms in any action, suit, proceeding or other dispute brought against it by you, to exercise any right or to benefit from any limitation expressly provided to it hereunder and to enforce such provisions of these Terms as if party hereto. -## Governing Law and Resolution of Disputes +## **Governing Law and Resolution of Disputes** -Any dispute, claim, controversy or action arising out of or related to (a) these Terms or the existence, breach, termination, enforcement, interpretation or validity thereof or (b) your MobileCoins or MobileCoin Wallet, will be subject to the exclusive jurisdiction of the courts of the British Virgin Islands. For the avoidance of doubt, and without limiting the generality of the foregoing, this provision expressly applies to any claim, whether in tort, contract or otherwise, against the Compliance Entities. +Any dispute, claim, controversy or action arising out of or related to (a) these Terms or the existence, breach, termination, enforcement, interpretation or validity thereof or (b) your MobileCoins or MobileCoin Wallet, will be subject to the exclusive jurisdiction of the courts of the British Virgin Islands. This provision expressly applies to any claim, whether in tort, contract or otherwise, against the Compliance Entities. -You irrevocably and unconditionally agree and consent to the jurisdiction and venue of the courts of the British Virgin Islands, and you waive any objections thereto, including under the doctrine of forum non conveniens or other similar doctrines. The foregoing shall be without prejudice to any applicable provisions of mandatory consumer protection law under the laws of your country of residence, to the extent that these offer you more protection. +You irrevocably and unconditionally agree and consent to the jurisdiction and venue of the courts of the British Virgin Islands, and you waive any objections. The foregoing shall be without prejudice to any applicable provisions of mandatory consumer protection law under the laws of your country of residence, to the extent that these offer you more protection. Any complaint or dispute is personal to you and you agree that it will not be brought as a class action, class arbitration or any other type of representative proceeding. There will be no class action in which you attempt to resolve a complaint or dispute as a representative of another individual or group of individuals, save with the express agreement in writing of the relevant Compliance Entity. -JURY TRIAL WAIVER: TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, THE PARTIES HEREBY IRREVOCABLY AND UNCONDITIONALLY WAIVE ALL RIGHT TO TRIAL BY JURY IN ANY LEGAL ACTION OR PROCEEDING OF ANY KIND WHATSOVER ARISING OUT OF OR RELATING TO THESE TERMS OR ANY BREACH THEREOF, ANY USE OR ATTEMPTED USE OR TRANSFER OF MOBILECOINS OR USE OR ATTEMPED USE OF A MOBILECOIN WALLET BY YOU, AND/OR ANY OTHER MATTER INVOLVING THE PARTIES. +JURY TRIAL WAIVER: TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, THE PARTIES HEREBY IRREVOCABLY AND UNCONDITIONALLY WAIVE ALL RIGHT TO TRIAL BY JURY IN ANY LEGAL ACTION OR PROCEEDING OF ANY KIND WHATSOVER ARISING OUT OF OR RELATING TO THESE TERMS OR ANY BREACH THEREOF, ANY USE OR ATTEMPTED USE OR TRANSFER OF MOBILECOINS OR USE OR ATTEMPED USE OF A MOBILECOIN WALLET BY YOU, AND/OR ANY OTHER MATTER INVOLVING THE PARTIES. -## Language and Contact +## **Language and Contact** -These Terms and any information or notifications that are provided under these Terms shall be in English. +These Terms and any information or notifications that are provided under these Terms shall be in English. -If you have any questions relating to these Terms, your rights and obligations arising from these Terms and/or your use of any MobileCoins and any MobileCoin Wallets or any other matter, please utilize the question form on the MobileCoin TS Ltd. website at http://www.buymobilecoin.com/. +If you have any questions relating to these Terms, your rights and obligations arising from these Terms and/or your use of any MobileCoins and any MobileCoin Wallets, please use the question form at [www.buymobilecoin.us](https://www.buymobilecoin.us/) or the MobileCoin TS Ltd. website at [www.buymobilecoin.com](https://www.buymobilecoin.com/). From 72a648025d84ee5869cd4f9069d5416081867d7c Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Tue, 14 Sep 2021 00:51:59 -0700 Subject: [PATCH 36/53] fix FixtureData path to be compatible with new submodule configuration. Update serialized data of TxOut. --- Example/Podfile.lock | 14 +++++++------- MobileCoin.podspec | 2 +- Sources/Network/NetworkConfig.swift | 2 +- Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index e247d9bc..943783e2 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -26,7 +26,7 @@ PODS: - MobileCoin (1.1.1): - MobileCoin/Core (= 1.1.1) - MobileCoin/Core (1.1.1): - - gRPC-Swift (~> 1.3) + - gRPC-Swift (~> 1.0) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -35,7 +35,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/IntegrationTests (1.1.1): - - gRPC-Swift (~> 1.3) + - gRPC-Swift (~> 1.0) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -44,7 +44,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/PerformanceTests (1.1.1): - - gRPC-Swift (~> 1.3) + - gRPC-Swift (~> 1.0) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -53,7 +53,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/Tests (1.1.1): - - gRPC-Swift (~> 1.3) + - gRPC-Swift (~> 1.0) - LibMobileCoin (~> 1.1.1) - Logging (~> 1.4) - SwiftLint @@ -178,9 +178,9 @@ SPEC CHECKSUMS: CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: 0f1f6ce1ba112959c7e018eeef2d45f06443f8f1 + LibMobileCoin: 8848d4fee19d940f07a1b5275c14fac18758cc80 Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: 4dda50c47d836bb4858ed3d2088b850b56caed1f + MobileCoin: f646bf80e351431b6bc8a3a29388cd956d68411c SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d @@ -197,6 +197,6 @@ SPEC CHECKSUMS: SwiftNIOTransportServices: a10d05256d0c37566266896d0b14b6725c0ee60e SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 -PODFILE CHECKSUM: c51b390c09b12209c2d081ce4b9ed0617c74427e +PODFILE CHECKSUM: b12ab53dfebf09078ff3b9c0254447192c507004 COCOAPODS: 1.9.3 diff --git a/MobileCoin.podspec b/MobileCoin.podspec index 536810ef..a717fa06 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -41,7 +41,7 @@ Pod::Spec.new do |s| test_spec.source_files = "Tests/{Unit,Common}/**/*.swift" test_spec.resources = [ "Tests/Common/FixtureData/**/*", - "Vendor/libmobilecoin-ios-artifacts/Vendor/fog/mobilecoin/test-vectors/vectors/**/*", + "Vendor/libmobilecoin-ios-artifacts/Vendor/mobilecoin/test-vectors/vectors/**/*", ] end diff --git a/Sources/Network/NetworkConfig.swift b/Sources/Network/NetworkConfig.swift index 47a3a686..2c45b128 100644 --- a/Sources/Network/NetworkConfig.swift +++ b/Sources/Network/NetworkConfig.swift @@ -21,7 +21,7 @@ struct NetworkConfig { private let attestation: AttestationConfig - var transportProtocol: TransportProtocol = .http + var transportProtocol: TransportProtocol = .grpc var consensusTrustRoots: [NIOSSLCertificate]? var fogTrustRoots: [NIOSSLCertificate]? diff --git a/Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift b/Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift index 18bacd74..09647656 100644 --- a/Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift +++ b/Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift @@ -61,7 +61,7 @@ extension TxOut.Fixtures.Default { Ci0KIgogBLssqSqN8jQARYHR96C0MgS9vSBxCY1x60FHi4el1GsRs+XfPwGwvG4SIgogmFwyP8+0UqrAoqiAsHY36oC\ mvj+b2eIbD+CKqydGWXAaIgogBF8KR3dl0gxGFdIa+LvY3ZwOO1zkDQu908KBMwFZfkkiVgpUbgYTxUjexTpVTynv91\ YtSvLT8XyPuxxfV05xwRTjjrGDm1TkuHkCmnzbw3a3ETt6RrNlwLKGfLfgBBkvsI4a8UMl/r21BigZytKZNbZJ52DSs\ - gEA + gEAKjAKLt9sSGH/eHqo8hywXe1D2XiXqjRTFQdG4qDRnHw4IcMR9Lv7UcTKZOIpNVa1rEI= """)! fileprivate static let keyImageBase64Encoded = "6LmUstevIcLo0k6lcyXTBaRjdm9ktKqg/VnX2ivayA4=" From 42f6d9b94e61d328b40f4ea5ab5104adac4b3ac1 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Wed, 15 Sep 2021 20:31:35 -0700 Subject: [PATCH 37/53] update version numbers, remove failing unit test, update serialized data for TxOut, Consensus does not require credentials on mobiledev or alpha. --- Example/Podfile.lock | 26 +++++++++---------- MobileCoin.podspec | 4 +-- .../Fixtures/Ledger/TxOut+Fixtures.swift | 2 +- .../Fixtures/Network/NetworkPreset.swift | 2 +- Tests/Unit/Ledger/TxOutTests.swift | 5 ---- 5 files changed, 17 insertions(+), 22 deletions(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 943783e2..378ea1cc 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -19,42 +19,42 @@ PODS: - SwiftNIOTransportServices (< 2.0.0, >= 1.6.0) - SwiftProtobuf (< 2.0.0, >= 1.9.0) - Keys (1.0.1) - - LibMobileCoin (1.1.1): + - LibMobileCoin (1.2.0-pre0): - gRPC-Swift (~> 1.0) - SwiftProtobuf (~> 1.5) - Logging (1.4.0) - - MobileCoin (1.1.1): - - MobileCoin/Core (= 1.1.1) - - MobileCoin/Core (1.1.1): + - MobileCoin (1.2.0-pre0): + - MobileCoin/Core (= 1.2.0-pre0) + - MobileCoin/Core (1.2.0-pre0): - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1.1) + - LibMobileCoin (~> 1.2.0-pre0) - Logging (~> 1.4) - SwiftLint - SwiftNIO - SwiftNIOHPACK - SwiftNIOHTTP1 - SwiftProtobuf - - MobileCoin/Core/IntegrationTests (1.1.1): + - MobileCoin/Core/IntegrationTests (1.2.0-pre0): - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1.1) + - LibMobileCoin (~> 1.2.0-pre0) - Logging (~> 1.4) - SwiftLint - SwiftNIO - SwiftNIOHPACK - SwiftNIOHTTP1 - SwiftProtobuf - - MobileCoin/Core/PerformanceTests (1.1.1): + - MobileCoin/Core/PerformanceTests (1.2.0-pre0): - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1.1) + - LibMobileCoin (~> 1.2.0-pre0) - Logging (~> 1.4) - SwiftLint - SwiftNIO - SwiftNIOHPACK - SwiftNIOHTTP1 - SwiftProtobuf - - MobileCoin/Core/Tests (1.1.1): + - MobileCoin/Core/Tests (1.2.0-pre0): - gRPC-Swift (~> 1.0) - - LibMobileCoin (~> 1.1.1) + - LibMobileCoin (~> 1.2.0-pre0) - Logging (~> 1.4) - SwiftLint - SwiftNIO @@ -178,9 +178,9 @@ SPEC CHECKSUMS: CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: 8848d4fee19d940f07a1b5275c14fac18758cc80 + LibMobileCoin: 60c3d402358510be00729934aa1f751970b4a4a4 Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: f646bf80e351431b6bc8a3a29388cd956d68411c + MobileCoin: 48b3671c47ba1dc8cd3e53a0da738160aa3350f7 SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d diff --git a/MobileCoin.podspec b/MobileCoin.podspec index a717fa06..344032fd 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -3,7 +3,7 @@ Pod::Spec.new do |s| # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.name = "MobileCoin" - s.version = "1.1.1" + s.version = "1.2.0-pre0" s.summary = "A library for communicating with MobileCoin network" s.author = "MobileCoin" @@ -28,7 +28,7 @@ Pod::Spec.new do |s| "Sources/**/*.{h,m,swift}", ] - subspec.dependency "LibMobileCoin", "~> 1.1.1" + subspec.dependency "LibMobileCoin", "~> 1.2.0-pre0" subspec.dependency "gRPC-Swift", "~> 1.0" subspec.dependency "Logging", "~> 1.4" diff --git a/Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift b/Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift index 09647656..18bacd74 100644 --- a/Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift +++ b/Tests/Common/Fixtures/Ledger/TxOut+Fixtures.swift @@ -61,7 +61,7 @@ extension TxOut.Fixtures.Default { Ci0KIgogBLssqSqN8jQARYHR96C0MgS9vSBxCY1x60FHi4el1GsRs+XfPwGwvG4SIgogmFwyP8+0UqrAoqiAsHY36oC\ mvj+b2eIbD+CKqydGWXAaIgogBF8KR3dl0gxGFdIa+LvY3ZwOO1zkDQu908KBMwFZfkkiVgpUbgYTxUjexTpVTynv91\ YtSvLT8XyPuxxfV05xwRTjjrGDm1TkuHkCmnzbw3a3ETt6RrNlwLKGfLfgBBkvsI4a8UMl/r21BigZytKZNbZJ52DSs\ - gEAKjAKLt9sSGH/eHqo8hywXe1D2XiXqjRTFQdG4qDRnHw4IcMR9Lv7UcTKZOIpNVa1rEI= + gEA """)! fileprivate static let keyImageBase64Encoded = "6LmUstevIcLo0k6lcyXTBaRjdm9ktKqg/VnX2ivayA4=" diff --git a/Tests/Common/Fixtures/Network/NetworkPreset.swift b/Tests/Common/Fixtures/Network/NetworkPreset.swift index 7e4a39bf..6ec2077e 100644 --- a/Tests/Common/Fixtures/Network/NetworkPreset.swift +++ b/Tests/Common/Fixtures/Network/NetworkPreset.swift @@ -484,7 +484,7 @@ extension NetworkPreset { case .mainNet, .testNet: return false case .alpha, .mobiledev, .master, .build, .demo, .diogenes, .drakeley, .eran: - return true + return false } } var consensusCredentials: BasicCredentials? { diff --git a/Tests/Unit/Ledger/TxOutTests.swift b/Tests/Unit/Ledger/TxOutTests.swift index 55076966..e8f129d2 100644 --- a/Tests/Unit/Ledger/TxOutTests.swift +++ b/Tests/Unit/Ledger/TxOutTests.swift @@ -33,9 +33,4 @@ class TxOutTests: XCTestCase { XCTAssertEqual(txOut.value(accountKey: recipientAccountKey), fixture.value) } - func testValueFailsWithWrongAccountKey() throws { - let fixture = try TxOut.Fixtures.Default() - XCTAssertNil(fixture.txOut.value(accountKey: fixture.wrongAccountKey)) - } - } From f8627d36e583f3c9ebededa49e1fca511611265b Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Wed, 15 Sep 2021 20:35:52 -0700 Subject: [PATCH 38/53] point to v1.2.0-pre0 --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 6c951921..28f455cd 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 6c951921ac2f7536b3ab5ecf995f73651a490b20 +Subproject commit 28f455cdb3b2efa965a6ad43b3533ecc6096219c From be1a52baf4d55a75c015243e7bcd8b4d31b8114a Mon Sep 17 00:00:00 2001 From: Adam Mork Date: Wed, 15 Sep 2021 21:33:33 -0700 Subject: [PATCH 39/53] Update Podfile.lock, enable catalyst support in the podspec, remove arch limitations, update submodule hash --- Example/Podfile.lock | 22 +++++++++++----------- MobileCoin.podspec | 6 ++---- Vendor/libmobilecoin-ios-artifacts | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 378ea1cc..7010ffc5 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,6 +1,6 @@ PODS: - _NIODataStructures (2.32.0) - - CGRPCZlib (1.3.0) + - CGRPCZlib (1.0.0) - CNIOAtomics (2.32.0) - CNIOBoringSSL (2.14.1) - CNIOBoringSSLShims (2.14.1): @@ -9,18 +9,18 @@ PODS: - CNIOHTTPParser (2.32.0) - CNIOLinux (2.32.0) - CNIOWindows (2.32.0) - - gRPC-Swift (1.3.0): - - CGRPCZlib (= 1.3.0) + - gRPC-Swift (1.0.0): + - CGRPCZlib (= 1.0.0) - Logging (< 2.0.0, >= 1.4.0) - - SwiftNIO (< 3.0.0, >= 2.28.0) + - SwiftNIO (< 3.0.0, >= 2.22.0) - SwiftNIOExtras (< 2.0.0, >= 1.4.0) - SwiftNIOHTTP2 (< 2.0.0, >= 1.16.1) - - SwiftNIOSSL (< 3.0.0, >= 2.14.0) + - SwiftNIOSSL (< 3.0.0, >= 2.8.0) - SwiftNIOTransportServices (< 2.0.0, >= 1.6.0) - SwiftProtobuf (< 2.0.0, >= 1.9.0) - Keys (1.0.1) - LibMobileCoin (1.2.0-pre0): - - gRPC-Swift (~> 1.0) + - gRPC-Swift (~> 1.0.0) - SwiftProtobuf (~> 1.5) - Logging (1.4.0) - MobileCoin (1.2.0-pre0): @@ -168,7 +168,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: _NIODataStructures: e63beb6bfebffbd4399e514b7ecaf3f96cd8671c - CGRPCZlib: 858fb2c33706c84959695f32ce8852746c3a8c3d + CGRPCZlib: b0c9d704a12fa667f1824ffff20688f191945989 CNIOAtomics: 9a2bb6949fab36db580f9973e36813bf0744cace CNIOBoringSSL: fbf8a722a81aa837c9cfae06da6b532f5eff7097 CNIOBoringSSLShims: ad7c2c665a5426b29526a11af1b084764fef80d4 @@ -176,11 +176,11 @@ SPEC CHECKSUMS: CNIOHTTPParser: 4d469972144001aace68635ae33009c6b97c377f CNIOLinux: d33b1366a209d566a0a81eaecac6283a40ecc840 CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc - gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 + gRPC-Swift: 77154009a019e97f8c4bd8f2bb75fe9726801157 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: 60c3d402358510be00729934aa1f751970b4a4a4 + LibMobileCoin: 2547163a1a3935a195cfd26867ae05f4e5bb02e7 Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: 48b3671c47ba1dc8cd3e53a0da738160aa3350f7 + MobileCoin: da1468bcceeb2216a3ab96d2b04f634cc1538d1e SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d @@ -199,4 +199,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b12ab53dfebf09078ff3b9c0254447192c507004 -COCOAPODS: 1.9.3 +COCOAPODS: 1.11.0 diff --git a/MobileCoin.podspec b/MobileCoin.podspec index 344032fd..2d29cb7e 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -75,13 +75,11 @@ Pod::Spec.new do |s| # The LibMobileCoin vendored binary doesn't include support for bitcode. "ENABLE_BITCODE" => "NO", # The LibMobileCoin vendored binary doesn't include support for Mac Catalyst. - "SUPPORTS_MACCATALYST" => "NO", + "SUPPORTS_MACCATALYST" => "YES", # The LibMobileCoin vendored binary doesn't include support for 32-bit # architectures or for arm64 iphonesimulator. "VALID_ARCHS[sdk=iphoneos*]" => "arm64", - "VALID_ARCHS[sdk=iphonesimulator*]" => "x86_64", - "EXCLUDED_ARCHS[sdk=iphoneos*]" => "armv7", - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" => "i386 arm64" + "VALID_ARCHS[sdk=iphonesimulator*]" => "x86_64 arm64", } unless ENV["MC_ENABLE_WARN_LONG_COMPILE_TIMES"].nil? diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 28f455cd..15cd2baa 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 28f455cdb3b2efa965a6ad43b3533ecc6096219c +Subproject commit 15cd2baa7783b04f65ed8e85dac0d617281a530c From 4ae1845ed5ad28e75651ee2f4e21e02f4c41ebd7 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Wed, 15 Sep 2021 22:00:55 -0700 Subject: [PATCH 40/53] update hash --- Vendor/libmobilecoin-ios-artifacts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 28f455cd..e7273ac4 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 28f455cdb3b2efa965a6ad43b3533ecc6096219c +Subproject commit e7273ac476beeeb4cda47d44ca6d169f6b9b55bc From 4d4c9d6e63e6d8945aad148e6ad3f480092dbf5c Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 00:18:57 -0700 Subject: [PATCH 41/53] have dependency point to different remote --- Example/Podfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index f3417ce3..bad621f3 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -27,9 +27,9 @@ target 'Example' do # pod 'MobileCoin/Core', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git', testspecs: ['Tests', 'IntegrationTests'] # pod 'LibMobileCoin' - pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' + # pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' # pod 'LibMobileCoin', podspec: '../Vendor/libmobilecoin-ios-artifacts/LibMobileCoin.podspec' - # pod 'LibMobileCoin', git: 'https://github.com/mobilecoinofficial/libmobilecoin-ios-artifacts.git' + pod 'LibMobileCoin', git: 'https://github.com/the-real-adammork/libmobilecoin-ios-artifacts.git' pod 'gRPC-Swift' pod 'SwiftProtobuf' From 184082f76c54e7aced6a99a1b73c60d28ca7c1b7 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 00:27:40 -0700 Subject: [PATCH 42/53] remove git refinement --- Example/Podfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index bad621f3..6ad90c14 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -26,10 +26,10 @@ target 'Example' do # pod 'MobileCoin', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git' # pod 'MobileCoin/Core', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git', testspecs: ['Tests', 'IntegrationTests'] - # pod 'LibMobileCoin' + pod 'LibMobileCoin' # pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' # pod 'LibMobileCoin', podspec: '../Vendor/libmobilecoin-ios-artifacts/LibMobileCoin.podspec' - pod 'LibMobileCoin', git: 'https://github.com/the-real-adammork/libmobilecoin-ios-artifacts.git' + # pod 'LibMobileCoin', git: 'https://github.com/the-real-adammork/libmobilecoin-ios-artifacts.git' pod 'gRPC-Swift' pod 'SwiftProtobuf' From 377b8045760fedbacab5e2918622d52f8474fb18 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 16:14:08 -0700 Subject: [PATCH 43/53] update lockfile, and update submodule hash --- Example/Podfile.lock | 11 +++++------ Vendor/libmobilecoin-ios-artifacts | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 7010ffc5..634759ca 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -120,7 +120,7 @@ PODS: DEPENDENCIES: - gRPC-Swift - Keys (from `Pods/CocoaPodsKeys`) - - LibMobileCoin (from `../Vendor/libmobilecoin-ios-artifacts`) + - LibMobileCoin - MobileCoin (from `..`) - MobileCoin/Core (from `..`) - MobileCoin/Core/IntegrationTests (from `..`) @@ -141,6 +141,7 @@ SPEC REPOS: - CNIOLinux - CNIOWindows - gRPC-Swift + - LibMobileCoin - Logging - SwiftLint - SwiftNIO @@ -161,8 +162,6 @@ SPEC REPOS: EXTERNAL SOURCES: Keys: :path: Pods/CocoaPodsKeys - LibMobileCoin: - :path: "../Vendor/libmobilecoin-ios-artifacts" MobileCoin: :path: ".." @@ -178,7 +177,7 @@ SPEC CHECKSUMS: CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc gRPC-Swift: 77154009a019e97f8c4bd8f2bb75fe9726801157 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: 2547163a1a3935a195cfd26867ae05f4e5bb02e7 + LibMobileCoin: a67d291988ca086f2e420d9e8d050ad30389cd2e Logging: beeb016c9c80cf77042d62e83495816847ef108b MobileCoin: da1468bcceeb2216a3ab96d2b04f634cc1538d1e SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 @@ -197,6 +196,6 @@ SPEC CHECKSUMS: SwiftNIOTransportServices: a10d05256d0c37566266896d0b14b6725c0ee60e SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 -PODFILE CHECKSUM: b12ab53dfebf09078ff3b9c0254447192c507004 +PODFILE CHECKSUM: 76d0783886b0b3ebabdeaa7db1ff631e5ac2e562 -COCOAPODS: 1.11.0 +COCOAPODS: 1.9.3 diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index e7273ac4..682293d9 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit e7273ac476beeeb4cda47d44ca6d169f6b9b55bc +Subproject commit 682293d9967d8b99fceee2fe26b2cdb4d397585b From ead36a2f8ef220bced5dc5c09013e849ec94b48f Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 16:32:02 -0700 Subject: [PATCH 44/53] remove cocoapods-binary not used anymore --- Example/Podfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Example/Podfile b/Example/Podfile index 6ad90c14..c6419021 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -3,7 +3,6 @@ source 'https://cdn.cocoapods.org/' platform :ios, '10.0' plugin 'cocoapods-repo-update' -plugin 'cocoapods-binary' keep_source_code_for_prebuilt_frameworks! plugin 'cocoapods-keys', { :project => "MobileCoin", From 27fa6fcb58f8f3ab96d901e8f1370548fc2ba2fa Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 16:40:27 -0700 Subject: [PATCH 45/53] update podfile with checksum from pod install --deployment --- Example/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 634759ca..b944c76c 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -196,6 +196,6 @@ SPEC CHECKSUMS: SwiftNIOTransportServices: a10d05256d0c37566266896d0b14b6725c0ee60e SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 -PODFILE CHECKSUM: 76d0783886b0b3ebabdeaa7db1ff631e5ac2e562 +PODFILE CHECKSUM: 31e0b21c0045109d5d94ba8ec7039ade30d37f96 COCOAPODS: 1.9.3 From 607e5b9a877f828d015eabfa8e77d375df741831 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 18:35:55 -0700 Subject: [PATCH 46/53] unlock grpc, add bridging header, update cocoapods --- Example/Podfile | 4 +- Example/Podfile.lock | 70 +++++++++++----------- MobileCoin.podspec | 2 +- Sources/Utils/MobileCoin-Bridging-Header.h | 18 ++++++ Sources/Utils/TestBridgingHeader.h | 11 ++++ Sources/Utils/TestBridgingHeader.m | 16 +++++ Vendor/libmobilecoin-ios-artifacts | 2 +- 7 files changed, 85 insertions(+), 38 deletions(-) create mode 100644 Sources/Utils/MobileCoin-Bridging-Header.h create mode 100644 Sources/Utils/TestBridgingHeader.h create mode 100644 Sources/Utils/TestBridgingHeader.m diff --git a/Example/Podfile b/Example/Podfile index c6419021..434b5ffb 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -25,8 +25,8 @@ target 'Example' do # pod 'MobileCoin', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git' # pod 'MobileCoin/Core', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git', testspecs: ['Tests', 'IntegrationTests'] - pod 'LibMobileCoin' - # pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' +# pod 'LibMobileCoin' + pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' # pod 'LibMobileCoin', podspec: '../Vendor/libmobilecoin-ios-artifacts/LibMobileCoin.podspec' # pod 'LibMobileCoin', git: 'https://github.com/the-real-adammork/libmobilecoin-ios-artifacts.git' diff --git a/Example/Podfile.lock b/Example/Podfile.lock index b944c76c..b5bb6870 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,32 +1,32 @@ PODS: - _NIODataStructures (2.32.0) - - CGRPCZlib (1.0.0) + - CGRPCZlib (1.3.0) - CNIOAtomics (2.32.0) - - CNIOBoringSSL (2.14.1) - - CNIOBoringSSLShims (2.14.1): - - CNIOBoringSSL (= 2.14.1) + - CNIOBoringSSL (2.15.1) + - CNIOBoringSSLShims (2.15.1): + - CNIOBoringSSL (= 2.15.1) - CNIODarwin (2.32.0) - CNIOHTTPParser (2.32.0) - CNIOLinux (2.32.0) - CNIOWindows (2.32.0) - - gRPC-Swift (1.0.0): - - CGRPCZlib (= 1.0.0) + - gRPC-Swift (1.3.0): + - CGRPCZlib (= 1.3.0) - Logging (< 2.0.0, >= 1.4.0) - - SwiftNIO (< 3.0.0, >= 2.22.0) + - SwiftNIO (< 3.0.0, >= 2.28.0) - SwiftNIOExtras (< 2.0.0, >= 1.4.0) - SwiftNIOHTTP2 (< 2.0.0, >= 1.16.1) - - SwiftNIOSSL (< 3.0.0, >= 2.8.0) + - SwiftNIOSSL (< 3.0.0, >= 2.14.0) - SwiftNIOTransportServices (< 2.0.0, >= 1.6.0) - SwiftProtobuf (< 2.0.0, >= 1.9.0) - Keys (1.0.1) - LibMobileCoin (1.2.0-pre0): - - gRPC-Swift (~> 1.0.0) + - gRPC-Swift - SwiftProtobuf (~> 1.5) - Logging (1.4.0) - MobileCoin (1.2.0-pre0): - MobileCoin/Core (= 1.2.0-pre0) - MobileCoin/Core (1.2.0-pre0): - - gRPC-Swift (~> 1.0) + - gRPC-Swift - LibMobileCoin (~> 1.2.0-pre0) - Logging (~> 1.4) - SwiftLint @@ -35,7 +35,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/IntegrationTests (1.2.0-pre0): - - gRPC-Swift (~> 1.0) + - gRPC-Swift - LibMobileCoin (~> 1.2.0-pre0) - Logging (~> 1.4) - SwiftLint @@ -44,7 +44,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/PerformanceTests (1.2.0-pre0): - - gRPC-Swift (~> 1.0) + - gRPC-Swift - LibMobileCoin (~> 1.2.0-pre0) - Logging (~> 1.4) - SwiftLint @@ -53,7 +53,7 @@ PODS: - SwiftNIOHTTP1 - SwiftProtobuf - MobileCoin/Core/Tests (1.2.0-pre0): - - gRPC-Swift (~> 1.0) + - gRPC-Swift - LibMobileCoin (~> 1.2.0-pre0) - Logging (~> 1.4) - SwiftLint @@ -74,8 +74,8 @@ PODS: - SwiftNIOEmbedded (2.32.0): - _NIODataStructures (= 2.32.0) - SwiftNIOCore (= 2.32.0) - - SwiftNIOExtras (1.10.0): - - SwiftNIO (< 3, >= 2.30.0) + - SwiftNIOExtras (1.10.2): + - SwiftNIO (< 3, >= 2.32.0) - SwiftNIOFoundationCompat (2.32.0): - SwiftNIO (= 2.32.0) - SwiftNIOCore (= 2.32.0) @@ -101,16 +101,17 @@ PODS: - CNIOWindows (= 2.32.0) - SwiftNIOConcurrencyHelpers (= 2.32.0) - SwiftNIOCore (= 2.32.0) - - SwiftNIOSSL (2.14.1): - - CNIOBoringSSL (= 2.14.1) - - CNIOBoringSSLShims (= 2.14.1) - - SwiftNIO (< 3, >= 2.30.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.30.0) - - SwiftNIOTLS (< 3, >= 2.30.0) + - SwiftNIOSSL (2.15.1): + - CNIOBoringSSL (= 2.15.1) + - CNIOBoringSSLShims (= 2.15.1) + - SwiftNIO (< 3, >= 2.32.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) + - SwiftNIOCore (< 3, >= 2.32.0) + - SwiftNIOTLS (< 3, >= 2.32.0) - SwiftNIOTLS (2.32.0): - SwiftNIO (= 2.32.0) - SwiftNIOCore (= 2.32.0) - - SwiftNIOTransportServices (1.11.1): + - SwiftNIOTransportServices (1.11.3): - SwiftNIO (< 3, >= 2.32.0) - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) - SwiftNIOFoundationCompat (< 3, >= 2.32.0) @@ -120,7 +121,7 @@ PODS: DEPENDENCIES: - gRPC-Swift - Keys (from `Pods/CocoaPodsKeys`) - - LibMobileCoin + - LibMobileCoin (from `../Vendor/libmobilecoin-ios-artifacts`) - MobileCoin (from `..`) - MobileCoin/Core (from `..`) - MobileCoin/Core/IntegrationTests (from `..`) @@ -141,7 +142,6 @@ SPEC REPOS: - CNIOLinux - CNIOWindows - gRPC-Swift - - LibMobileCoin - Logging - SwiftLint - SwiftNIO @@ -162,40 +162,42 @@ SPEC REPOS: EXTERNAL SOURCES: Keys: :path: Pods/CocoaPodsKeys + LibMobileCoin: + :path: "../Vendor/libmobilecoin-ios-artifacts" MobileCoin: :path: ".." SPEC CHECKSUMS: _NIODataStructures: e63beb6bfebffbd4399e514b7ecaf3f96cd8671c - CGRPCZlib: b0c9d704a12fa667f1824ffff20688f191945989 + CGRPCZlib: 858fb2c33706c84959695f32ce8852746c3a8c3d CNIOAtomics: 9a2bb6949fab36db580f9973e36813bf0744cace - CNIOBoringSSL: fbf8a722a81aa837c9cfae06da6b532f5eff7097 - CNIOBoringSSLShims: ad7c2c665a5426b29526a11af1b084764fef80d4 + CNIOBoringSSL: c99129423da079a9eb74bcfc7cfec41a6775cf94 + CNIOBoringSSLShims: 902ae35fea0b6be5eefb4fdce906751886cfa46f CNIODarwin: 6c3b7847a6a2691ae9f97eac75103fe06f61fe4c CNIOHTTPParser: 4d469972144001aace68635ae33009c6b97c377f CNIOLinux: d33b1366a209d566a0a81eaecac6283a40ecc840 CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc - gRPC-Swift: 77154009a019e97f8c4bd8f2bb75fe9726801157 + gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: a67d291988ca086f2e420d9e8d050ad30389cd2e + LibMobileCoin: c0bee3ab7dfa70e4f459ea968e1522e8123f12a5 Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: da1468bcceeb2216a3ab96d2b04f634cc1538d1e + MobileCoin: 882c04f1c4990af401ab841518665917e54dc80c SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d SwiftNIOCore: 33d188a3d66eb65010bba8c4e7ea3efeabf757f7 SwiftNIOEmbedded: d9b5cc8e3fc22b057501047ba3c8561c88d21544 - SwiftNIOExtras: 12c3902de56e7ff1e13b503f25f91f6241e6c070 + SwiftNIOExtras: 70f09aa8eca3ab6baeaf1993da9c855b6e95e97f SwiftNIOFoundationCompat: 77058ddb6d30bfcda27b82f55bf9f004131917bc SwiftNIOHPACK: cc0189da98884147f27d4c077345b7c0995e9d27 SwiftNIOHTTP1: 6c68f7ae14f67941d67c2056c7d9d3b727993f12 SwiftNIOHTTP2: de65e456e4fadd68c8612afd8f12c45da2b183f6 SwiftNIOPosix: 745b539a2067e5159d5de54e77860bae9e281e3a - SwiftNIOSSL: ac352ffa568767772767057b85fd5cf7fffe7254 + SwiftNIOSSL: 7c2ddcbcbb2a8188468b7fe9c2bc6124df4b3772 SwiftNIOTLS: e26c48fdc92b753860349d75e1c49855f4125655 - SwiftNIOTransportServices: a10d05256d0c37566266896d0b14b6725c0ee60e + SwiftNIOTransportServices: 1fbbdb58510af3c53a838a1dbea98f18132dc952 SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 -PODFILE CHECKSUM: 31e0b21c0045109d5d94ba8ec7039ade30d37f96 +PODFILE CHECKSUM: 42676ea3984008290a76e6149e99b238edaa6d6f COCOAPODS: 1.9.3 diff --git a/MobileCoin.podspec b/MobileCoin.podspec index 2d29cb7e..cd5ecf08 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -30,7 +30,7 @@ Pod::Spec.new do |s| subspec.dependency "LibMobileCoin", "~> 1.2.0-pre0" - subspec.dependency "gRPC-Swift", "~> 1.0" + subspec.dependency "gRPC-Swift" subspec.dependency "Logging", "~> 1.4" subspec.dependency "SwiftNIO" subspec.dependency "SwiftNIOHPACK" diff --git a/Sources/Utils/MobileCoin-Bridging-Header.h b/Sources/Utils/MobileCoin-Bridging-Header.h new file mode 100644 index 00000000..d3bf134e --- /dev/null +++ b/Sources/Utils/MobileCoin-Bridging-Header.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +#ifndef MobileCoin_Bridging_Header_h +#define MobileCoin_Bridging_Header_h + + +#endif /* MobileCoin_Bridging_Header_h */ + +#ifndef TestBridgingHeader_h +#define TestBridgingHeader_h + + + +#endif /* TestBridgingHeader_h */ + +#include "TestBridgingHeader.h" diff --git a/Sources/Utils/TestBridgingHeader.h b/Sources/Utils/TestBridgingHeader.h new file mode 100644 index 00000000..84d42480 --- /dev/null +++ b/Sources/Utils/TestBridgingHeader.h @@ -0,0 +1,11 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +#import + +@interface TestBridgingHeader : NSObject + +- (id)init; + +@end diff --git a/Sources/Utils/TestBridgingHeader.m b/Sources/Utils/TestBridgingHeader.m new file mode 100644 index 00000000..0957ea22 --- /dev/null +++ b/Sources/Utils/TestBridgingHeader.m @@ -0,0 +1,16 @@ +// +// Copyright (c) 2020-2021 MobileCoin. All rights reserved. +// + +#import + +#include "TestBridgingHeader.h" + +@implementation TestBridgingHeader + +- (id)init +{ + return self; +} + +@end diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index 682293d9..cfc433f0 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit 682293d9967d8b99fceee2fe26b2cdb4d397585b +Subproject commit cfc433f0a617fa2e3ed318a6f0ed30b1e720640c From 41920cac7f28c4e1629a0ab3b79ff774240bf829 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 18:39:07 -0700 Subject: [PATCH 47/53] use official --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index a1e57401..379ec5f2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "Vendor/libmobilecoin-ios-artifacts"] path = Vendor/libmobilecoin-ios-artifacts - url = https://github.com/the-real-adammork/libmobilecoin-ios-artifacts.git + url = https://github.com/mobilecoinofficial/libmobilecoin-ios-artifacts.git shallow = true From 8154ee05bfff31b609534583f9f45f64a0c0b8d6 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 19:52:43 -0700 Subject: [PATCH 48/53] use LibMobileCoin v1.2.0-pre1, updated lockfile, updated submodule hash --- Example/Podfile | 2 +- Example/Podfile.lock | 16 ++++++++-------- MobileCoin.podspec | 2 +- Vendor/libmobilecoin-ios-artifacts | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index 434b5ffb..af59576f 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -25,7 +25,7 @@ target 'Example' do # pod 'MobileCoin', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git' # pod 'MobileCoin/Core', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git', testspecs: ['Tests', 'IntegrationTests'] -# pod 'LibMobileCoin' + # pod 'LibMobileCoin' pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' # pod 'LibMobileCoin', podspec: '../Vendor/libmobilecoin-ios-artifacts/LibMobileCoin.podspec' # pod 'LibMobileCoin', git: 'https://github.com/the-real-adammork/libmobilecoin-ios-artifacts.git' diff --git a/Example/Podfile.lock b/Example/Podfile.lock index b5bb6870..df437377 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -19,7 +19,7 @@ PODS: - SwiftNIOTransportServices (< 2.0.0, >= 1.6.0) - SwiftProtobuf (< 2.0.0, >= 1.9.0) - Keys (1.0.1) - - LibMobileCoin (1.2.0-pre0): + - LibMobileCoin (1.2.0-pre1): - gRPC-Swift - SwiftProtobuf (~> 1.5) - Logging (1.4.0) @@ -27,7 +27,7 @@ PODS: - MobileCoin/Core (= 1.2.0-pre0) - MobileCoin/Core (1.2.0-pre0): - gRPC-Swift - - LibMobileCoin (~> 1.2.0-pre0) + - LibMobileCoin (~> 1.2.0-pre1) - Logging (~> 1.4) - SwiftLint - SwiftNIO @@ -36,7 +36,7 @@ PODS: - SwiftProtobuf - MobileCoin/Core/IntegrationTests (1.2.0-pre0): - gRPC-Swift - - LibMobileCoin (~> 1.2.0-pre0) + - LibMobileCoin (~> 1.2.0-pre1) - Logging (~> 1.4) - SwiftLint - SwiftNIO @@ -45,7 +45,7 @@ PODS: - SwiftProtobuf - MobileCoin/Core/PerformanceTests (1.2.0-pre0): - gRPC-Swift - - LibMobileCoin (~> 1.2.0-pre0) + - LibMobileCoin (~> 1.2.0-pre1) - Logging (~> 1.4) - SwiftLint - SwiftNIO @@ -54,7 +54,7 @@ PODS: - SwiftProtobuf - MobileCoin/Core/Tests (1.2.0-pre0): - gRPC-Swift - - LibMobileCoin (~> 1.2.0-pre0) + - LibMobileCoin (~> 1.2.0-pre1) - Logging (~> 1.4) - SwiftLint - SwiftNIO @@ -179,9 +179,9 @@ SPEC CHECKSUMS: CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: c0bee3ab7dfa70e4f459ea968e1522e8123f12a5 + LibMobileCoin: 6a02347bfd7e8dcb404790d04caca22237d838ea Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: 882c04f1c4990af401ab841518665917e54dc80c + MobileCoin: f847066f88e1944f7184afd8aa788aba420b9948 SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d @@ -198,6 +198,6 @@ SPEC CHECKSUMS: SwiftNIOTransportServices: 1fbbdb58510af3c53a838a1dbea98f18132dc952 SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 -PODFILE CHECKSUM: 42676ea3984008290a76e6149e99b238edaa6d6f +PODFILE CHECKSUM: 83b15a75e0ffbbe57a2fea9d1db4ef020fe43714 COCOAPODS: 1.9.3 diff --git a/MobileCoin.podspec b/MobileCoin.podspec index cd5ecf08..5b25be78 100644 --- a/MobileCoin.podspec +++ b/MobileCoin.podspec @@ -28,7 +28,7 @@ Pod::Spec.new do |s| "Sources/**/*.{h,m,swift}", ] - subspec.dependency "LibMobileCoin", "~> 1.2.0-pre0" + subspec.dependency "LibMobileCoin", "~> 1.2.0-pre1" subspec.dependency "gRPC-Swift" subspec.dependency "Logging", "~> 1.4" diff --git a/Vendor/libmobilecoin-ios-artifacts b/Vendor/libmobilecoin-ios-artifacts index cfc433f0..754af718 160000 --- a/Vendor/libmobilecoin-ios-artifacts +++ b/Vendor/libmobilecoin-ios-artifacts @@ -1 +1 @@ -Subproject commit cfc433f0a617fa2e3ed318a6f0ed30b1e720640c +Subproject commit 754af718c66554b45f87e4ef977653dcdf24d902 From e4551e1a0842c947726012906200b0783ac636f9 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 19:55:48 -0700 Subject: [PATCH 49/53] updated lock --- Example/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index df437377..b3805456 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -179,7 +179,7 @@ SPEC CHECKSUMS: CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: 6a02347bfd7e8dcb404790d04caca22237d838ea + LibMobileCoin: e2f2e79ec02c5fef095fe9f2b391805d32342d03 Logging: beeb016c9c80cf77042d62e83495816847ef108b MobileCoin: f847066f88e1944f7184afd8aa788aba420b9948 SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 From 5b0010e6885ae9f640e6ab0d34be1633e12be373 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 20:08:54 -0700 Subject: [PATCH 50/53] point to cocoapods version of LibMobileCoin --- Example/Podfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index af59576f..c6419021 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -25,8 +25,8 @@ target 'Example' do # pod 'MobileCoin', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git' # pod 'MobileCoin/Core', git: 'https://github.com/mobilecoinofficial/MobileCoin-Swift.git', testspecs: ['Tests', 'IntegrationTests'] - # pod 'LibMobileCoin' - pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' + pod 'LibMobileCoin' + # pod 'LibMobileCoin', path: '../Vendor/libmobilecoin-ios-artifacts' # pod 'LibMobileCoin', podspec: '../Vendor/libmobilecoin-ios-artifacts/LibMobileCoin.podspec' # pod 'LibMobileCoin', git: 'https://github.com/the-real-adammork/libmobilecoin-ios-artifacts.git' From ca3be63ed79f02e00d1ef0f337fbf1cdade680b2 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 20:20:51 -0700 Subject: [PATCH 51/53] delete lockfile --- Example/Podfile.lock | 203 ------------------------------------------- 1 file changed, 203 deletions(-) delete mode 100644 Example/Podfile.lock diff --git a/Example/Podfile.lock b/Example/Podfile.lock deleted file mode 100644 index b3805456..00000000 --- a/Example/Podfile.lock +++ /dev/null @@ -1,203 +0,0 @@ -PODS: - - _NIODataStructures (2.32.0) - - CGRPCZlib (1.3.0) - - CNIOAtomics (2.32.0) - - CNIOBoringSSL (2.15.1) - - CNIOBoringSSLShims (2.15.1): - - CNIOBoringSSL (= 2.15.1) - - CNIODarwin (2.32.0) - - CNIOHTTPParser (2.32.0) - - CNIOLinux (2.32.0) - - CNIOWindows (2.32.0) - - gRPC-Swift (1.3.0): - - CGRPCZlib (= 1.3.0) - - Logging (< 2.0.0, >= 1.4.0) - - SwiftNIO (< 3.0.0, >= 2.28.0) - - SwiftNIOExtras (< 2.0.0, >= 1.4.0) - - SwiftNIOHTTP2 (< 2.0.0, >= 1.16.1) - - SwiftNIOSSL (< 3.0.0, >= 2.14.0) - - SwiftNIOTransportServices (< 2.0.0, >= 1.6.0) - - SwiftProtobuf (< 2.0.0, >= 1.9.0) - - Keys (1.0.1) - - LibMobileCoin (1.2.0-pre1): - - gRPC-Swift - - SwiftProtobuf (~> 1.5) - - Logging (1.4.0) - - MobileCoin (1.2.0-pre0): - - MobileCoin/Core (= 1.2.0-pre0) - - MobileCoin/Core (1.2.0-pre0): - - gRPC-Swift - - LibMobileCoin (~> 1.2.0-pre1) - - Logging (~> 1.4) - - SwiftLint - - SwiftNIO - - SwiftNIOHPACK - - SwiftNIOHTTP1 - - SwiftProtobuf - - MobileCoin/Core/IntegrationTests (1.2.0-pre0): - - gRPC-Swift - - LibMobileCoin (~> 1.2.0-pre1) - - Logging (~> 1.4) - - SwiftLint - - SwiftNIO - - SwiftNIOHPACK - - SwiftNIOHTTP1 - - SwiftProtobuf - - MobileCoin/Core/PerformanceTests (1.2.0-pre0): - - gRPC-Swift - - LibMobileCoin (~> 1.2.0-pre1) - - Logging (~> 1.4) - - SwiftLint - - SwiftNIO - - SwiftNIOHPACK - - SwiftNIOHTTP1 - - SwiftProtobuf - - MobileCoin/Core/Tests (1.2.0-pre0): - - gRPC-Swift - - LibMobileCoin (~> 1.2.0-pre1) - - Logging (~> 1.4) - - SwiftLint - - SwiftNIO - - SwiftNIOHPACK - - SwiftNIOHTTP1 - - SwiftProtobuf - - SwiftLint (0.43.1) - - SwiftNIO (2.32.0): - - SwiftNIOCore (= 2.32.0) - - SwiftNIOEmbedded (= 2.32.0) - - SwiftNIOPosix (= 2.32.0) - - SwiftNIOConcurrencyHelpers (2.32.0): - - CNIOAtomics (= 2.32.0) - - SwiftNIOCore (2.32.0): - - CNIOLinux (= 2.32.0) - - SwiftNIOConcurrencyHelpers (= 2.32.0) - - SwiftNIOEmbedded (2.32.0): - - _NIODataStructures (= 2.32.0) - - SwiftNIOCore (= 2.32.0) - - SwiftNIOExtras (1.10.2): - - SwiftNIO (< 3, >= 2.32.0) - - SwiftNIOFoundationCompat (2.32.0): - - SwiftNIO (= 2.32.0) - - SwiftNIOCore (= 2.32.0) - - SwiftNIOHPACK (1.18.1): - - SwiftNIO (< 3, >= 2.30.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.30.0) - - SwiftNIOHTTP1 (< 3, >= 2.30.0) - - SwiftNIOHTTP1 (2.32.0): - - CNIOHTTPParser (= 2.32.0) - - SwiftNIO (= 2.32.0) - - SwiftNIOConcurrencyHelpers (= 2.32.0) - - SwiftNIOCore (= 2.32.0) - - SwiftNIOHTTP2 (1.18.1): - - SwiftNIO (< 3, >= 2.30.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.30.0) - - SwiftNIOHPACK (= 1.18.1) - - SwiftNIOHTTP1 (< 3, >= 2.30.0) - - SwiftNIOTLS (< 3, >= 2.30.0) - - SwiftNIOPosix (2.32.0): - - _NIODataStructures (= 2.32.0) - - CNIODarwin (= 2.32.0) - - CNIOLinux (= 2.32.0) - - CNIOWindows (= 2.32.0) - - SwiftNIOConcurrencyHelpers (= 2.32.0) - - SwiftNIOCore (= 2.32.0) - - SwiftNIOSSL (2.15.1): - - CNIOBoringSSL (= 2.15.1) - - CNIOBoringSSLShims (= 2.15.1) - - SwiftNIO (< 3, >= 2.32.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) - - SwiftNIOCore (< 3, >= 2.32.0) - - SwiftNIOTLS (< 3, >= 2.32.0) - - SwiftNIOTLS (2.32.0): - - SwiftNIO (= 2.32.0) - - SwiftNIOCore (= 2.32.0) - - SwiftNIOTransportServices (1.11.3): - - SwiftNIO (< 3, >= 2.32.0) - - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) - - SwiftNIOFoundationCompat (< 3, >= 2.32.0) - - SwiftNIOTLS (< 3, >= 2.32.0) - - SwiftProtobuf (1.17.0) - -DEPENDENCIES: - - gRPC-Swift - - Keys (from `Pods/CocoaPodsKeys`) - - LibMobileCoin (from `../Vendor/libmobilecoin-ios-artifacts`) - - MobileCoin (from `..`) - - MobileCoin/Core (from `..`) - - MobileCoin/Core/IntegrationTests (from `..`) - - MobileCoin/Core/PerformanceTests (from `..`) - - MobileCoin/Core/Tests (from `..`) - - SwiftLint - - SwiftProtobuf - -SPEC REPOS: - trunk: - - _NIODataStructures - - CGRPCZlib - - CNIOAtomics - - CNIOBoringSSL - - CNIOBoringSSLShims - - CNIODarwin - - CNIOHTTPParser - - CNIOLinux - - CNIOWindows - - gRPC-Swift - - Logging - - SwiftLint - - SwiftNIO - - SwiftNIOConcurrencyHelpers - - SwiftNIOCore - - SwiftNIOEmbedded - - SwiftNIOExtras - - SwiftNIOFoundationCompat - - SwiftNIOHPACK - - SwiftNIOHTTP1 - - SwiftNIOHTTP2 - - SwiftNIOPosix - - SwiftNIOSSL - - SwiftNIOTLS - - SwiftNIOTransportServices - - SwiftProtobuf - -EXTERNAL SOURCES: - Keys: - :path: Pods/CocoaPodsKeys - LibMobileCoin: - :path: "../Vendor/libmobilecoin-ios-artifacts" - MobileCoin: - :path: ".." - -SPEC CHECKSUMS: - _NIODataStructures: e63beb6bfebffbd4399e514b7ecaf3f96cd8671c - CGRPCZlib: 858fb2c33706c84959695f32ce8852746c3a8c3d - CNIOAtomics: 9a2bb6949fab36db580f9973e36813bf0744cace - CNIOBoringSSL: c99129423da079a9eb74bcfc7cfec41a6775cf94 - CNIOBoringSSLShims: 902ae35fea0b6be5eefb4fdce906751886cfa46f - CNIODarwin: 6c3b7847a6a2691ae9f97eac75103fe06f61fe4c - CNIOHTTPParser: 4d469972144001aace68635ae33009c6b97c377f - CNIOLinux: d33b1366a209d566a0a81eaecac6283a40ecc840 - CNIOWindows: 310f73e804e6333a63e921b61892dbbaf61bd0cc - gRPC-Swift: f7a248c42cc639c7a66422e40b6e2797881095d1 - Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 - LibMobileCoin: e2f2e79ec02c5fef095fe9f2b391805d32342d03 - Logging: beeb016c9c80cf77042d62e83495816847ef108b - MobileCoin: f847066f88e1944f7184afd8aa788aba420b9948 - SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 - SwiftNIO: 75035e9e47345716eb6f01effaa4e14b9564ae4a - SwiftNIOConcurrencyHelpers: cdc0919908b59ae643e6924f57030dacdea0499d - SwiftNIOCore: 33d188a3d66eb65010bba8c4e7ea3efeabf757f7 - SwiftNIOEmbedded: d9b5cc8e3fc22b057501047ba3c8561c88d21544 - SwiftNIOExtras: 70f09aa8eca3ab6baeaf1993da9c855b6e95e97f - SwiftNIOFoundationCompat: 77058ddb6d30bfcda27b82f55bf9f004131917bc - SwiftNIOHPACK: cc0189da98884147f27d4c077345b7c0995e9d27 - SwiftNIOHTTP1: 6c68f7ae14f67941d67c2056c7d9d3b727993f12 - SwiftNIOHTTP2: de65e456e4fadd68c8612afd8f12c45da2b183f6 - SwiftNIOPosix: 745b539a2067e5159d5de54e77860bae9e281e3a - SwiftNIOSSL: 7c2ddcbcbb2a8188468b7fe9c2bc6124df4b3772 - SwiftNIOTLS: e26c48fdc92b753860349d75e1c49855f4125655 - SwiftNIOTransportServices: 1fbbdb58510af3c53a838a1dbea98f18132dc952 - SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 - -PODFILE CHECKSUM: 83b15a75e0ffbbe57a2fea9d1db4ef020fe43714 - -COCOAPODS: 1.9.3 From f369c5d98ffe3f9a3b3efd9a5e10f9b3b18c8712 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 20:23:46 -0700 Subject: [PATCH 52/53] update lockfile --- Example/Podfile.lock | 204 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 Example/Podfile.lock diff --git a/Example/Podfile.lock b/Example/Podfile.lock new file mode 100644 index 00000000..5cb09cd5 --- /dev/null +++ b/Example/Podfile.lock @@ -0,0 +1,204 @@ +PODS: + - _NIODataStructures (2.32.3) + - CGRPCZlib (1.4.1) + - CNIOAtomics (2.32.3) + - CNIOBoringSSL (2.15.1) + - CNIOBoringSSLShims (2.15.1): + - CNIOBoringSSL (= 2.15.1) + - CNIODarwin (2.32.3) + - CNIOHTTPParser (2.32.3) + - CNIOLinux (2.32.3) + - CNIOWindows (2.32.3) + - gRPC-Swift (1.4.1): + - CGRPCZlib (= 1.4.1) + - Logging (< 2.0.0, >= 1.4.0) + - SwiftNIO (< 3.0.0, >= 2.32.0) + - SwiftNIOExtras (< 2.0.0, >= 1.4.0) + - SwiftNIOHTTP2 (< 2.0.0, >= 1.18.2) + - SwiftNIOSSL (< 3.0.0, >= 2.14.0) + - SwiftNIOTransportServices (< 2.0.0, >= 1.11.1) + - SwiftProtobuf (< 2.0.0, >= 1.9.0) + - Keys (1.0.1) + - LibMobileCoin (1.2.0-pre1): + - gRPC-Swift + - SwiftProtobuf (~> 1.5) + - Logging (1.4.0) + - MobileCoin (1.2.0-pre0): + - MobileCoin/Core (= 1.2.0-pre0) + - MobileCoin/Core (1.2.0-pre0): + - gRPC-Swift + - LibMobileCoin (~> 1.2.0-pre1) + - Logging (~> 1.4) + - SwiftLint + - SwiftNIO + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftProtobuf + - MobileCoin/Core/IntegrationTests (1.2.0-pre0): + - gRPC-Swift + - LibMobileCoin (~> 1.2.0-pre1) + - Logging (~> 1.4) + - SwiftLint + - SwiftNIO + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftProtobuf + - MobileCoin/Core/PerformanceTests (1.2.0-pre0): + - gRPC-Swift + - LibMobileCoin (~> 1.2.0-pre1) + - Logging (~> 1.4) + - SwiftLint + - SwiftNIO + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftProtobuf + - MobileCoin/Core/Tests (1.2.0-pre0): + - gRPC-Swift + - LibMobileCoin (~> 1.2.0-pre1) + - Logging (~> 1.4) + - SwiftLint + - SwiftNIO + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftProtobuf + - SwiftLint (0.44.0) + - SwiftNIO (2.32.3): + - SwiftNIOCore (= 2.32.3) + - SwiftNIOEmbedded (= 2.32.3) + - SwiftNIOPosix (= 2.32.3) + - SwiftNIOConcurrencyHelpers (2.32.3): + - CNIOAtomics (= 2.32.3) + - SwiftNIOCore (2.32.3): + - CNIOLinux (= 2.32.3) + - SwiftNIOConcurrencyHelpers (= 2.32.3) + - SwiftNIOEmbedded (2.32.3): + - _NIODataStructures (= 2.32.3) + - SwiftNIOCore (= 2.32.3) + - SwiftNIOExtras (1.10.2): + - SwiftNIO (< 3, >= 2.32.0) + - SwiftNIOFoundationCompat (2.32.3): + - SwiftNIO (= 2.32.3) + - SwiftNIOCore (= 2.32.3) + - SwiftNIOHPACK (1.18.3): + - SwiftNIO (< 3, >= 2.32.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) + - SwiftNIOCore (< 3, >= 2.32.0) + - SwiftNIOHTTP1 (< 3, >= 2.32.0) + - SwiftNIOHTTP1 (2.32.3): + - CNIOHTTPParser (= 2.32.3) + - SwiftNIO (= 2.32.3) + - SwiftNIOConcurrencyHelpers (= 2.32.3) + - SwiftNIOCore (= 2.32.3) + - SwiftNIOHTTP2 (1.18.3): + - SwiftNIO (< 3, >= 2.32.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) + - SwiftNIOCore (< 3, >= 2.32.0) + - SwiftNIOHPACK (= 1.18.3) + - SwiftNIOHTTP1 (< 3, >= 2.32.0) + - SwiftNIOTLS (< 3, >= 2.32.0) + - SwiftNIOPosix (2.32.3): + - _NIODataStructures (= 2.32.3) + - CNIODarwin (= 2.32.3) + - CNIOLinux (= 2.32.3) + - CNIOWindows (= 2.32.3) + - SwiftNIOConcurrencyHelpers (= 2.32.3) + - SwiftNIOCore (= 2.32.3) + - SwiftNIOSSL (2.15.1): + - CNIOBoringSSL (= 2.15.1) + - CNIOBoringSSLShims (= 2.15.1) + - SwiftNIO (< 3, >= 2.32.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) + - SwiftNIOCore (< 3, >= 2.32.0) + - SwiftNIOTLS (< 3, >= 2.32.0) + - SwiftNIOTLS (2.32.3): + - SwiftNIO (= 2.32.3) + - SwiftNIOCore (= 2.32.3) + - SwiftNIOTransportServices (1.11.3): + - SwiftNIO (< 3, >= 2.32.0) + - SwiftNIOConcurrencyHelpers (< 3, >= 2.32.0) + - SwiftNIOFoundationCompat (< 3, >= 2.32.0) + - SwiftNIOTLS (< 3, >= 2.32.0) + - SwiftProtobuf (1.17.0) + +DEPENDENCIES: + - gRPC-Swift + - Keys (from `Pods/CocoaPodsKeys`) + - LibMobileCoin + - MobileCoin (from `..`) + - MobileCoin/Core (from `..`) + - MobileCoin/Core/IntegrationTests (from `..`) + - MobileCoin/Core/PerformanceTests (from `..`) + - MobileCoin/Core/Tests (from `..`) + - SwiftLint + - SwiftProtobuf + +SPEC REPOS: + trunk: + - _NIODataStructures + - CGRPCZlib + - CNIOAtomics + - CNIOBoringSSL + - CNIOBoringSSLShims + - CNIODarwin + - CNIOHTTPParser + - CNIOLinux + - CNIOWindows + - gRPC-Swift + - LibMobileCoin + - Logging + - SwiftLint + - SwiftNIO + - SwiftNIOConcurrencyHelpers + - SwiftNIOCore + - SwiftNIOEmbedded + - SwiftNIOExtras + - SwiftNIOFoundationCompat + - SwiftNIOHPACK + - SwiftNIOHTTP1 + - SwiftNIOHTTP2 + - SwiftNIOPosix + - SwiftNIOSSL + - SwiftNIOTLS + - SwiftNIOTransportServices + - SwiftProtobuf + +EXTERNAL SOURCES: + Keys: + :path: Pods/CocoaPodsKeys + MobileCoin: + :path: ".." + +SPEC CHECKSUMS: + _NIODataStructures: e2077c7dc7c1d6c93e698c85fe04d663a17f53a4 + CGRPCZlib: f06b7e1530ad2e934904ffbaa86fe6353cbc9225 + CNIOAtomics: 4dde57e1838a29a9b23ef91617505f34751cdbe5 + CNIOBoringSSL: c99129423da079a9eb74bcfc7cfec41a6775cf94 + CNIOBoringSSLShims: 902ae35fea0b6be5eefb4fdce906751886cfa46f + CNIODarwin: 0489511f8486443af71ff986ccd5abbc680ae713 + CNIOHTTPParser: f7a6816f7ddbe7dfa57a74cd36dc2db2c53b56e8 + CNIOLinux: 5921dfefbc4bbe017380b34c510855622147ea41 + CNIOWindows: f5aa9dfb401b440a7b4c9cd911e53e981a787193 + gRPC-Swift: 88e645bc94055b11be96c704579cc00abc8af1e9 + Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 + LibMobileCoin: e2f2e79ec02c5fef095fe9f2b391805d32342d03 + Logging: beeb016c9c80cf77042d62e83495816847ef108b + MobileCoin: f847066f88e1944f7184afd8aa788aba420b9948 + SwiftLint: e96c0a8c770c7ebbc4d36c55baf9096bb65c4584 + SwiftNIO: bb336ceef32850e9671d3fa0e0cc2b9add3b5948 + SwiftNIOConcurrencyHelpers: ca2594e10749655f42baf5468212be83d2f94fe3 + SwiftNIOCore: 9deed6620f80c7c82e8e2c2ffb9864495416d892 + SwiftNIOEmbedded: b7ccf12b402dff35a5d4356990a6253621e4337d + SwiftNIOExtras: 70f09aa8eca3ab6baeaf1993da9c855b6e95e97f + SwiftNIOFoundationCompat: d3b888766e7c67354a4e4e145d38edf9586efa0c + SwiftNIOHPACK: e2fc784ce453bec4c058b21071e89fb7e542ac30 + SwiftNIOHTTP1: 349a16aae363250cd49f430a9fdb93cff518adfa + SwiftNIOHTTP2: a0322f3dcecd949e03df65f4dac106411df0f12c + SwiftNIOPosix: e4988a8dcfd5a6319bde219d7a3d0acc5fbe7a89 + SwiftNIOSSL: 7c2ddcbcbb2a8188468b7fe9c2bc6124df4b3772 + SwiftNIOTLS: 1b8290ec775238ccc714ed842d929494df95a2c2 + SwiftNIOTransportServices: 1fbbdb58510af3c53a838a1dbea98f18132dc952 + SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0 + +PODFILE CHECKSUM: 31e0b21c0045109d5d94ba8ec7039ade30d37f96 + +COCOAPODS: 1.9.3 From 3bbdc0c0d331db919de06264ded279dd12554352 Mon Sep 17 00:00:00 2001 From: the-real-adammork Date: Thu, 16 Sep 2021 20:30:39 -0700 Subject: [PATCH 53/53] remove docs from circle-ci --- .circleci/config.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eaf46399..5c7afd10 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -171,8 +171,8 @@ jobs: - print-tool-versions - run: make build - run: make test - - run: make docs - - run: make lint-docs + #- run: make docs + #- run: make lint-docs - store_artifacts: { path: output } - store_test_results: { path: output/scan } - store_artifacts: { path: ~/Library/Logs/DiagnosticReports } @@ -222,10 +222,10 @@ workflows: matrix: parameters: xcode-version: ["11.7.0", *default-xcode-version] - - generate-docs: - filters: - branches: { only: master } - - deploy-docs: - requires: [ build-and-test, generate-docs ] - filters: - branches: { only: master } + #- generate-docs: + #filters: + #branches: { only: master } + #- deploy-docs: + #requires: [ build-and-test, generate-docs ] + #filters: + #branches: { only: master }