MobileCoin-Swift/Sources/LibMobileCoin/ProtoExtensions.swift
Adam Mork 9bc59e1b98
v1.2.0-pre0 - Network Robustness, Fog 1.2.0, Apple Silicon/M1 & Mac Catalyst, LibMobileCoin v1.2.0-pre1 (#73)
# Title

`v1.2.0-pre0` - Network Robustness,  Fog 1.2.0, Apple Silicon/M1 & Mac Catalyst

# Description 

Added a way for implementing apps to pass in there own `HttpRequester` which can be useful for network robustness. Subspec `LibMobileCoin` now supports Apple Silicon/M1 and Mac Catalyst. Code changes to support Fog v1.2.0.

#### `pre1` Changes 

- Uses the `v1.2.0-pre1` version of `LibMobileCoin` which supports a higher version of `GRPC`.
- Added bridging headers
- Updated Gemfile/Makefile to use the latest `cocoapods` version `1.11.2`


#### Future Work

Fix the `docs` steps in the circleci build process. Will require `jazzy` related fixes and testing on Xcode 11.

# Changes

## Network Robustness

Adds a separate `HTTP` networking architecture. An object conforming to `protocol HttpRequester` can be provided to the `NetworkConfig` object when the `MobileCoinClient` is created. Then the `TransportProtocolOption` can be changed from `grpc` to `http`.

> NOTE: This branch will not run because it depends on changes in other submodules that have not yet been merged.

### `HttpRequester`

Implementing apps/frameworks should provide an object conforming to this protocol. Our `RestApiRequester` wraps around an `HttpRequester` to communicate with with our services using `protobuf`s.

```
Sources/Network/HttpConnection/HttpRequester.swift
```

### Attested & Auth Connection Wrappers

`HTTP` versions of the Auth & Attested wrapper classes. These protocol and their default implementations handle the logic paths needed for authentication/attestation and re-authentication/attestation:

> Can become generic

```
Sources/Network/HttpConnection/ArbitraryHttpConnection.swift
Sources/Network/HttpConnection/AttestedHttpConnection.swift
```

### Networking Protocols 

Separate code-paths for `HTTP` versions of the networking protocols:

```
Sources/Network/HttpConnection/HttpCallable/AttestedHttpCallable.swift
Sources/Network/HttpConnection/HttpCallable/AuthHttpCallable.swift
Sources/Network/HttpConnection/HttpCallable/AuthHttpCallableClientWrapper.swift
Sources/Network/HttpConnection/HttpCallable/HttpCallable.swift
```

`HTTP` "interfaces" that closely mimic functionality from `GRPC`. Allows us to re-use more of our existing patterns.

```
Sources/Network/HttpConnection/HTTPInterface/HTTPCallOptions.swift
Sources/Network/HttpConnection/HTTPInterface/HTTPClient.swift
Sources/Network/HttpConnection/HTTPInterface/HTTPClientCall.swift
Sources/Network/HttpConnection/HTTPInterface/HTTPMethod.swift
Sources/Network/HttpConnection/HTTPInterface/HTTPResponse.swift
Sources/Network/HttpConnection/HTTPInterface/HTTPStatus.swift
Sources/Network/HttpConnection/HTTPInterface/HTTPUnaryCall.swift
```

### `HTTP` Connection Implementations

Wrapper classes that interface directly with `protoc-swift` generated `.swift` files for our protobuf models.

```
Sources/Network/HttpConnection/HttpConnection.swift
Sources/Network/HttpConnection/HttpConnections/BlockchainHttpConnection.swift
Sources/Network/HttpConnection/HttpConnections/ConsensusHttpConnection.swift
Sources/Network/HttpConnection/HttpConnections/FogBlockHttpConnection.swift
Sources/Network/HttpConnection/HttpConnections/FogKeyImageHttpConnection.swift
Sources/Network/HttpConnection/HttpConnections/FogMerkleProofHttpConnection.swift
Sources/Network/HttpConnection/HttpConnections/FogReportHttpConnection.swift
Sources/Network/HttpConnection/HttpConnections/FogUntrustedTxOutHttpConnection.swift
Sources/Network/HttpConnection/HttpConnections/FogViewHttpConnection.swift
```

### `HTTP` versions of `protoc-swift` generated models

The GRPC versions of these are generated by `protoc-swift`. The HTTP versions were edited by hand to work with the `HTTP` Connections implementations. 

> **This could be automated preferably with a `protoc-swift` plugin template but also `sed`/`VIM` if needed.**

```
Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/attest.http.swift
Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_client.http.swift
Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/consensus_common.http.swift
Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/ledger.http.swift
Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/report.http.swift
Sources/Network/HttpConnection/HttpConnections/Http Proto Generated/view.http.swift
```

## Fog Updates 

The latest version of `fog` changes the name of a protobuf `FogLedger_Block` -> `FogLedger_BlockData`.

### Compressed Commitment 

The `TxOut` compressed commitment is no longer sent in the protobuf message because it can be reconstructed with its constituent parts (+ the user's `view_private_key`)

We now reconstruct the commitment in several places whereas before it was being returned from the decoded protobuf message.

Lastly some function signatures into `LibMobileCoin` were updated to adjust to the changes.

## Miscellaneous

New MrEnclave values

Support for Apple Silicon/M1 & Mac Catalyst

## Unit Tests

One unit test was removed. It creates a TxOut and tries to unmask the value with an **incorrect** private view key. The return value should be 'nil' but is noise. It will require a change in the rust code and should be implemented in a future release.

Some objects were re-serialized to match the new TxOut structure.

Credentials are not required for `consensus` so this has been changed in the `NetworkConfig`

Tests can be run with `TransportProtocol == .http` by changing the default value in `NetworkConfig`
2021-09-16 21:15:20 -07:00

184 lines
5.0 KiB
Swift

// swiftlint:disable:this file_name
//
// Copyright (c) 2020-2021 MobileCoin. All rights reserved.
//
import Foundation
import LibMobileCoin
// MARK: - External
extension External_RistrettoPrivate {
init<DataType: DataConvertible>(_ data: DataType) {
self.init()
self.data = data.data
}
}
extension External_CompressedRistretto {
init<DataType: DataConvertible>(_ data: DataType) {
self.init()
self.data = data.data
}
}
extension External_KeyImage {
init<DataType: DataConvertible>(_ data: DataType) {
self.init()
self.data = data.data
}
}
extension External_Amount {
init<CommitmentType: DataConvertible>(commitment: CommitmentType, maskedValue: UInt64) {
self.init()
self.commitment = External_CompressedRistretto(commitment)
self.maskedValue = maskedValue
}
}
extension External_EncryptedFogHint {
init<DataType: DataConvertible>(_ data: DataType) {
self.init()
self.data = data.data
}
}
// MARK: - Fog Common
extension FogCommon_BlockRange {
init(_ range: Range<UInt64>) {
self.init()
self.startBlock = range.lowerBound
self.endBlock = range.upperBound
}
var range: Range<UInt64> {
get { startBlock..<endBlock }
set {
startBlock = newValue.lowerBound
endBlock = newValue.upperBound
}
}
}
// MARK: - Fog View
extension FogView_RngRecord {
init(nonce fogRngKey: FogRngKey, startBlock: UInt64) {
self.init()
self.pubkey = KexRng_KexRngPubkey(fogRngKey)
self.startBlock = startBlock
}
}
extension FogView_TxOutSearchResult {
var resultCodeEnum: FogView_TxOutSearchResultCode {
get {
FogView_TxOutSearchResultCode(rawValue: Int(resultCode))
?? .UNRECOGNIZED(Int(resultCode))
}
set { resultCode = UInt32(newValue.rawValue) }
}
}
extension FogView_TxOutRecord {
var timestampDate: Date? {
get { timestamp != UInt64.max ? Date(timeIntervalSince1970: TimeInterval(timestamp)) : nil }
set {
if let newValue = newValue {
timestamp = UInt64(newValue.timeIntervalSince1970)
} else {
timestamp = UInt64.max
}
}
}
}
// MARK: - Fog Ledger
extension FogLedger_OutputResult {
var resultCodeEnum: FogLedger_OutputResultCode {
get {
FogLedger_OutputResultCode(rawValue: Int(resultCode)) ?? .UNRECOGNIZED(Int(resultCode))
}
set { resultCode = UInt32(newValue.rawValue) }
}
}
extension FogLedger_KeyImageResult {
var timestampDate: Date {
get { Date(timeIntervalSince1970: TimeInterval(timestamp)) }
set { timestamp = UInt64(newValue.timeIntervalSince1970) }
}
var timestampResultCodeEnum: Watcher_TimestampResultCode {
get {
Watcher_TimestampResultCode(rawValue: Int(timestampResultCode))
?? .UNRECOGNIZED(Int(timestampResultCode))
}
set { timestampResultCode = UInt32(newValue.rawValue) }
}
var keyImageResultCodeEnum: FogLedger_KeyImageResultCode {
get {
FogLedger_KeyImageResultCode(rawValue: Int(keyImageResultCode))
?? .UNRECOGNIZED(Int(keyImageResultCode))
}
set { keyImageResultCode = UInt32(newValue.rawValue) }
}
var timestampStatus: BlockMetadata.TimestampStatus? {
switch timestampResultCodeEnum {
case .timestampFound:
return .known(timestamp: timestampDate)
case .unavailable:
return .unavailable
case .watcherBehind, .watcherDatabaseError, .blockIndexOutOfBounds:
return .temporarilyUnknown
case .unusedField, .UNRECOGNIZED:
return nil
}
}
}
extension FogLedger_BlockRequest {
var rangeValues: [Range<UInt64>] {
get { ranges.map { $0.startBlock..<$0.endBlock } }
set { ranges = newValue.map { FogCommon_BlockRange($0) } }
}
}
extension FogLedger_BlockData {
var timestampDate: Date {
get { Date(timeIntervalSince1970: TimeInterval(timestamp)) }
set { timestamp = UInt64(newValue.timeIntervalSince1970) }
}
var timestampResultCodeEnum: Watcher_TimestampResultCode {
get {
Watcher_TimestampResultCode(rawValue: Int(timestampResultCode))
?? .UNRECOGNIZED(Int(timestampResultCode))
}
set { timestampResultCode = UInt32(newValue.rawValue) }
}
var timestampStatus: BlockMetadata.TimestampStatus? {
switch timestampResultCodeEnum {
case .timestampFound:
return .known(timestamp: timestampDate)
case .unavailable:
return .unavailable
case .watcherBehind, .watcherDatabaseError, .blockIndexOutOfBounds:
return .temporarilyUnknown
case .unusedField, .UNRECOGNIZED:
return nil
}
}
var metadata: BlockMetadata {
BlockMetadata(index: index, timestampStatus: timestampStatus)
}
}