5
5
// Created by Arik Sosman on 3/29/22.
6
6
//
7
7
8
- import XCTest
8
+ #if os(Linux)
9
9
import LDKSwift
10
10
import LDKHeaders
11
+ #endif
12
+ import XCTest
11
13
12
14
public class BitcoinTests : XCTestCase {
13
-
15
+
14
16
func testVarInt( ) throws {
15
17
do {
16
18
let varInt = BTCVarInt ( 0xfc )
17
19
let serialization = varInt. serialize ( )
18
20
XCTAssertEqual ( serialization, [ 0xfc ] )
19
21
}
20
-
22
+
21
23
do {
22
24
let varInt = BTCVarInt ( 0xfd )
23
25
let serialization = varInt. serialize ( )
24
26
XCTAssertEqual ( serialization, [ 0xfd , 0xfd , 0 ] )
25
27
}
26
-
28
+
27
29
do {
28
30
let varInt = BTCVarInt ( 0xfe )
29
31
let serialization = varInt. serialize ( )
30
32
XCTAssertEqual ( serialization, [ 0xfd , 0xfe , 0 ] )
31
33
}
32
34
}
33
-
35
+
34
36
func testBlockHashing( ) throws {
35
37
let block = BTCBlock ( )
36
38
block. version = 1
@@ -40,19 +42,19 @@ public class BitcoinTests: XCTestCase {
40
42
block. difficultyTarget = 440711666
41
43
block. nonce = 2504433986
42
44
let hash = block. calculateHash ( ) ;
43
-
45
+
44
46
for i in 1 ... 8 {
45
47
// verify that the hash worked correctly with enough trailing 0s
46
48
XCTAssertEqual ( hash [ hash. count - i] , 0 )
47
49
}
48
-
50
+
49
51
// sanity check that the hash is not all 0s
50
52
XCTAssertNotEqual ( hash [ hash. count - 9 ] , 0 )
51
-
53
+
52
54
// verify that the leading byte is nonzero
53
55
XCTAssertNotEqual ( hash [ 0 ] , 0 )
54
56
}
55
-
57
+
56
58
func testBlockSerialization( ) throws {
57
59
let block = BTCBlock ( )
58
60
block. version = 2
@@ -61,28 +63,28 @@ public class BitcoinTests: XCTestCase {
61
63
block. timestamp = 42
62
64
block. difficultyTarget = 0
63
65
block. nonce = 0
64
-
66
+
65
67
let serialization = block. serialize ( )
66
68
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 ] )
67
69
}
68
-
70
+
69
71
func testTxSerialization( ) throws {
70
72
let tx = BTCTransaction ( )
71
73
tx. version = 1
72
74
let input = BTCTransaction . Input (
73
75
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
75
77
script: [ ]
76
78
)
77
79
tx. inputs = [ input]
78
80
tx. setWitnessForInput ( inputIndex: 0 , witness: BTCTransaction . Witness ( stackElements: [ [ 1 ] ] ) )
79
-
81
+
80
82
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 ] )
81
83
tx. outputs = [ output]
82
84
let txSerialization = tx. serialize ( )
83
85
XCTAssertEqual ( txSerialization. count, 99 )
84
86
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
+
86
88
let block = BTCBlock ( )
87
89
block. version = 2
88
90
block. previousBlockHash = BTCHashing . SHA_ZERO_HASH
@@ -94,5 +96,116 @@ public class BitcoinTests: XCTestCase {
94
96
let blockSerialization = block. serialize ( )
95
97
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 ] )
96
98
}
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
+
98
211
}
0 commit comments