From eee8942e754579d48d094a6f993bf3eae861d685 Mon Sep 17 00:00:00 2001 From: "Cary A. Bakker" Date: Fri, 23 Sep 2022 16:34:07 -0400 Subject: [PATCH 1/3] Update APIs to use MobileCoinRng instead of RngSeed --- Sources/MobileCoinClient+Deprecated.swift | 29 ++++++------------- Sources/MobileCoinClient.swift | 18 +++++++++--- .../TransactionIdempotenceTests.swift | 6 ++-- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/Sources/MobileCoinClient+Deprecated.swift b/Sources/MobileCoinClient+Deprecated.swift index 4fde3919..e8d88cab 100644 --- a/Sources/MobileCoinClient+Deprecated.swift +++ b/Sources/MobileCoinClient+Deprecated.swift @@ -209,9 +209,10 @@ extension MobileCoinClient { } } + @available(*, deprecated, message: """ - Use the new `prepareTransaction(...)` that accepts a 32-byte rngSeed. + Use the `prepareTransaction(...)` that accepts a MobileCoinRng instead of RngSeed ``` public func prepareTransaction( @@ -219,42 +220,35 @@ extension MobileCoinClient { memoType: MemoType = .recoverable, amount: Amount, fee: UInt64, - rngSeed: RngSeed, + rng: MobileCoinRng, completion: @escaping ( Result ) -> Void ) { ``` - - this function creates a 32-byte seed by combining the data from 4 calls to rng.next() """) public func prepareTransaction( to recipient: PublicAddress, memoType: MemoType = .recoverable, amount: Amount, fee: UInt64, - rng: MobileCoinRng, + rngSeed: RngSeed, completion: @escaping ( Result ) -> Void ) { - guard let rngSeed = rng.generateRngSeed() else { - completion(.failure( - TransactionPreparationError.invalidInput("Could not create 32 byte RNG seed"))) - return - } prepareTransaction( to: recipient, memoType: memoType, amount: amount, fee: fee, - rngSeed: rngSeed, + rng: MobileCoinChaCha20Rng(rngSeed:rngSeed), completion: completion) } @available(*, deprecated, message: """ - Use the new `prepareTransaction(...)` that accepts a 32-byte rngSeed. + Use the `prepareTransaction(...)` that accepts a MobileCoinRng instead of an RngSeed ``` public func prepareTransaction( @@ -262,7 +256,7 @@ extension MobileCoinClient { memoType: MemoType = .recoverable, amount: Amount, feeLevel: FeeLevel = .minimum, - rngSeed: RngSeed, + rng: MobileCoinRng, completion: @escaping ( Result ) -> Void @@ -276,22 +270,17 @@ extension MobileCoinClient { memoType: MemoType = .recoverable, amount: Amount, feeLevel: FeeLevel = .minimum, - rng: MobileCoinRng, + rngSeed: RngSeed, completion: @escaping ( Result ) -> Void ) { - guard let rngSeed = rng.generateRngSeed() else { - completion(.failure( - TransactionPreparationError.invalidInput("Could not create 32-byte RNG seed"))) - return - } prepareTransaction( to: recipient, memoType: memoType, amount: amount, feeLevel: feeLevel, - rngSeed: rngSeed, + rng: MobileCoinChaCha20Rng(rngSeed:rngSeed), completion: completion) } diff --git a/Sources/MobileCoinClient.swift b/Sources/MobileCoinClient.swift index 6f397abf..307b1b37 100644 --- a/Sources/MobileCoinClient.swift +++ b/Sources/MobileCoinClient.swift @@ -203,7 +203,7 @@ public final class MobileCoinClient { memoType: memoType, amount: amount, fee: fee, - rngSeed: RngSeed(), + rng: MobileCoinChaCha20Rng(), completion: completion) } @@ -212,11 +212,16 @@ public final class MobileCoinClient { memoType: MemoType = .recoverable, amount: Amount, fee: UInt64, - rngSeed: RngSeed, + rng: MobileCoinRng, completion: @escaping ( Result ) -> Void ) { + guard let rngSeed = rng.generateRngSeed() else { + completion(.failure( + TransactionPreparationError.invalidInput("Could not create 32 byte RNG seed"))) + return + } Account.TransactionOperations( account: accountLock, fogMerkleProofService: serviceProvider.fogMerkleProofService, @@ -252,7 +257,7 @@ public final class MobileCoinClient { memoType: memoType, amount: amount, feeLevel: feeLevel, - rngSeed: RngSeed(), + rng: MobileCoinChaCha20Rng(), completion: completion) } @@ -261,11 +266,16 @@ public final class MobileCoinClient { memoType: MemoType = .recoverable, amount: Amount, feeLevel: FeeLevel = .minimum, - rngSeed: RngSeed, + rng: MobileCoinRng, completion: @escaping ( Result ) -> Void ) { + guard let rngSeed = rng.generateRngSeed() else { + completion(.failure( + TransactionPreparationError.invalidInput("Could not create 32-byte RNG seed"))) + return + } Account.TransactionOperations( account: accountLock, fogMerkleProofService: serviceProvider.fogMerkleProofService, diff --git a/Tests/Integration/Transaction/TransactionIdempotenceTests.swift b/Tests/Integration/Transaction/TransactionIdempotenceTests.swift index f6e62df1..67299782 100644 --- a/Tests/Integration/Transaction/TransactionIdempotenceTests.swift +++ b/Tests/Integration/Transaction/TransactionIdempotenceTests.swift @@ -77,7 +77,7 @@ class TransactionIdempotenceTests: XCTestCase { memoType: .unused, amount: amt, fee: IntegrationTestFixtures.fee, - rngSeed: rngSeed + rng: MobileCoinChaCha20Rng(rngSeed: rngSeed) ) { result in guard let payload = result.successOrFulfill(expectation: expect) else { return @@ -145,7 +145,7 @@ class TransactionIdempotenceTests: XCTestCase { memoType: .unused, amount: amt, fee: IntegrationTestFixtures.fee, - rngSeed: rngSeed + rng: MobileCoinChaCha20Rng(rngSeed: rngSeed) ) { result in guard let transaction1 = result.successOrFulfill(expectation: expect) else { return @@ -155,7 +155,7 @@ class TransactionIdempotenceTests: XCTestCase { memoType: .unused, amount: amt, fee: IntegrationTestFixtures.fee, - rngSeed: rngSeed + rng: MobileCoinChaCha20Rng(rngSeed: rngSeed) ) { guard let transaction2 = $0.successOrFulfill(expectation: expect) else { return From 7a6408cad6e5f77af2b4fbb2181cf84341fae9f2 Mon Sep 17 00:00:00 2001 From: "Cary A. Bakker" Date: Sun, 25 Sep 2022 11:53:01 -0400 Subject: [PATCH 2/3] Add test for Android-iOS Idempotence verification --- .../TransactionIdempotenceTests.swift | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/Tests/Integration/Transaction/TransactionIdempotenceTests.swift b/Tests/Integration/Transaction/TransactionIdempotenceTests.swift index 67299782..03e0926f 100644 --- a/Tests/Integration/Transaction/TransactionIdempotenceTests.swift +++ b/Tests/Integration/Transaction/TransactionIdempotenceTests.swift @@ -11,14 +11,62 @@ enum IdempotenceTestError: Error { class TransactionIdempotenceTests: XCTestCase { - func testIdempotenceSubmissionFailure() throws { + func testAndroidIdempotenceOutputPublicKeyMatch() throws { let description = "Testing idempotence submission failure" try testSupportedProtocols(description: description) { - try idempotenceSubmissionFailure(transportProtocol: $0, expectation: $1) + try androidIdempotenceOutputPublicKeyMatch(transportProtocol: $0, expectation: $1) } } - func idempotenceSubmissionFailure( + func androidIdempotenceOutputPublicKeyMatch( + transportProtocol: TransportProtocol, + expectation expect: XCTestExpectation + ) throws { + let rngSeedHex = + "676f746f2068747470733a2f2f6275792e6d6f62696c65636f696e2e636f6d00" + let recipientAddressHex = """ + 0a220a2048d9e6aa836d7aa57f7a9da9709603d8f5071faff4908c86ed829e68c0129f63\ + 12220a207ee52b7741a8b9f3701ab716fa361483b03ddcaeecb64ba64355a3411c87d43d + """ + let androidTxOutputPublicKeyHex = + "d47d4f6525cee846a47106e92de3e63e5b3cb677b8ae4df7efd667e2bad15719" + + let client = try IntegrationTestFixtures.createMobileCoinClient( + accountIndex: 1, + using: transportProtocol) + let rngSeed = try XCTUnwrap(RngSeed(try XCTUnwrap(Data(hexEncoded: rngSeedHex)))) + let recipientAddressData = try XCTUnwrap(Data(hexEncoded: recipientAddressHex)) + let recipient = try XCTUnwrap(PublicAddress(serializedData: recipientAddressData)) + let androidTxOutputPublicKey = try XCTUnwrap(Data(hexEncoded: androidTxOutputPublicKeyHex)) + let amt = Amount(mob: 100) + + client.updateBalances { + guard $0.successOrFulfill(expectation: expect) != nil else { return } + client.prepareTransaction( + to: recipient, + memoType: .unused, + amount: amt, + fee: IntegrationTestFixtures.fee, + rng: MobileCoinChaCha20Rng(rngSeed: rngSeed) + ) { result in + guard let payload = result.successOrFulfill(expectation: expect) else { + XCTFail("Invalid payload from prepareTransaction") + return + } + XCTAssertEqual(payload.payloadTxOutContext.txOutPublicKey, androidTxOutputPublicKey) + expect.fulfill() + } + } + } + + func testIdempotenceDoubleSubmissionFailure() throws { + let description = "Testing idempotence submission failure" + try testSupportedProtocols(description: description) { + try idempotenceDoubleSubmissionFailure(transportProtocol: $0, expectation: $1) + } + } + + func idempotenceDoubleSubmissionFailure( transportProtocol: TransportProtocol, expectation expect: XCTestExpectation ) throws { From 50c6a5c5bb979ffbfb43a66addcc5488994ce1b6 Mon Sep 17 00:00:00 2001 From: "Cary A. Bakker" Date: Mon, 26 Sep 2022 13:35:46 -0400 Subject: [PATCH 3/3] lint fix --- Sources/MobileCoinClient+Deprecated.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/MobileCoinClient+Deprecated.swift b/Sources/MobileCoinClient+Deprecated.swift index e8d88cab..219f9868 100644 --- a/Sources/MobileCoinClient+Deprecated.swift +++ b/Sources/MobileCoinClient+Deprecated.swift @@ -209,7 +209,6 @@ extension MobileCoinClient { } } - @available(*, deprecated, message: """ Use the `prepareTransaction(...)` that accepts a MobileCoinRng instead of RngSeed @@ -242,7 +241,7 @@ extension MobileCoinClient { memoType: memoType, amount: amount, fee: fee, - rng: MobileCoinChaCha20Rng(rngSeed:rngSeed), + rng: MobileCoinChaCha20Rng(rngSeed: rngSeed), completion: completion) } @@ -280,7 +279,7 @@ extension MobileCoinClient { memoType: memoType, amount: amount, feeLevel: feeLevel, - rng: MobileCoinChaCha20Rng(rngSeed:rngSeed), + rng: MobileCoinChaCha20Rng(rngSeed: rngSeed), completion: completion) }