Skip to content

Commit

Permalink
[Wallet] State synchronisation (#274)
Browse files Browse the repository at this point in the history
State sync
  • Loading branch information
flypaper0 authored and llbartekll committed Jul 5, 2022
1 parent d72e08a commit ec9f3a3
Show file tree
Hide file tree
Showing 25 changed files with 289 additions and 101 deletions.
6 changes: 3 additions & 3 deletions Example/DApp/Connect/ConnectViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ class ConnectViewController: UIViewController, UITableViewDataSource, UITableVie
super.viewDidLoad()
DispatchQueue.global().async { [unowned self] in
if let qrImage = generateQRCode(from: uriString) {
DispatchQueue.main.async {
connectView.qrCodeView.image = qrImage
connectView.copyButton.isHidden = false
DispatchQueue.main.async { [self] in
self.connectView.qrCodeView.image = qrImage
self.connectView.copyButton.isHidden = false
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions Example/ExampleApp/Wallet/WalletViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ extension WalletViewController {
return settledSessions.map { session -> ActiveSessionItem in
let app = session.peer
return ActiveSessionItem(
dappName: app.name ?? "",
dappURL: app.url ?? "",
dappName: app.name ,
dappURL: app.url ,
iconURL: app.icons.first ?? "",
topic: session.topic)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Chat/Types/ChatRequestParams.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ enum ChatRequestParams: Codable, Equatable {
}

extension JSONRPCRequest {
init(id: Int64 = JSONRPCRequest.generateId(), params: T) where T == ChatRequestParams {
init(id: Int64 = JsonRpcID.generate(), params: T) where T == ChatRequestParams {
var method: String!
switch params {
case .invite:
Expand Down
8 changes: 5 additions & 3 deletions Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ final class ApproveEngine {
}
proposalPayloadsStore.delete(forKey: proposerPubKey)
try await networkingInteractor.respondError(payload: payload, reason: reason)
// TODO: Delete pairing if inactive
// TODO: Delete pairing if inactive
}

func settle(topic: String, proposal: SessionProposal, namespaces: [String: SessionNamespace]) async throws {
guard let agreementKeys = try kms.getAgreementSecret(for: topic) else {
guard let agreementKeys = kms.getAgreementSecret(for: topic) else {
throw Errors.agreementMissingOrInvalid
}
let selfParticipant = Participant(
Expand All @@ -120,6 +120,7 @@ final class ApproveEngine {

let session = WCSession(
topic: topic,
timestamp: Date(),
selfParticipant: selfParticipant,
peerParticipant: proposal.proposer,
settleParams: settleParams,
Expand Down Expand Up @@ -294,7 +295,7 @@ private extension ApproveEngine {
}

let topic = payload.topic
let agreementKeys = try kms.getAgreementSecret(for: topic)!
let agreementKeys = kms.getAgreementSecret(for: topic)!
let selfParticipant = Participant(
publicKey: agreementKeys.publicKey.hexRepresentation,
metadata: metadata
Expand All @@ -305,6 +306,7 @@ private extension ApproveEngine {

let session = WCSession(
topic: topic,
timestamp: Date(),
selfParticipant: selfParticipant,
peerParticipant: settleParams.controller,
settleParams: settleParams,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,42 +50,46 @@ final class ControllerSessionStateMachine {

private func handleResponse(_ response: WCResponse) {
switch response.requestParams {
case .sessionUpdate:
handleUpdateResponse(topic: response.topic, result: response.result)
case .sessionExtend:
handleUpdateExpiryResponse(topic: response.topic, result: response.result)
case .sessionUpdate(let payload):
handleUpdateResponse(response: response, payload: payload)
case .sessionExtend(let payload):
handleUpdateExpiryResponse(response: response, payload: payload)
default:
break
}
}

// TODO: Re-enable callback
private func handleUpdateResponse(topic: String, result: JsonRpcResult) {
guard let _ = sessionStore.getSession(forTopic: topic) else {
return
}
switch result {
private func handleUpdateResponse(response: WCResponse, payload: SessionType.UpdateParams) {
guard var session = sessionStore.getSession(forTopic: response.topic) else { return }
switch response.result {
case .response:
// TODO - state sync
// onNamespacesUpdate?(session.topic, session.namespaces)
break
do {
try session.updateNamespaces(payload.namespaces, timestamp: response.timestamp)

if sessionStore.setSessionIfNewer(session) {
onNamespacesUpdate?(session.topic, session.namespaces)
}
} catch {
logger.error("Update namespaces error: \(error.localizedDescription)")
}
case .error:
// TODO - state sync
logger.error("Peer failed to update methods.")
logger.error("Peer failed to update session")
}
}

private func handleUpdateExpiryResponse(topic: String, result: JsonRpcResult) {
guard let session = sessionStore.getSession(forTopic: topic) else {
return
}
switch result {
private func handleUpdateExpiryResponse(response: WCResponse, payload: SessionType.UpdateExpiryParams) {
guard var session = sessionStore.getSession(forTopic: response.topic) else { return }
switch response.result {
case .response:
// TODO - state sync
onExtend?(session.topic, session.expiryDate)
do {
try session.updateExpiry(to: payload.expiry)
sessionStore.setSession(session)
onExtend?(session.topic, session.expiryDate)
} catch {
logger.error("Update expiry error: \(error.localizedDescription)")
}
case .error:
// TODO - state sync
logger.error("Peer failed to update events.")
logger.error("Peer failed to extend session")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ final class NonControllerSessionStateMachine {
throw Errors.respondError(payload: payload, reason: .unauthorizedUpdateNamespacesRequest)
}
do {
try session.updateNamespaces(updateParams.namespaces)
try session.updateNamespaces(updateParams.namespaces, timestamp: payload.timestamp)
} catch {
throw Errors.respondError(payload: payload, reason: .invalidUpdateNamespaceRequest)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/WalletConnectSign/Namespace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public struct SessionNamespace: Equatable, Codable {
self.methods = methods
self.events = events
}

func isSuperset(of other: Extension) -> Bool {
self.accounts.isSuperset(of: other.accounts) &&
self.methods.isSuperset(of: other.methods) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ import Combine
import WalletConnectUtils
import WalletConnectKMS

struct WCResponse: Codable {
let topic: String
let chainId: String?
let requestMethod: WCRequest.Method
let requestParams: WCRequest.Params
let result: JsonRpcResult
}

protocol NetworkInteracting: AnyObject {
var transportConnectionPublisher: AnyPublisher<Void, Never> {get}
var wcRequestPublisher: AnyPublisher<WCRequestSubscriptionPayload, Never> {get}
Expand Down
6 changes: 1 addition & 5 deletions Sources/WalletConnectSign/Request.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,10 @@ public struct Request: Codable, Equatable {
}

public init(topic: String, method: String, params: AnyCodable, chainId: Blockchain) {
self.id = Self.generateId()
self.id = JsonRpcID.generate()
self.topic = topic
self.method = method
self.params = params
self.chainId = chainId
}

public static func generateId() -> Int64 {
return Int64(Date().timeIntervalSince1970 * 1000)*1000 + Int64.random(in: 0..<1000)
}
}
14 changes: 10 additions & 4 deletions Sources/WalletConnectSign/Storage/SequenceStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ protocol Expirable {
var expiryDate: Date { get }
}

protocol ExpirableSequence: Codable, Expirable {
protocol Entitled {
var topic: String { get }
}

// TODO: Find replacement for 'Sequence' prefix
final class SequenceStore<T> where T: ExpirableSequence {
typealias SequenceObject = Entitled & Expirable & Codable

final class SequenceStore<T> where T: SequenceObject {

var onSequenceExpiration: ((_ sequence: T) -> Void)?

Expand Down Expand Up @@ -47,8 +48,13 @@ final class SequenceStore<T> where T: ExpirableSequence {
func deleteAll() {
store.deleteAll()
}
}

// MARK: Privates

private extension SequenceStore {

private func verifyExpiry(on sequence: T) -> T? {
func verifyExpiry(on sequence: T) -> T? {
let now = dateInitializer()
if now >= sequence.expiryDate {
store.delete(forKey: sequence.topic)
Expand Down
21 changes: 20 additions & 1 deletion Sources/WalletConnectSign/Storage/SessionStorage.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
protocol WCSessionStorage: AnyObject {
var onSessionExpiration: ((WCSession) -> Void)? { get set }
func hasSession(forTopic topic: String) -> Bool
@discardableResult
func setSessionIfNewer(_ session: WCSession) -> Bool
func setSession(_ session: WCSession)
func hasSession(forTopic topic: String) -> Bool
func getSession(forTopic topic: String) -> WCSession?
func getAll() -> [WCSession]
func delete(topic: String)
Expand Down Expand Up @@ -29,6 +31,13 @@ final class SessionStorage: WCSessionStorage {
storage.setSequence(session)
}

@discardableResult
func setSessionIfNewer(_ session: WCSession) -> Bool {
guard isNeedToReplace(session) else { return false }
storage.setSequence(session)
return true
}

func getSession(forTopic topic: String) -> WCSession? {
return try? storage.getSequence(forTopic: topic)
}
Expand All @@ -45,3 +54,13 @@ final class SessionStorage: WCSessionStorage {
storage.deleteAll()
}
}

// MARK: Privates

private extension SessionStorage {

func isNeedToReplace(_ session: WCSession) -> Bool {
guard let old = getSession(forTopic: session.topic) else { return true }
return session.timestamp > old.timestamp
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import Foundation
import WalletConnectUtils

struct WCRequestSubscriptionPayload: Codable {
let topic: String
let wcRequest: WCRequest

var timestamp: Date {
return JsonRpcID.timestamp(from: wcRequest.id)
}
}
2 changes: 1 addition & 1 deletion Sources/WalletConnectSign/Types/Pairing/WCPairing.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import WalletConnectKMS

struct WCPairing: ExpirableSequence {
struct WCPairing: SequenceObject {
let topic: String
let relay: RelayProtocolOptions
var peerMetadata: AppMetadata?
Expand Down
Loading

0 comments on commit ec9f3a3

Please sign in to comment.