Skip to content

Commit 725a390

Browse files
committed
Deduplicate bitcoin tests between CI and Xcode project.
1 parent 69af429 commit 725a390

File tree

8 files changed

+224
-49
lines changed

8 files changed

+224
-49
lines changed

ci/LDKSwift/Tests/LDKSwiftTests/HumanObjectPeerTestInstance.swift

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
// Created by Arik Sosman on 7/22/21.
66
//
77

8-
import XCTest
8+
#if os(Linux)
99
import LDKSwift
1010
import LDKHeaders
11+
#endif
12+
import XCTest
1113

1214
public class HumanObjectPeerTestInstance {
1315

@@ -53,6 +55,10 @@ public class HumanObjectPeerTestInstance {
5355
private(set) var tcpSocketHandler: TCPPeerHandler?
5456
private(set) var tcpPort: UInt16?
5557

58+
fileprivate enum SocketBindError: Error {
59+
case failedToBindSocket
60+
}
61+
5662
fileprivate actor PendingEventTracker {
5763

5864
private(set) var pendingManagerEvents: [Event] = []
@@ -206,11 +212,11 @@ public class HumanObjectPeerTestInstance {
206212
}
207213

208214
func handle_event(event: Event) {
209-
let eventClone = event.clone()
210-
print("peer \(self.master.seed) received event: \(eventClone.getValueType())")
215+
// let eventClone = event.clone()
216+
print("peer \(self.master.seed) received event: \(event.getValueType())")
211217
Task {
212218
// clone to avoid deallocation-related issues
213-
await master.pendingEventTracker.addEvent(event: eventClone)
219+
await master.pendingEventTracker.addEvent(event: event)
214220
}
215221
}
216222

@@ -298,7 +304,7 @@ public class HumanObjectPeerTestInstance {
298304
self.peerManager = PeerManager(message_handler: messageHandler, our_node_secret: nodeSecret, ephemeral_random_data: randomData, logger: self.logger, custom_message_handler: IgnoringMessageHandler().as_CustomMessageHandler())
299305
}
300306
self.nodeId = self.channelManager.get_our_node_id()
301-
self.bindSocketHandler()
307+
try! self.bindSocketHandler()
302308
}
303309

304310
fileprivate convenience init(original: Peer) {
@@ -323,22 +329,23 @@ public class HumanObjectPeerTestInstance {
323329
managerResult.getValue()!
324330
}
325331
self.nodeId = self.channelManager.get_our_node_id()
326-
self.bindSocketHandler()
332+
try! self.bindSocketHandler()
327333
}
328334

329-
private func bindSocketHandler() {
335+
private func bindSocketHandler() throws {
330336
if !self.master.use_nio_peer_handler {
331337
return
332338
}
333339
self.tcpSocketHandler = self.constructor!.getTCPPeerHandler()
334-
for i in 1...10000 {
340+
for i in 10000...65535 {
335341
let port = UInt16(i)
336342
let bound = self.tcpSocketHandler!.bind(address: "127.0.0.1", port: port)
337343
if bound {
338344
self.tcpPort = port
339345
return
340346
}
341347
}
348+
throw SocketBindError.failedToBindSocket
342349
}
343350

344351
fileprivate func payInvoice() {
@@ -416,6 +423,53 @@ public class HumanObjectPeerTestInstance {
416423
}
417424
}
418425

426+
func test_multiple_peer_connections() async {
427+
let peerA = Peer(master: self, seed: 1)
428+
let peerB = Peer(master: self, seed: 2)
429+
let peerC = Peer(master: self, seed: 3)
430+
431+
let originalPeersA = peerA.peerManager.get_peer_node_ids()
432+
let originalPeersB = peerB.peerManager.get_peer_node_ids()
433+
let originalPeersC = peerC.peerManager.get_peer_node_ids()
434+
XCTAssertEqual(originalPeersA.count, 0)
435+
XCTAssertEqual(originalPeersB.count, 0)
436+
XCTAssertEqual(originalPeersC.count, 0)
437+
438+
do {
439+
connectPeers(peerA: peerA, peerB: peerB)
440+
441+
// sleep for one second
442+
try! await Task.sleep(nanoseconds: 1_000_000_000)
443+
let connectedPeersA = peerA.peerManager.get_peer_node_ids()
444+
let connectedPeersB = peerB.peerManager.get_peer_node_ids()
445+
XCTAssertEqual(connectedPeersA.count, 1)
446+
XCTAssertEqual(connectedPeersB.count, 1)
447+
}
448+
449+
do {
450+
connectPeers(peerA: peerA, peerB: peerC)
451+
452+
// sleep for one second
453+
try! await Task.sleep(nanoseconds: 1_000_000_000)
454+
let connectedPeersA = peerA.peerManager.get_peer_node_ids()
455+
let connectedPeersC = peerC.peerManager.get_peer_node_ids()
456+
XCTAssertEqual(connectedPeersA.count, 2)
457+
XCTAssertEqual(connectedPeersC.count, 1)
458+
}
459+
460+
do {
461+
// sleep for a total of 10 seconds
462+
for i in 0..<100 {
463+
// sleep for 100ms
464+
try! await Task.sleep(nanoseconds: 0_100_000_000)
465+
}
466+
467+
peerA.constructor?.interrupt()
468+
peerB.constructor?.interrupt()
469+
peerC.constructor?.interrupt()
470+
}
471+
}
472+
419473
func do_test_message_handler() async {
420474

421475
let FUNDING_SATOSHI_AMOUNT: UInt64 = 100_000 // 100k satoshis

ci/LDKSwift/Tests/LDKSwiftTests/LDKSwiftTests.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,7 @@ class LDKSwiftTests: XCTestCase {
206206
print("net graph available!")
207207
}
208208

209-
210-
Bindings.setLogThreshold(severity: .WARNING)
209+
// Bindings.setLogThreshold(severity: .WARNING)
211210

212211
// bitrefill
213212
tcpPeerHandler.connect(address: "52.50.244.44", port: 9735, theirNodeId: Self.hexStringToBytes(hexString: "030c3f19d742ca294a55c00376b3b355c3c90d61c6b6b39554dbc7ac19b141c14f")!)

ci/LDKSwift/Tests/LDKSwiftTests/bitcoin/BTCBlock.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
// Created by Arik Sosman on 3/28/22.
66
//
77

8+
#if os(Linux)
89
import LDKSwift
910
import LDKHeaders
11+
#endif
12+
import XCTest
1013

1114
/// serialization:
1215
/// 4 bytes: 0xD9B4BEF9

ci/LDKSwift/Tests/LDKSwiftTests/bitcoin/BTCHashing.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
// Created by Arik Sosman on 3/29/22.
66
//
77

8+
#if os(Linux)
89
import LDKSwift
910
import LDKHeaders
11+
#endif
1012
import Crypto
1113

1214
class BTCHashing {

ci/LDKSwift/Tests/LDKSwiftTests/bitcoin/BTCTransaction.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
// Created by Arik Sosman on 3/29/22.
66
//
77

8+
#if os(Linux)
89
import LDKSwift
910
import LDKHeaders
11+
#endif
1012

1113
class BTCTransaction: Equatable {
1214

ci/LDKSwift/Tests/LDKSwiftTests/bitcoin/BTCVarInt.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
// Created by Arik Sosman on 3/29/22.
66
//
77

8+
#if os(Linux)
89
import LDKSwift
910
import LDKHeaders
11+
#endif
1012

1113
public class BTCVarInt {
1214

ci/LDKSwift/Tests/LDKSwiftTests/bitcoin/BitcoinTests.swift

Lines changed: 128 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,34 @@
55
// Created by Arik Sosman on 3/29/22.
66
//
77

8-
import XCTest
8+
#if os(Linux)
99
import LDKSwift
1010
import LDKHeaders
11+
#endif
12+
import XCTest
1113

1214
public class BitcoinTests: XCTestCase {
13-
15+
1416
func testVarInt() throws {
1517
do {
1618
let varInt = BTCVarInt(0xfc)
1719
let serialization = varInt.serialize()
1820
XCTAssertEqual(serialization, [0xfc])
1921
}
20-
22+
2123
do {
2224
let varInt = BTCVarInt(0xfd)
2325
let serialization = varInt.serialize()
2426
XCTAssertEqual(serialization, [0xfd, 0xfd, 0])
2527
}
26-
28+
2729
do {
2830
let varInt = BTCVarInt(0xfe)
2931
let serialization = varInt.serialize()
3032
XCTAssertEqual(serialization, [0xfd, 0xfe, 0])
3133
}
3234
}
33-
35+
3436
func testBlockHashing() throws {
3537
let block = BTCBlock()
3638
block.version = 1
@@ -40,19 +42,19 @@ public class BitcoinTests: XCTestCase {
4042
block.difficultyTarget = 440711666
4143
block.nonce = 2504433986
4244
let hash = block.calculateHash();
43-
45+
4446
for i in 1...8 {
4547
// verify that the hash worked correctly with enough trailing 0s
4648
XCTAssertEqual(hash[hash.count - i], 0)
4749
}
48-
50+
4951
// sanity check that the hash is not all 0s
5052
XCTAssertNotEqual(hash[hash.count - 9], 0)
51-
53+
5254
// verify that the leading byte is nonzero
5355
XCTAssertNotEqual(hash[0], 0)
5456
}
55-
57+
5658
func testBlockSerialization() throws {
5759
let block = BTCBlock()
5860
block.version = 2
@@ -61,28 +63,28 @@ public class BitcoinTests: XCTestCase {
6163
block.timestamp = 42
6264
block.difficultyTarget = 0
6365
block.nonce = 0
64-
66+
6567
let serialization = block.serialize()
6668
XCTAssertEqual(serialization, [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
6769
}
68-
70+
6971
func testTxSerialization() throws {
7072
let tx = BTCTransaction()
7173
tx.version = 1
7274
let input = BTCTransaction.Input(
7375
previousTransactionHash: BTCHashing.SHA_ZERO_HASH,
74-
previousOutputIndex: 0xffffffff, // coinbase transaction has a u32::MAX prev output index
76+
previousOutputIndex: 0xffffffff, // coinbase transaction has a u32::MAX prev output index
7577
script: []
7678
)
7779
tx.inputs = [input]
7880
tx.setWitnessForInput(inputIndex: 0, witness: BTCTransaction.Witness(stackElements: [[1]]))
79-
81+
8082
let output = BTCTransaction.Output(value: 100000, script: [0, 32, 214, 232, 96, 182, 226, 231, 42, 33, 219, 246, 121, 242, 58, 123, 110, 124, 118, 63, 70, 117, 109, 247, 0, 58, 172, 198, 127, 254, 216, 194, 41, 14])
8183
tx.outputs = [output]
8284
let txSerialization = tx.serialize()
8385
XCTAssertEqual(txSerialization.count, 99)
8486
XCTAssertEqual(txSerialization, [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 255, 1, 160, 134, 1, 0, 0, 0, 0, 0, 34, 0, 32, 214, 232, 96, 182, 226, 231, 42, 33, 219, 246, 121, 242, 58, 123, 110, 124, 118, 63, 70, 117, 109, 247, 0, 58, 172, 198, 127, 254, 216, 194, 41, 14, 1, 1, 1, 0, 0, 0, 0])
85-
87+
8688
let block = BTCBlock()
8789
block.version = 2
8890
block.previousBlockHash = BTCHashing.SHA_ZERO_HASH
@@ -94,5 +96,116 @@ public class BitcoinTests: XCTestCase {
9496
let blockSerialization = block.serialize()
9597
XCTAssertEqual(blockSerialization, [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 255, 1, 160, 134, 1, 0, 0, 0, 0, 0, 34, 0, 32, 214, 232, 96, 182, 226, 231, 42, 33, 219, 246, 121, 242, 58, 123, 110, 124, 118, 63, 70, 117, 109, 247, 0, 58, 172, 198, 127, 254, 216, 194, 41, 14, 1, 1, 1, 0, 0, 0, 0])
9698
}
97-
99+
100+
@available(iOS 15.0, *)
101+
func testRpcCalls() async throws {
102+
let username = ProcessInfo.processInfo.environment["BITCOIN_REGTEST_RPC_USERNAME"] ?? "polaruser" // "alice"
103+
let password = ProcessInfo.processInfo.environment["BITCOIN_REGTEST_RPC_PASSWORD"] ?? "polarpass" // "DONT_USE_THIS_YOU_WILL_GET_ROBBED"
104+
let port = NumberFormatter().number(from: ProcessInfo.processInfo.environment["BITCOIN_REGTEST_RPC_PORT"] ?? "") ?? 18443
105+
let rpcInterface = try RegtestBlockchainManager(rpcProtocol: .http, rpcDomain: "localhost", rpcPort: (port as! UInt), rpcUsername: username, rpcPassword: password)
106+
let chaintipHeight = try await rpcInterface.getChaintipHeight()
107+
XCTAssertGreaterThanOrEqual(chaintipHeight, 0)
108+
let chaintipHashImplicit = try await rpcInterface.getBlockHashHex(height: chaintipHeight)
109+
let chaintipHashExplicit = try await rpcInterface.getChaintipHashHex()
110+
XCTAssertEqual(chaintipHashImplicit, chaintipHashExplicit)
111+
let blockDetails = try await rpcInterface.getBlock(hash: chaintipHashExplicit)
112+
XCTAssertEqual(blockDetails.height, chaintipHeight)
113+
114+
let chainInfo = try await rpcInterface.getChainInfo()
115+
116+
let genesisHash = try await rpcInterface.getBlockHashHex(height: 1)
117+
let genesisDetails = try await rpcInterface.getBlock(hash: genesisHash)
118+
let genesisBinary = try await rpcInterface.getBlockBinary(hash: genesisHash)
119+
let genesisHeader = try await rpcInterface.getBlockHeader(hash: genesisHash)
120+
121+
let genesisCoinbaseTxHash = genesisDetails.tx.first!
122+
let genesisCoinbaseTx = try await rpcInterface.getTransaction(hash: genesisCoinbaseTxHash)
123+
124+
125+
// try? await rpcInterface.submitTransaction(transaction: modifiedCoinbaseTx)
126+
127+
// let address = try await rpcInterface.generateAddress()
128+
// let details = try await rpcInterface.mineBlocks(number: 1, coinbaseDestinationAddress: address)
129+
let helpDetails = try await rpcInterface.getHelp()
130+
// print(helpDetails)
131+
132+
let exampleFundingTx: [UInt8] = [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 255, 1, 160, 134, 1, 0, 0, 0, 0, 0, 34, 0, 32, 15, 45, 153, 123, 98, 37, 242, 142, 113, 51, 126, 45, 206, 175, 66, 247, 173, 2, 141, 2, 27, 84, 38, 188, 34, 74, 82, 164, 28, 229, 39, 139, 1, 1, 1, 0, 0, 0, 0]
133+
134+
// try? await rpcInterface.submitTransaction(transaction: exampleFundingTx)
135+
136+
137+
class Listener: BlockchainListener {
138+
var initializationComplete = false
139+
var newBlocksDetected = 0
140+
var blocksLost = 0
141+
142+
func blockConnected(block: [UInt8], height: UInt32) {
143+
if self.initializationComplete {
144+
self.newBlocksDetected += 1
145+
}
146+
let blockHash = LDKSwiftTests.bytesToHexString(bytes: BTCHashing.doubleSha256(block))
147+
// print("block connected at height \(height): \(blockHash)")
148+
}
149+
150+
func blockDisconnected(header: [UInt8]?, height: UInt32) {
151+
self.blocksLost += 1
152+
// print("block disconnected from height \(height): \(header)")
153+
}
154+
}
155+
156+
var listener = Listener()
157+
rpcInterface.registerListener(listener)
158+
159+
try await rpcInterface.preloadMonitor();
160+
// async let monitor = try rpcInterface.monitorBlockchain()
161+
listener.initializationComplete = true
162+
163+
let testAddress = try await rpcInterface.generateAddress()
164+
let exampleOutputScript: [UInt8] = [0, 32, 200, 194, 75, 55, 227, 33, 251, 71, 196, 33, 177, 196, 155, 145, 17, 78, 244, 226, 155, 141, 216, 230, 180, 183, 149, 172, 116, 249, 56, 6, 118, 255]
165+
let scriptInfo = try await rpcInterface.decodeScript(script: exampleOutputScript)
166+
let outputAddress = (scriptInfo["addresses"] as! [String]).first!
167+
try await rpcInterface.mineBlocks(number: 1, coinbaseDestinationAddress: testAddress)
168+
try await rpcInterface.mineBlocks(number: 1, coinbaseDestinationAddress: outputAddress)
169+
170+
// sleep for six seconds
171+
// try await Task.sleep(nanoseconds: 6_000_000_000)
172+
try await rpcInterface.reconcileChaintips()
173+
XCTAssertEqual(listener.newBlocksDetected, 2)
174+
XCTAssertEqual(listener.blocksLost, 0)
175+
176+
do {
177+
let testAddress = try await rpcInterface.generateAddress()
178+
let chaintip = try await rpcInterface.getChaintipHeight()
179+
let penultimateBlockHash = try await rpcInterface.getBlockHashHex(height: chaintip - 1)
180+
try await rpcInterface.unmineBlock(hash: penultimateBlockHash)
181+
try await rpcInterface.mineBlocks(number: 1, coinbaseDestinationAddress: testAddress)
182+
183+
try await rpcInterface.reconcileChaintips()
184+
XCTAssertEqual(listener.newBlocksDetected, 3)
185+
XCTAssertEqual(listener.blocksLost, 2)
186+
}
187+
188+
do {
189+
let testAddress = try await rpcInterface.generateAddress()
190+
let chaintipHash = try await rpcInterface.getChaintipHashHex()
191+
print("chaintip: \(chaintipHash)")
192+
try await rpcInterface.unmineBlock(hash: chaintipHash)
193+
try await rpcInterface.mineBlocks(number: 2, coinbaseDestinationAddress: testAddress)
194+
195+
try await rpcInterface.reconcileChaintips()
196+
XCTAssertEqual(listener.newBlocksDetected, 5)
197+
XCTAssertEqual(listener.blocksLost, 3)
198+
}
199+
200+
do {
201+
let chaintipHash = try await rpcInterface.getChaintipHashHex()
202+
print("chaintip: \(chaintipHash)")
203+
try await rpcInterface.unmineBlock(hash: chaintipHash)
204+
205+
try await rpcInterface.reconcileChaintips()
206+
XCTAssertEqual(listener.newBlocksDetected, 5)
207+
XCTAssertEqual(listener.blocksLost, 4)
208+
}
209+
}
210+
98211
}

0 commit comments

Comments
 (0)