Skip to content

Commit 574b245

Browse files
committed
New post and docs update
1 parent 7500a68 commit 574b245

File tree

2,506 files changed

+3577
-2327
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

2,506 files changed

+3577
-2327
lines changed

src/content/post/posts2025.swift

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,101 @@
1+
let post06 = Post("/post/2025-01-16-testing-transport-layer", "Testing the Transport Layer", "2025-01-16T12:00:00Z", .testing) { """
2+
3+
Creating meaningful unit tests can be difficult – even more when the system under test is a transport layer protocol like the [Bitcoin wire protocol](https://en.bitcoin.it/wiki/Protocol_documentation).
4+
5+
A modern framework like [Swift Testing](https://developer.apple.com/documentation/testing/) offers facilities to deal with asynchronous code. We are taking full advantage of that capability to verify node interactions like the [handshake sequence](https://developer.bitcoin.org/reference/p2p_networking.html#version), post handshake exchange, ping/pong and transaction and block relay communication.
6+
7+
8+
As an example let's look at how Alice would relay a transaction to Bob.
9+
10+
First let's define our services get a reference to some channels:
11+
12+
```swift
13+
import Bitcoin
14+
15+
let alice = NodeService(blockchain: BlockchainService())
16+
let bob = NodeService(blockchain: BlockchainService())
17+
18+
// Alice's asynchronous messages to Bob.
19+
var aliceToBob = await alice.getChannel(for: peerB).makeAsyncIterator()
20+
21+
// Alice's transaction inventory (subscription to internal blockchain events).
22+
var aliceTxs = try #require(await alice.txs?.makeAsyncIterator())
23+
24+
```
25+
26+
After bootstrapping our nodes with a synchronized state we can kickstart an interaction by submitting a new transaction to Alice's mempool:
27+
28+
```swift
29+
let tx = …
30+
31+
// Add the transaction directly to Alice's blockchain as one would with RPC.
32+
Task {
33+
try await alice.blockchain.addTx(tx)
34+
}
35+
36+
// Alice's transactions channel will notify us of the newly accepted transaction.
37+
let aliceTx = try #require(await aliceTxs.next())
38+
await Task.yield()
39+
40+
// We can now forward the transaction to the node so that it can relay it to its peers if needed.
41+
Task {
42+
await alice.handleTx(aliceTx)
43+
}
44+
```
45+
46+
We can see how a combination of subtasks and `Task.yield()` can help us work through the asynchronicity.
47+
48+
Once the transaction relay process is triggered we proceed to checking the actual message exchange:
49+
50+
```swift
51+
// Alice --(inv)->> …
52+
let messageAB0_inv = try #require(await aliceToBob.next())
53+
await Task.yield()
54+
#expect(messageAB0_inv.command == .inv)
55+
56+
let inv = try #require(InventoryMessage(messageAB0_inv.payload))
57+
#expect(inv.items == [.init(type: .witnessTx, hash: tx.id)])
58+
59+
// … --(inv)->> Bob
60+
try await bob.processMessage(messageAB0_inv, from: peerA)
61+
62+
// Bob --(getdata)->> …
63+
let messageBA0_getdata = try #require(await bob.popMessage(peerA))
64+
#expect(messageBA0_getdata.command == .getdata)
65+
66+
let getData = try #require(GetDataMessage(messageBA0_getdata.payload))
67+
#expect(getData.items == [.init(type: .witnessTx, hash: tx.id)])
68+
69+
// … --(getdata)->> Alice
70+
try await alice.processMessage(messageBA0_getdata, from: peerB)
71+
72+
// Alice --(tx)->> …
73+
let messageAB1_tx = try #require(await alice.popMessage(peerB))
74+
#expect(messageAB1_tx.command == .tx)
75+
76+
let txMessage = try #require(BitcoinTx(messageAB1_tx.payload))
77+
#expect(txMessage == tx)
78+
79+
// … --(tx)->> Bob
80+
try await bob.processMessage(messageAB1_tx, from: peerA)
81+
```
82+
83+
As indicated by the comments in the snippet above the sequence of messages being verified looks like:
84+
85+
- Alice sends an `inv` message to Bob.
86+
- Bob responds to Alice with a `getdata` message.
87+
- Alice responds to Bob with a `tx` message.
88+
89+
In addition to inspecting each message's content along the way we can also ensure the state of the node and blockchain services is correct. For instance here's how we would compare the mempool's content to our expectation of it containing our relay transaction:
90+
91+
```swift
92+
let bobsMempool = await bob.blockchain.mempool
93+
#expect(await alice.blockchain.mempool == bobsMempool)
94+
```
95+
96+
That's it. Check out the rest of Swift Bitcoin [Transport tests](https://github.com/swift-bitcoin/swift-bitcoin/tree/develop/test/bitcoin-transport) and feel free to reach out if you would like to contribute!
97+
""" }
98+
199
let post05 = Post("/post/2025-01-03-update", "New Year's Update", "2025-01-03T12:00:00Z", .announcements) { """
2100
3101
Happy 2025 to all Swift and Bitcoin devs! And Happy 16th Birthday to the Bitcoin network! I wanted to use the occasion for posting an update of where the project stands today and where it could go from here.

src/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import SwiftySites
22

33
let posts = [
4-
post01, post02, post03, post04, post05
4+
post01, post02, post03, post04, post05, post06
55
]
66

77
let site = Site(

static/docc/base/data/documentation/bitcoinbase.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"topicSections":[{"title":"Extended Structures","identifiers":["doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig","doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/PubKey","doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/SecretKey"],"anchor":"Extended-Structures","generated":true}],"schemaVersion":{"major":0,"minor":3,"patch":0},"sections":[],"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/bitcoinbase\/bitcoincrypto"]}],"hierarchy":{"paths":[["doc:\/\/BitcoinBase\/documentation\/BitcoinBase"]]},"metadata":{"title":"BitcoinCrypto","modules":[{"name":"Bitcoin Base"}],"role":"collection","roleHeading":"Extended Module","externalID":"s:m:s:e:s:13BitcoinCrypto6AnySigV0A4BaseE30schnorrSignatureExtendedLengthSivpZ","symbolKind":"extension"},"identifier":{"url":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto","interfaceLanguage":"swift"},"kind":"symbol","references":{"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/PubKey":{"abstract":[{"type":"text","text":"Extensions for BIP341 taproot."}],"identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/PubKey","fragments":[{"kind":"keyword","text":"extension"},{"text":" ","kind":"text"},{"text":"PubKey","kind":"identifier","preciseIdentifier":"s:13BitcoinCrypto6PubKeyV"}],"title":"PubKey","kind":"symbol","url":"\/documentation\/bitcoinbase\/bitcoincrypto\/pubkey","navigatorTitle":[{"text":"PubKey","kind":"identifier"}],"role":"symbol","type":"topic"},"doc://BitcoinBase/documentation/BitcoinBase":{"abstract":[{"type":"text","text":"Basic elements of the Bitcoin protocol, namely transactions and scripts."}],"title":"Bitcoin Base","url":"\/documentation\/bitcoinbase","kind":"symbol","type":"topic","role":"collection","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/AnySig":{"type":"topic","title":"AnySig","kind":"symbol","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig","role":"symbol","abstract":[],"navigatorTitle":[{"kind":"identifier","text":"AnySig"}],"url":"\/documentation\/bitcoinbase\/bitcoincrypto\/anysig","fragments":[{"kind":"keyword","text":"extension"},{"kind":"text","text":" "},{"kind":"identifier","preciseIdentifier":"s:13BitcoinCrypto6AnySigV","text":"AnySig"}]},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto":{"role":"collection","kind":"symbol","title":"BitcoinCrypto","url":"\/documentation\/bitcoinbase\/bitcoincrypto","abstract":[],"type":"topic","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/SecretKey":{"kind":"symbol","type":"topic","role":"symbol","title":"SecretKey","fragments":[{"kind":"keyword","text":"extension"},{"kind":"text","text":" "},{"preciseIdentifier":"s:13BitcoinCrypto9SecretKeyV","text":"SecretKey","kind":"identifier"}],"navigatorTitle":[{"kind":"identifier","text":"SecretKey"}],"identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/SecretKey","abstract":[{"type":"text","text":"Extensions for BIP341 taproot."}],"url":"\/documentation\/bitcoinbase\/bitcoincrypto\/secretkey"}}}
1+
{"variants":[{"paths":["\/documentation\/bitcoinbase\/bitcoincrypto"],"traits":[{"interfaceLanguage":"swift"}]}],"topicSections":[{"anchor":"Extended-Structures","title":"Extended Structures","generated":true,"identifiers":["doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig","doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/PubKey","doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/SecretKey"]}],"hierarchy":{"paths":[["doc:\/\/BitcoinBase\/documentation\/BitcoinBase"]]},"sections":[],"identifier":{"url":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto","interfaceLanguage":"swift"},"metadata":{"title":"BitcoinCrypto","roleHeading":"Extended Module","externalID":"s:m:s:e:s:13BitcoinCrypto6AnySigV0A4BaseE30schnorrSignatureExtendedLengthSivpZ","modules":[{"name":"Bitcoin Base"}],"symbolKind":"extension","role":"collection"},"schemaVersion":{"patch":0,"minor":3,"major":0},"kind":"symbol","references":{"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/SecretKey":{"title":"SecretKey","navigatorTitle":[{"kind":"identifier","text":"SecretKey"}],"type":"topic","kind":"symbol","abstract":[{"text":"Extensions for BIP341 taproot.","type":"text"}],"role":"symbol","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/SecretKey","fragments":[{"text":"extension","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"SecretKey","preciseIdentifier":"s:13BitcoinCrypto9SecretKeyV"}],"url":"\/documentation\/bitcoinbase\/bitcoincrypto\/secretkey"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/AnySig":{"type":"topic","fragments":[{"kind":"keyword","text":"extension"},{"text":" ","kind":"text"},{"text":"AnySig","preciseIdentifier":"s:13BitcoinCrypto6AnySigV","kind":"identifier"}],"url":"\/documentation\/bitcoinbase\/bitcoincrypto\/anysig","abstract":[],"navigatorTitle":[{"text":"AnySig","kind":"identifier"}],"role":"symbol","kind":"symbol","title":"AnySig","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto":{"title":"BitcoinCrypto","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto","kind":"symbol","role":"collection","type":"topic","abstract":[],"url":"\/documentation\/bitcoinbase\/bitcoincrypto"},"doc://BitcoinBase/documentation/BitcoinBase":{"url":"\/documentation\/bitcoinbase","type":"topic","title":"Bitcoin Base","role":"collection","kind":"symbol","abstract":[{"text":"Basic elements of the Bitcoin protocol, namely transactions and scripts.","type":"text"}],"identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/PubKey":{"abstract":[{"text":"Extensions for BIP341 taproot.","type":"text"}],"kind":"symbol","type":"topic","url":"\/documentation\/bitcoinbase\/bitcoincrypto\/pubkey","role":"symbol","fragments":[{"kind":"keyword","text":"extension"},{"text":" ","kind":"text"},{"text":"PubKey","kind":"identifier","preciseIdentifier":"s:13BitcoinCrypto6PubKeyV"}],"title":"PubKey","navigatorTitle":[{"text":"PubKey","kind":"identifier"}],"identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/PubKey"}}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"sections":[],"metadata":{"extendedModule":"BitcoinCrypto","title":"AnySig","modules":[{"name":"Bitcoin Base","relatedModules":["BitcoinCrypto"]}],"externalID":"s:e:s:13BitcoinCrypto6AnySigV0A4BaseE30schnorrSignatureExtendedLengthSivpZ","role":"symbol","symbolKind":"extension","navigatorTitle":[{"text":"AnySig","kind":"identifier"}],"roleHeading":"Extended Structure","fragments":[{"text":"extension","kind":"keyword"},{"text":" ","kind":"text"},{"text":"AnySig","kind":"identifier","preciseIdentifier":"s:13BitcoinCrypto6AnySigV"}]},"kind":"symbol","topicSections":[{"identifiers":["doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig\/schnorrSignatureExtendedLength"],"title":"Type Properties","generated":true,"anchor":"Type-Properties"}],"hierarchy":{"paths":[["doc:\/\/BitcoinBase\/documentation\/BitcoinBase","doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto"]]},"primaryContentSections":[{"declarations":[{"platforms":["macOS"],"languages":["swift"],"tokens":[{"kind":"keyword","text":"extension"},{"kind":"text","text":" "},{"preciseIdentifier":"s:13BitcoinCrypto6AnySigV","kind":"typeIdentifier","text":"AnySig"}]}],"kind":"declarations"}],"identifier":{"url":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig","interfaceLanguage":"swift"},"variants":[{"traits":[{"interfaceLanguage":"swift"}],"paths":["\/documentation\/bitcoinbase\/bitcoincrypto\/anysig"]}],"schemaVersion":{"minor":3,"major":0,"patch":0},"references":{"doc://BitcoinBase/documentation/BitcoinBase":{"abstract":[{"type":"text","text":"Basic elements of the Bitcoin protocol, namely transactions and scripts."}],"title":"Bitcoin Base","url":"\/documentation\/bitcoinbase","kind":"symbol","type":"topic","role":"collection","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/AnySig/schnorrSignatureExtendedLength":{"role":"symbol","title":"schnorrSignatureExtendedLength","kind":"symbol","abstract":[{"text":"Standard Schnorr signature extended with the sighash type byte.","type":"text"}],"fragments":[{"text":"static","kind":"keyword"},{"kind":"text","text":" "},{"text":"let","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"identifier","text":"schnorrSignatureExtendedLength"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"Int","preciseIdentifier":"s:Si"}],"type":"topic","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig\/schnorrSignatureExtendedLength","url":"\/documentation\/bitcoinbase\/bitcoincrypto\/anysig\/schnorrsignatureextendedlength"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto":{"role":"collection","kind":"symbol","title":"BitcoinCrypto","url":"\/documentation\/bitcoinbase\/bitcoincrypto","abstract":[],"type":"topic","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/AnySig":{"type":"topic","title":"AnySig","kind":"symbol","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig","role":"symbol","abstract":[],"navigatorTitle":[{"kind":"identifier","text":"AnySig"}],"url":"\/documentation\/bitcoinbase\/bitcoincrypto\/anysig","fragments":[{"kind":"keyword","text":"extension"},{"kind":"text","text":" "},{"kind":"identifier","preciseIdentifier":"s:13BitcoinCrypto6AnySigV","text":"AnySig"}]}}}
1+
{"primaryContentSections":[{"kind":"declarations","declarations":[{"languages":["swift"],"tokens":[{"kind":"keyword","text":"extension"},{"text":" ","kind":"text"},{"preciseIdentifier":"s:13BitcoinCrypto6AnySigV","text":"AnySig","kind":"typeIdentifier"}],"platforms":["macOS"]}]}],"variants":[{"paths":["\/documentation\/bitcoinbase\/bitcoincrypto\/anysig"],"traits":[{"interfaceLanguage":"swift"}]}],"hierarchy":{"paths":[["doc:\/\/BitcoinBase\/documentation\/BitcoinBase","doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto"]]},"schemaVersion":{"patch":0,"minor":3,"major":0},"kind":"symbol","metadata":{"navigatorTitle":[{"text":"AnySig","kind":"identifier"}],"extendedModule":"BitcoinCrypto","externalID":"s:e:s:13BitcoinCrypto6AnySigV0A4BaseE30schnorrSignatureExtendedLengthSivpZ","title":"AnySig","modules":[{"name":"Bitcoin Base","relatedModules":["BitcoinCrypto"]}],"roleHeading":"Extended Structure","role":"symbol","fragments":[{"kind":"keyword","text":"extension"},{"text":" ","kind":"text"},{"kind":"identifier","text":"AnySig","preciseIdentifier":"s:13BitcoinCrypto6AnySigV"}],"symbolKind":"extension"},"topicSections":[{"anchor":"Type-Properties","generated":true,"title":"Type Properties","identifiers":["doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig\/schnorrSignatureExtendedLength"]}],"sections":[],"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig"},"references":{"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/AnySig/schnorrSignatureExtendedLength":{"title":"schnorrSignatureExtendedLength","abstract":[{"text":"Standard Schnorr signature extended with the sighash type byte.","type":"text"}],"kind":"symbol","url":"\/documentation\/bitcoinbase\/bitcoincrypto\/anysig\/schnorrsignatureextendedlength","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig\/schnorrSignatureExtendedLength","role":"symbol","fragments":[{"text":"static","kind":"keyword"},{"text":" ","kind":"text"},{"kind":"keyword","text":"let"},{"text":" ","kind":"text"},{"text":"schnorrSignatureExtendedLength","kind":"identifier"},{"text":": ","kind":"text"},{"kind":"typeIdentifier","text":"Int","preciseIdentifier":"s:Si"}],"type":"topic"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto/AnySig":{"type":"topic","fragments":[{"kind":"keyword","text":"extension"},{"text":" ","kind":"text"},{"text":"AnySig","preciseIdentifier":"s:13BitcoinCrypto6AnySigV","kind":"identifier"}],"url":"\/documentation\/bitcoinbase\/bitcoincrypto\/anysig","abstract":[],"navigatorTitle":[{"text":"AnySig","kind":"identifier"}],"role":"symbol","kind":"symbol","title":"AnySig","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto\/AnySig"},"doc://BitcoinBase/documentation/BitcoinBase/BitcoinCrypto":{"title":"BitcoinCrypto","identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase\/BitcoinCrypto","kind":"symbol","role":"collection","type":"topic","abstract":[],"url":"\/documentation\/bitcoinbase\/bitcoincrypto"},"doc://BitcoinBase/documentation/BitcoinBase":{"url":"\/documentation\/bitcoinbase","type":"topic","title":"Bitcoin Base","role":"collection","kind":"symbol","abstract":[{"text":"Basic elements of the Bitcoin protocol, namely transactions and scripts.","type":"text"}],"identifier":"doc:\/\/BitcoinBase\/documentation\/BitcoinBase"}}}

0 commit comments

Comments
 (0)