Outbound transaction reorg handling proposal (#48)
* Outbound transaction reorg handling proposal * Add rewind distance * include rewind on reorg notification, use it to refresh pending transactions
This commit is contained in:
parent
a139ffbdfe
commit
5930fbed6f
|
@ -19,6 +19,7 @@ public struct CompactBlockProcessorNotificationKey {
|
|||
public static let progressHeight = "CompactBlockProcessorNotificationKey.progressHeight"
|
||||
public static let reorgHeight = "CompactBlockProcessorNotificationKey.reorgHeight"
|
||||
public static let latestScannedBlockHeight = "CompactBlockProcessorNotificationKey.latestScannedBlockHeight"
|
||||
public static let rewindHeight = "CompactBlockProcessorNotificationKey.rewindHeight"
|
||||
}
|
||||
|
||||
public extension Notification.Name {
|
||||
|
@ -313,9 +314,6 @@ public class CompactBlockProcessor {
|
|||
// cancel all Tasks
|
||||
queue.cancelAllOperations()
|
||||
|
||||
// notify reorg
|
||||
NotificationCenter.default.post(name: Notification.Name.blockProcessorHandledReOrg, object: self, userInfo: [CompactBlockProcessorNotificationKey.reorgHeight : height])
|
||||
|
||||
// register latest failure
|
||||
self.lastChainValidationFailure = height
|
||||
self.consecutiveChainValidationErrors = self.consecutiveChainValidationErrors + 1
|
||||
|
@ -328,6 +326,10 @@ public class CompactBlockProcessor {
|
|||
return
|
||||
}
|
||||
|
||||
// notify reorg
|
||||
NotificationCenter.default.post(name: Notification.Name.blockProcessorHandledReOrg, object: self, userInfo: [CompactBlockProcessorNotificationKey.reorgHeight : height,
|
||||
CompactBlockProcessorNotificationKey.rewindHeight : rewindHeight])
|
||||
|
||||
do {
|
||||
try downloader.rewind(to: rewindHeight)
|
||||
// process next batch
|
||||
|
|
|
@ -19,6 +19,7 @@ enum TransactionManagerError: Error {
|
|||
|
||||
class PersistentTransactionManager: OutboundTransactionManager {
|
||||
|
||||
|
||||
var repository: PendingTransactionRepository
|
||||
var encoder: TransactionEncoder
|
||||
var service: LightWalletService
|
||||
|
@ -126,6 +127,19 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
|||
return tx
|
||||
}
|
||||
|
||||
func handleReorg(at height: BlockHeight) throws {
|
||||
guard let affectedTxs = try self.allPendingTransactions()?.filter({ $0.minedHeight >= height }) else {
|
||||
return
|
||||
}
|
||||
|
||||
try affectedTxs.map { (tx) -> PendingTransactionEntity in
|
||||
var updatedTx = tx
|
||||
updatedTx.minedHeight = -1
|
||||
return updatedTx
|
||||
} .forEach({ try self.repository.update($0) })
|
||||
|
||||
}
|
||||
|
||||
func monitorChanges(byId: Int, observer: Any) {
|
||||
// TODO: Implement this
|
||||
}
|
||||
|
|
|
@ -30,4 +30,6 @@ protocol OutboundTransactionManager {
|
|||
func cancel(pendingTransaction: PendingTransactionEntity) -> Bool
|
||||
|
||||
func allPendingTransactions() throws -> [PendingTransactionEntity]?
|
||||
|
||||
func handleReorg(at: BlockHeight) throws
|
||||
}
|
||||
|
|
|
@ -100,9 +100,12 @@ public class SDKSynchronizer: Synchronizer {
|
|||
|
||||
center.addObserver(self,
|
||||
selector: #selector(applicationDidBecomeActive(_:)),
|
||||
name: UIApplication.didBecomeActiveNotification, object: nil)
|
||||
name: UIApplication.didBecomeActiveNotification,
|
||||
object: nil)
|
||||
|
||||
center.addObserver(self, selector: #selector(applicationWillTerminate(_:)), name: UIApplication.willTerminateNotification,
|
||||
center.addObserver(self,
|
||||
selector: #selector(applicationWillTerminate(_:)),
|
||||
name: UIApplication.willTerminateNotification,
|
||||
object: nil)
|
||||
|
||||
center.addObserver(self,
|
||||
|
@ -178,10 +181,32 @@ public class SDKSynchronizer: Synchronizer {
|
|||
selector: #selector(processorTransitionUnknown(_:)),
|
||||
name: Notification.Name.blockProcessorUnknownTransition,
|
||||
object: processor)
|
||||
|
||||
center.addObserver(self,
|
||||
selector: #selector(reorgDetected(_:)),
|
||||
name: Notification.Name.blockProcessorHandledReOrg,
|
||||
object: processor)
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: Block Processor notifications
|
||||
|
||||
@objc func reorgDetected(_ notification: Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let progress = userInfo[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||
let rewindHeight = userInfo[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight else {
|
||||
print("error processing reorg notification")
|
||||
return }
|
||||
|
||||
print("handling reorg at: \(progress) with rewind height: \(rewindHeight)")
|
||||
do {
|
||||
try transactionManager.handleReorg(at: rewindHeight)
|
||||
} catch {
|
||||
print("error handling reorg: \(error)") // TODO: handle and propagate Error
|
||||
}
|
||||
}
|
||||
|
||||
@objc func processorUpdated(_ notification: Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let progress = userInfo[CompactBlockProcessorNotificationKey.progress] as? Float,
|
||||
|
|
|
@ -67,8 +67,11 @@ class CompactBlockReorgTests: XCTestCase {
|
|||
@objc func processorHandledReorg(_ notification: Notification) {
|
||||
DispatchQueue.main.sync {
|
||||
XCTAssertNotNil(notification.userInfo)
|
||||
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight {
|
||||
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
||||
XCTAssertTrue( reorg == 0 || reorg > SAPLING_ACTIVATION_HEIGHT)
|
||||
XCTAssertTrue( rewind == 0 || rewind > SAPLING_ACTIVATION_HEIGHT)
|
||||
XCTAssertTrue( rewind <= reorg )
|
||||
} else {
|
||||
XCTFail("CompactBlockProcessor reorg notification is malformed")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue