2020-07-22 12:32:07 -07:00
//
// P e n d i n g T r a n s a c t i o n U p d a t e s T e s t . s w i f t
// Z c a s h L i g h t C l i e n t K i t - U n i t - T e s t s
//
// C r e a t e d b y F r a n c i s c o G i n d r e o n 7 / 1 7 / 2 0 .
//
import XCTest
@ testable import ZcashLightClientKit
class PendingTransactionUpdatesTest : XCTestCase {
var seedPhrase = " still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread " // TODO: P a r a m e t e r i z e t h i s f r o m e n v i r o n m e n t ?
let testRecipientAddress = " zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a " // TODO: P a r a m e t e r i z e t h i s f r o m e n v i r o n m e n t
let sendAmount : Int64 = 1000
var birthday : BlockHeight = 663150
let defaultLatestHeight : BlockHeight = 663175
var coordinator : TestCoordinator !
var syncedExpectation = XCTestExpectation ( description : " synced " )
var sentTransactionExpectation = XCTestExpectation ( description : " sent " )
var expectedReorgHeight : BlockHeight = 665188
var expectedRewindHeight : BlockHeight = 665188
var reorgExpectation : XCTestExpectation = XCTestExpectation ( description : " reorg " )
2021-05-18 14:22:29 -07:00
let branchID = " 2bb40e60 "
let chainName = " main "
2020-07-22 12:32:07 -07:00
override func setUpWithError ( ) throws {
coordinator = try TestCoordinator (
seed : seedPhrase ,
walletBirthday : birthday ,
channelProvider : ChannelProvider ( )
)
2021-05-18 14:22:29 -07:00
try coordinator . reset ( saplingActivation : 663150 , branchID : " e9ff75a6 " , chainName : " main " )
2020-07-22 12:32:07 -07:00
}
override func tearDownWithError ( ) throws {
NotificationCenter . default . removeObserver ( self )
try coordinator . stop ( )
try ? FileManager . default . removeItem ( at : coordinator . databases . cacheDB )
try ? FileManager . default . removeItem ( at : coordinator . databases . dataDB )
try ? FileManager . default . removeItem ( at : coordinator . databases . pendingDB )
}
@objc func handleReorg ( _ notification : Notification ) {
guard let reorgHeight = notification . userInfo ? [ CompactBlockProcessorNotificationKey . reorgHeight ] as ? BlockHeight
// l e t r e w i n d H e i g h t = n o t i f i c a t i o n . u s e r I n f o ? [ C o m p a c t B l o c k P r o c e s s o r N o t i f i c a t i o n K e y . r e w i n d H e i g h t ] a s ? B l o c k H e i g h t
else {
XCTFail ( " empty reorg notification " )
return
}
// X C T A s s e r t E q u a l ( r e w i n d H e i g h t , e x p e c t e d R e w i n d H e i g h t )
XCTAssertEqual ( reorgHeight , expectedReorgHeight )
reorgExpectation . fulfill ( )
}
func testPendingTransactionMinedHeightUpdated ( ) throws {
/*
1. create fake chain
*/
LoggerProxy . info ( " 1. create fake chain " )
2021-05-18 14:22:29 -07:00
try FakeChainBuilder . buildChain ( darksideWallet : coordinator . service , branchID : branchID , chainName : chainName )
2020-07-22 12:32:07 -07:00
try coordinator . applyStaged ( blockheight : 663188 )
sleep ( 2 )
let firstSyncExpectation = XCTestExpectation ( description : " first sync " )
/*
1 a . sync to latest height
*/
LoggerProxy . info ( " 1a. sync to latest height " )
try coordinator . sync ( completion : { ( s ) in
firstSyncExpectation . fulfill ( )
} , error : self . handleError )
wait ( for : [ firstSyncExpectation ] , timeout : 5 )
sleep ( 1 )
let sendExpectation = XCTestExpectation ( description : " send expectation " )
var p : PendingTransactionEntity ? = nil
/*
2. send transaction to recipient address
*/
LoggerProxy . info ( " 2. send transaction to recipient address " )
coordinator . synchronizer . sendToAddress ( spendingKey : self . coordinator . spendingKeys ! . first ! , zatoshi : 20000 , toAddress : self . testRecipientAddress , memo : " this is a test " , from : 0 , resultBlock : { ( result ) in
switch result {
case . failure ( let e ) :
self . handleError ( e )
case . success ( let pendingTx ) :
p = pendingTx
}
sendExpectation . fulfill ( )
} )
wait ( for : [ sendExpectation ] , timeout : 11 )
guard let pendingUnconfirmedTx = p else {
XCTFail ( " no pending transaction after sending " )
try coordinator . stop ( )
return
}
XCTAssertFalse ( pendingUnconfirmedTx . isConfirmed ( currentHeight : 663188 ) , " pending transaction evaluated as confirmed when it shouldn't " )
XCTAssertFalse ( pendingUnconfirmedTx . isMined , " pending transaction evaluated as mined when it shouldn't " )
XCTAssertTrue ( pendingUnconfirmedTx . isPending ( currentHeight : 663188 ) , " pending transaction evaluated as not pending when it should be " )
/* *
3. getIncomingTransaction
*/
LoggerProxy . info ( " 3. getIncomingTransaction " )
guard let incomingTx = try coordinator . getIncomingTransactions ( ) ? . first else {
XCTFail ( " no incoming transaction " )
try coordinator . stop ( )
return
}
let sentTxHeight : BlockHeight = 663189
/*
4. stage transaction at sentTxHeight
*/
LoggerProxy . info ( " 4. stage transaction at \( sentTxHeight ) " )
try coordinator . stageBlockCreate ( height : sentTxHeight )
try coordinator . stageTransaction ( incomingTx , at : sentTxHeight )
/*
5. applyHeight ( sentTxHeight )
*/
LoggerProxy . info ( " 5. applyHeight( \( sentTxHeight ) ) " )
try coordinator . applyStaged ( blockheight : sentTxHeight )
sleep ( 2 )
/*
6. sync to latest height
*/
LoggerProxy . info ( " 6. sync to latest height " )
let secondSyncExpectation = XCTestExpectation ( description : " after send expectation " )
try coordinator . sync ( completion : { ( s ) in
secondSyncExpectation . fulfill ( )
} , error : self . handleError )
wait ( for : [ secondSyncExpectation ] , timeout : 5 )
XCTAssertEqual ( coordinator . synchronizer . pendingTransactions . count , 1 )
guard let afterStagePendingTx = coordinator . synchronizer . pendingTransactions . first else {
return
}
/*
6 a . verify that there ' s a pending transaction with a mined height of sentTxHeight
*/
LoggerProxy . info ( " 6a. verify that there's a pending transaction with a mined height of \( sentTxHeight ) " )
XCTAssertEqual ( afterStagePendingTx . minedHeight , sentTxHeight )
XCTAssertTrue ( afterStagePendingTx . isMined , " pending transaction shown as unmined when it has been mined " )
XCTAssertTrue ( afterStagePendingTx . isPending ( currentHeight : sentTxHeight ) )
/*
7. stage 15 blocks from sentTxHeight
*/
LoggerProxy . info ( " 7. stage 15 blocks from \( sentTxHeight ) " )
try coordinator . stageBlockCreate ( height : sentTxHeight + 1 , count : 15 )
sleep ( 2 )
let lastStageHeight = sentTxHeight + 14
LoggerProxy . info ( " applyStaged( \( lastStageHeight ) ) " )
try coordinator . applyStaged ( blockheight : lastStageHeight )
sleep ( 2 )
let syncToConfirmExpectation = XCTestExpectation ( description : " sync to confirm expectation " )
/*
8. last sync to latest height
*/
LoggerProxy . info ( " last sync to latest height: \( lastStageHeight ) " )
try coordinator . sync ( completion : { ( s ) in
syncToConfirmExpectation . fulfill ( )
} , error : self . handleError )
wait ( for : [ syncToConfirmExpectation ] , timeout : 6 )
var supposedlyPendingUnexistingTransaction : PendingTransactionEntity ? = nil
XCTAssertNoThrow ( try { supposedlyPendingUnexistingTransaction = try coordinator . synchronizer . allPendingTransactions ( ) . first } ( ) )
XCTAssertNil ( supposedlyPendingUnexistingTransaction )
}
func handleError ( _ error : Error ? ) {
_ = try ? coordinator . stop ( )
guard let testError = error else {
XCTFail ( " failed with nil error " )
return
}
XCTFail ( " Failed with error: \( testError ) " )
}
func hookToReOrgNotification ( ) {
NotificationCenter . default . addObserver ( self , selector : #selector ( handleReorg ( _ : ) ) , name : . blockProcessorHandledReOrg , object : nil )
}
}