mirror of
https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
synced 2025-06-07 16:06:26 +00:00
full edit
This commit is contained in:
parent
90cf9baa47
commit
cdd46a6946
@ -6,9 +6,9 @@ This section explains how to interact with `bitcoind` using the Swift programmin
|
||||
|
||||
## Setting Up Swift on Your Mac
|
||||
|
||||
To date, you've built all of your alternative programming language development environments on your Debian virtual node. However, that's not the best platform for Swift. Though there is a version of Swift available for Ubuntu platforms, it's not fully featured, and it works somewhat differently from the Mac-native Swift. A "variant" at the bottom of this section explains how to set it up, but be warned that you'll be in uncharted territory.
|
||||
To date, you've built all of your alternative-programming-language development environments on your Debian virtual node. However, that's not the best platform for Swift. Though there is a version of Swift available for Ubuntu platforms, it's not fully featured, and it works somewhat differently from the Mac-native Swift. A "variant" at the bottom of this section explains how to set it up, but be warned that you'll be in uncharted territory.
|
||||
|
||||
Instead. we suggest an optimal Swift environment on a Mac. There are three major steps in setting that up.
|
||||
Instead, we suggest creating an optimal Swift environment on a Mac. There are four major steps in doing so.
|
||||
|
||||
### 1. Install Xcode
|
||||
|
||||
@ -18,9 +18,9 @@ You're going to need `Xcode`, the integrated development enviroment for Swift an
|
||||
|
||||
Some people advise against an App Store install because it's somewhat all-or-nothing; it also won't work if you're still using Mojave because you want to avoid Catalina's incompatibilities. In that case you can download directly from the [Developer Area](https://developer.apple.com/download/more/) at Apple.
|
||||
|
||||
If you're using Mojave, you'll need the xip for Xcode 10.3.1. Otherwise, get the newest one.
|
||||
If you're using Mojave, you'll need the `xip` file for Xcode 10.3.1. Otherwise, get the newest one.
|
||||
|
||||
Once it's downloaded, you can click on the XIP to extract it, then move the Xcode app to your Applications folder.
|
||||
Once it's downloaded, you can click on the `xip` to extract it, then move the Xcode app to your Applications folder.
|
||||
|
||||
(EIther way, you should have Xcode installed in your Applications folder at the end of this step.)
|
||||
|
||||
@ -28,15 +28,15 @@ Once it's downloaded, you can click on the XIP to extract it, then move the Xcod
|
||||
|
||||
You're also going to need a Bitcoin node on your Mac, so that you can communicate with it. Technically, you could use a remote node, and access it with the RPC login and password over the net. However, we suggest you instead install a full node directly on your Mac, because that's the safest and cleanest setup, ensuring that none of your communications leave your machine.
|
||||
|
||||
To easily install a full node on your Mac, use Blockchain Commons' [GordianServer for MacOS](https://github.com/BlockchainCommons/GordianServer-macOS). See the [installation instructions](https://github.com/BlockchainCommons/GordianServer-macOS#installation-instructions) in the README, but generally all you have to do is download the current DMG, open it, and install that app in your Applications too.
|
||||
To easily install a full node on your Mac, use Blockchain Commons' [GordianServer for MacOS](https://github.com/BlockchainCommons/GordianServer-macOS). See the [installation instructions](https://github.com/BlockchainCommons/GordianServer-macOS#installation-instructions) in the README, but generally all you have to do is download the current `dmg` file, open it, and install that app in your Applications too.
|
||||
|
||||
Afterward, run the GordianServer App, and tell it to `Start` Testnet.
|
||||
|
||||
> :link: **TESTNET vs. MAINNET:** Or `Start` Mainnet.
|
||||
|
||||
#### 2.1 Make Your Gordian bitcoin-cli Accessible
|
||||
#### 3. Make Your Gordian bitcoin-cli Accessible
|
||||
|
||||
Note that when you want to access the `bitcoin-cli` on your local Mac, you can find it at `~/.standup/BitcoinCore/bitcoin-VERSION/bin/bitcoin-cli`, for example `~/.standup/BitcoinCore/bitcoin-0.20.1/bin/bitcoin-cli`.
|
||||
When you want to access the `bitcoin-cli` created by GordianServer on your local Mac, you can find it at `~/.standup/BitcoinCore/bitcoin-VERSION/bin/bitcoin-cli`, for example `~/.standup/BitcoinCore/bitcoin-0.20.1/bin/bitcoin-cli`.
|
||||
|
||||
You may wish to create an alias for that:
|
||||
```
|
||||
@ -45,11 +45,9 @@ alias bitcoin-cli="~/.standup/BitcoinCore/bitcoin-0.20.1/bin/bitcoin-cli -testne
|
||||
|
||||
> :link: **TESTNET vs. MAINNET:** Obviously, the `-testnet` parameter is only required if you're running on testnet.
|
||||
|
||||
### 3. Find Your GordianServer Info
|
||||
### 4. Find Your GordianServer Info
|
||||
|
||||
As usual, you'll need the RPC login and password. That's in `~/Library/Application Support/Bitcoin/bitcoin.conf` by default under Gordian.
|
||||
|
||||
Pull out the `rpcuser` and `rpcpassword` information; you'll need it to build your RPC connection:
|
||||
Finally, you'll need your `rpcuser` and `rpcpassword` information. That's in `~/Library/Application Support/Bitcoin/bitcoin.conf` by default under Gordian.
|
||||
```
|
||||
$ grep rpc ~/Library/Application\ Support/Bitcoin/bitcoin.conf
|
||||
rpcuser=oIjA53JC2u
|
||||
@ -58,32 +56,39 @@ rpcpassword=ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU
|
||||
```
|
||||
## Building Your Connection by Hand
|
||||
|
||||
At the time of this writing, there isn't a simple and easy Bitcoin RPC Library for Swift, which you can drop in and immediately start using. Thus, we're going to do something we've never done before: build an RPC connection by hand.
|
||||
At the time of this writing, there isn't an up-to-date, simple-to-use Bitcoin RPC Library that's specific for Swift, which you can drop in and immediately start using. Thus, you're're going to do something you're never done before: build an RPC connection by hand.
|
||||
|
||||
It just requires writing a function:
|
||||
It just requires writing a function that passes RPC commands on to `bitcoind` in the correct format:
|
||||
```
|
||||
func makeCommand(method: String, param: Any, completionHandler: @escaping (Any?) -> Void) -> Void {
|
||||
```
|
||||
|
||||
### 1. Create a URL
|
||||
### Writing the RPC Transmitter
|
||||
|
||||
Within the funciton, you need to create a URL from your IP, port, `rpcuser`, `rpcpassword`, and wallet:
|
||||
RPC connections to `bitcoind` use the HTML protocol, which means that you need to do three things: create a URL; make a URLRequest; and initiate a URLSession.
|
||||
|
||||
#### 1. Create a URL
|
||||
|
||||
Within the function, you need to create a URL from your IP, port, `rpcuser`, `rpcpassword`, and wallet:
|
||||
```
|
||||
let testnetRpcPort = "18332"
|
||||
let nodeIp = "127.0.0.1:\(testnetRpcPort)"
|
||||
let rpcusername = "oIjA53JC2u"
|
||||
let rpcpassword = "ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU"
|
||||
let walletName = ""
|
||||
```
|
||||
The actual RPC connection to Bitcoin Core is built using a URL of the format "http://rpcusername:rpcpassword@nodeIp/walletName":
|
||||
```
|
||||
let walletUrl = "http://\(rpcusername):\(rpcpassword)@\(nodeIp)/\(walletName)"
|
||||
|
||||
let url = URL(string: walletUrl)
|
||||
```
|
||||
An RPC connection to Bitcoin Core is built using a URL of the format "http://\(rpcusername):\(rpcpassword)@\(nodeIp)/\(walletName)". This means that your sample variables result in the following URL:
|
||||
This means that your sample variables result in the following URL:
|
||||
```
|
||||
http://oIjA53JC2u:ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU@127.0.0.1:18332/
|
||||
```
|
||||
|
||||
### 2. Create a URLRequest
|
||||
#### 2. Create a URLRequest
|
||||
|
||||
With that URL in you hand, you can now create a URLRequest, with the `POST` method and the `text/plain` content type. The HTTP body is then the familiar JSON object that you've been sending whenever you connect directly to Bitcoin Core's RPC ports, as first demonstrated when using Curl in [§4.4](04_4__Interlude_Using_Curl.md).
|
||||
```
|
||||
@ -93,7 +98,7 @@ With that URL in you hand, you can now create a URLRequest, with the `POST` meth
|
||||
request.httpBody = "{\"jsonrpc\":\"1.0\",\"id\":\"curltest\",\"method\":\"\(method)\",\"params\":[\(param)]}".data(using: .utf8)
|
||||
```
|
||||
|
||||
### 3. Create a URLSession
|
||||
#### 3. Create a URLSession
|
||||
|
||||
Finally, you're ready to build a URLSession around your URLRequest.
|
||||
```
|
||||
@ -110,7 +115,7 @@ The completion handler for `dataTask` needs to check for errors:
|
||||
|
||||
} else {
|
||||
```
|
||||
And then parse the data. Here, you're pulling the JSON results into an `NSDictionary`:
|
||||
And then parse the data that you're receiving. Here, you're pulling the JSON results into an `NSDictionary`:
|
||||
```
|
||||
if let urlContent = data {
|
||||
|
||||
@ -118,7 +123,7 @@ And then parse the data. Here, you're pulling the JSON results into an `NSDictio
|
||||
|
||||
let json = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary
|
||||
```
|
||||
After that, there's more error handling and more error handling and then you can eventually return the JSON `result` using the `completionHandler` that you included for the new `makeCommand` function:
|
||||
After that, there's more error handling and more error handling and then you can eventually return the dictionary `result` using the `completionHandler` that you included for the new `makeCommand` function:
|
||||
```
|
||||
if let errorCheck = json["error"] as? NSDictionary {
|
||||
|
||||
@ -142,14 +147,19 @@ After that, there's more error handling and more error handling and then you can
|
||||
|
||||
}
|
||||
```
|
||||
Of course you eventually have to tell the `task` to start:
|
||||
```
|
||||
task.resume()
|
||||
```
|
||||
And that's "all" there is to doing that RPC interaction by hand using a program language such as Swift.
|
||||
|
||||
> :pray: **THANKS:** Thanks to @Fonta1n3 who provided the [main code](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/issues/137) for our RPC Transmitter.
|
||||
|
||||
### Making An RPC Call
|
||||
|
||||
Having written the `makeCommand` RPC function, you can send an RPC call by running it. Here's `getblockchaininfo`:
|
||||
```
|
||||
let method = "getblockchaininfo"
|
||||
// Your rpc commands parameters (none needed for getblockchaininfo)
|
||||
let param = ""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
@ -160,10 +170,9 @@ makeCommand(method: method,param: param) { result in
|
||||
```
|
||||
### Making an RPC Call with Arguments
|
||||
|
||||
You could similarly grab the current block count from that info and use it to get the hash of the current block, by using the `param` parameter:
|
||||
You could similarly grab the current block count from that info and use that to get the hash of the current block, by using the `param` parameter:
|
||||
```
|
||||
let method = "getblockchaininfo"
|
||||
// Your rpc commands parameters (none needed for getblockchaininfo)
|
||||
let param = ""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
@ -229,7 +238,7 @@ Blockhash for 1836745 is 00000000000000069725608ebc5b59e520572a8088cbc57ffa5ba87
|
||||
|
||||
## Looking Up Funds
|
||||
|
||||
With your new `makeCommand` for RPC functions, you can equally run a command like `getwalletinfo` or `getbalance`:
|
||||
With your new `makeCommand` for RPC functions, you can similarly run a command like `getwalletinfo` or `getbalance`:
|
||||
```
|
||||
var method = "getwalletinfo"
|
||||
var param = ""
|
||||
@ -296,6 +305,7 @@ $ bitcoin-cli getaddressesbylabel "learning-bitcoin"
|
||||
}
|
||||
}
|
||||
```
|
||||
Success!
|
||||
|
||||
> :information_source: **NOTE:** As we often say in these coding examples, a real program would be much more sophisticated. In particular, you'd want to be able to send an actual JSON object as a parameter, and then have your `makeCommand` program parse it and input it to the URLSession appropriately. What we have here maximizes readability and simplicity without focusing on ease of use.
|
||||
|
||||
@ -320,7 +330,7 @@ The `listunspent` RPC lets you find your UTXO:
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
let unspent = result! as! NSArray
|
||||
let unspent = result as! NSArray
|
||||
let utxo = unspent[0] as! NSDictionary
|
||||
|
||||
let txid = utxo["txid"] as! NSString
|
||||
@ -330,11 +340,11 @@ The `listunspent` RPC lets you find your UTXO:
|
||||
```
|
||||
As in other examples, you're going to arbitrarily grab the 0th UTXO, and pull the `txid`, `vout`, and `amount` from it.
|
||||
|
||||
> :information_source **NOTE:** As in other example, a real-life program would be much more sophisticated.
|
||||
> :information_source **NOTE:** Once again, a real-life program would be much more sophisticated.
|
||||
|
||||
### 2. Create a Raw Transaction
|
||||
|
||||
Creating a raw transaction is the trickiest thing because you need to get all of your JSON objects, arrays, and quotes right. Here's how to do so in Swift:
|
||||
Creating a raw transaction is the trickiest thing because you need to get all of your JSON objects, arrays, and quotes right. Here's how to do so in Swift, using our very basic `param` formatting:
|
||||
```
|
||||
method = "createrawtransaction"
|
||||
param="[ { \"txid\": \"\(txid)\", \"vout\": \(vout) } ], { \"\(address)\": \(new_amount)}"
|
||||
@ -391,7 +401,6 @@ Swift is a robust modern programming language that unfortunately doesn't yet hav
|
||||
|
||||
Learn about Lightning in [Chapter 19: Understanding Your Lightning Setup](19_0_Understanding_Your_Lightning_Setup.md).
|
||||
|
||||
|
||||
## Variant: Deploying Swift on Ubuntu
|
||||
|
||||
If you prefer to deploy Swift on Ubuntu, you can do so, though the functionality isn't the same. Some of the code in this chapter will likely generate errors that you'll need to resolve, and you'll also need to do more work to link in C libraries.
|
||||
|
Loading…
x
Reference in New Issue
Block a user