@ -1,112 +0,0 @@
|
||||
<section data-type="chapter">
|
||||
<h1>Quick Start Guide</h1>
|
||||
|
||||
<p>Atlas is currently in its Beta release; this means that, while we feel the system is ready to be used, it's still actively under development and needs some rigorous testing. That's where you come in! Here are the most important things you need to know to get started.</p>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>Atlas Is Built on Git</h1>
|
||||
|
||||
<p>Atlas is built on <a data-original-title="" href="http://git-scm.com" title="">Git</a>, the powerful version control system that tracks every change in your content, who made it, and when it happened. What this means is that your content is secure and can be rolled back to any previous version if necessary. Git also provides the functionality for seamless collaboration tools.</p>
|
||||
</section>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>Your Projects</h1>
|
||||
|
||||
<p>When you sign into Atlas, <strong>the first thing you'll see is a list of all your existing projects</strong>. If you want to edit or build from an existing project, simply find and click the project in the list. To <strong>create a new project</strong>, click the New Project button to the right of the projects list.</p>
|
||||
|
||||
<figure><img alt="Atlas new project button." class="icontentsimagesnewprojpng" src="images/newproj.png" />
|
||||
<figcaption>Click the New Project button in your project list to start fresh.</figcaption>
|
||||
</figure>
|
||||
|
||||
<p>If you want to start from scratch, you can define the title and description for your project and choose a project template to pre-populate your new repository with some skeleton files based on the kind of project you're making.</p>
|
||||
|
||||
<p>You can also create a new Atlas project by importing an existing project from GitHub.</p>
|
||||
|
||||
<p>Once you select a project or create a new one, <strong>you'll be taken to the project dashboard</strong>, where you'll see a list of all files in the project, and have access to the <a data-type="xref" href="#building_in_atlas" title="">ebook-building tools</a>.</p>
|
||||
</section>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>The Project Dashboard</h1>
|
||||
|
||||
<p><strong>The project dashboard is your landing page for each project.</strong> It lists all the files and folders in your project, specifies your active branch, and gives you quick access to the build tools (more on building <a data-type="xref" href="#building_in_atlas">below</a>). You can also navigate from here to the Project Settings and Activity pages.</p>
|
||||
|
||||
<p>From the project dashboard, <strong>click a file in the Files pane at left to open it in the editor.</strong></p>
|
||||
</section>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>Writing and Editing</h1>
|
||||
|
||||
<p><strong>The Atlas editor has two writing modes</strong>: the Visual Editor and the Code Editor. The Visual Editor is an online authoring environment similar to a word processor, with a formatting toolbar for tagging and styling your content. Documents created in the Visual Editor are stored as <a href="http://oreillymedia.github.io/HTMLBook/">HTMLBook</a>, a specification of <a href="http://en.wikipedia.org/wiki/HTML5">HTML5</a>. The Code Editor allows you to view and edit the underlying HTML5 markup for your document. You can toggle back and forth between the Visual and Code Editors, and changes you make in either mode will immediately be reflected in the other.</p>
|
||||
|
||||
<p>While <strong>HTML5 is the default markup language for Atlas content</strong>, Atlas also supports documents written in<strong> <a href="https://help.github.com/articles/github-flavored-markdown">Markdown</a>, <a href="http://www.methods.co.nz/asciidoc/">AsciiDoc</a>, and <a href="http://www.docbook.org/">DocBook XML</a></strong>. All three of these formats can be edited using the Code Editor.</p>
|
||||
|
||||
<p>In both writing modes, you can <strong>navigate among your files using the Files menu</strong> to the left of the screen, <strong>create and delete files and folders</strong>, <strong>upload images</strong>, <strong>save your project</strong> (specify a custom commit message by clicking on the dropdown arrow next to the Save button), and even <strong>initiate builds</strong>.</p>
|
||||
</section>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>Creating a New File</h1>
|
||||
|
||||
<p>To create a new file, click the New File button at bottom of the dashboard. Give your file a name, and press Enter. You can also do this in the Files pane in the editor.</p>
|
||||
|
||||
<p>You can also organize your files into folders. To add a folder, click the New Folder button (next to the New File button). You can then click the folder name in the Files menu to open the folder and create new files within it.</p>
|
||||
|
||||
<div data-type="warning">
|
||||
<h1>Warning</h1>
|
||||
|
||||
<p>You can't currently organize your files within Atlas. If you want to move existing files into a folder, you need to do that outside of Atlas using Git.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-type="sect1" id="building_in_atlas">
|
||||
<h1>Building</h1>
|
||||
|
||||
<p>When you're finished writing, it's time to build your project so you can share it with the world. <strong>Atlas lets you export your project in four different formats</strong>: PDF, EPUB, MOBI, and HTML website.</p>
|
||||
|
||||
<p>Before you build for the first time, you'll need to choose which files from your project to include and the settings you want to apply to each format; <strong>click Configure</strong> on the project dashboard.</p>
|
||||
|
||||
<p>In the Files section, simply <strong>choose files from the left-hand pane to add to the build</strong>, and drag the files into the correct order on the right. You can remove files from the build list by clicking on the minus button.</p>
|
||||
|
||||
<p>Each format has a few different configuration options. Four are common to all formats:</p>
|
||||
|
||||
<ul>
|
||||
<li>Create a <strong>table of contents</strong> in your output, based on your section headings.</li>
|
||||
<li>Collect all index tags you've added and create an <strong>alphabetical index</strong> in your final format.</li>
|
||||
<li>Apply <strong>syntax highlighting</strong> to language-specific code sections in build output.</li>
|
||||
<li>Display or suppress <strong>Atlas comments</strong> in build output (HTMLBook only).</li>
|
||||
</ul>
|
||||
|
||||
<p>Finally, choose a theme for your project. You can pick from one of the available default themes, or specify your own custom theme.</p>
|
||||
|
||||
<p>Click Save, and now you can build from the dashboard.</p>
|
||||
|
||||
<figure><img alt="Atlas build button." class="icontentsimagesquickbuildspng" src="images/quickbuilds.png" />
|
||||
<figcaption>The Builds menu on the project dashboard allows you to quickly trigger a build using your previously chosen settings.</figcaption>
|
||||
</figure>
|
||||
|
||||
<p>If the build is successful, you'll get a link to download the file. If it fails, you'll get information about what went wrong (the usual culprit is markup errors).</p>
|
||||
</section>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>Themes and Design</h1>
|
||||
|
||||
<p>All of the Atlas output formats (PDF, EPUB, MOBI, and HTML) are powered by <a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets">CSS</a>, the standard styling language for the Web. You can write an entirely new theme using CSS that can be used for multiple projects, by multiple people, or you can just add CSS customizations for your specific project.</p>
|
||||
|
||||
<p><strong>To apply a theme to your project</strong>, choose one of the default themes on the Configure page, or add a link to your own custom theme.</p>
|
||||
|
||||
<figure><img alt="Atlas theme selector." class="icontentsimagesthemepng" src="images/theme.png" />
|
||||
<figcaption>Add a design to your project on the Configure page.</figcaption>
|
||||
</figure>
|
||||
</section>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>Building Locally with the API</h1>
|
||||
|
||||
<p>Atlas gives you the option to <strong>build locally on the command line</strong>, using our <a href="http://docs.atlas.oreilly.com/ch11.html#atlas-api">API</a>. (Note that you'll still need an internet connection for this to work.) This is great if you prefer to work locally using your own text editor but still want to see the final output.</p>
|
||||
</section>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>Finding Help</h1>
|
||||
|
||||
<p>For more details on any of the above topics, or for more advanced information, <strong><a href="https://atlas.oreilly.com/help">visit the Atlas help and support page</a></strong>.</p>
|
||||
</section>
|
||||
</section>
|
@ -0,0 +1,137 @@
|
||||
[[appdxbitcoinimpproposals]]
|
||||
[appendix]
|
||||
== Bitcoin Improvement Proposals
|
||||
|
||||
((("Bitcoin improvement proposals", id="ix_appdx-bips-asciidoc0", range="startofrange")))Bitcoin improvement proposals are design documents providing information to the bitcoin community, or describing a new feature for bitcoin or its processes or environment.
|
||||
|
||||
As per BIP0001 _BIP Purpose and Guidelines_, there are three kinds of BIP:
|
||||
|
||||
_Standard_ BIP:: Describes any change that affects most or all bitcoin implementations, such as a change to the network protocol, a change in block or transaction validity rules, or any change or addition that affects the interoperability of applications using bitcoin.
|
||||
_Informational_ BIP:: Describes a bitcoin design issue, or provides general guidelines or information to the bitcoin community, but does not propose a new feature. Informational BIPs do not necessarily represent a bitcoin community consensus or recommendation, so users and implementors may ignore informational BIPs or follow their advice.
|
||||
_Process_ BIP:: Describes a bitcoin process, or proposes a change to (or an event in) a process. Process BIPs are like standard BIPs but apply to areas other than the bitcoin protocol itself. They might propose an implementation, but not to bitcoin's codebase; they often require community consensus; and unlike informational BIPs, they are more than recommendations, and users are typically not free to ignore them. Examples include procedures, guidelines, changes to the decision-making process, and changes to the tools or environment used in Bitcoin development. Any meta-BIP is also considered a process BIP.
|
||||
|
||||
Bitcoin improvement proposals are recorded in a versioned repository on https://github.com/bitcoin/bips[GitHub]. <<table_d-1>> shows a snapshot of BIPs in the Fall of 2014. Consult the authoritative repository for up-to-date information on existing BIPs and their contents.
|
||||
|
||||
[[table_d-1]]
|
||||
.Snapshot of BIPs
|
||||
[options="header"]
|
||||
|=======================================================================
|
||||
|BIP# | Link | Title |Owner |Type |Status
|
||||
|[[bip0001]]1|https://github.com/bitcoin/bips/blob/master/bip-0001.mediawiki|BIP Purpose and Guidelines |Amir Taaki
|
||||
|Standard |Active
|
||||
|
||||
|[[bip0010]]10|https://github.com/bitcoin/bips/blob/master/bip-0010.mediawiki|Multi-Sig Transaction Distribution |Alan
|
||||
Reiner |Informational |Draft
|
||||
|
||||
|[[bip0011]]11|https://github.com/bitcoin/bips/blob/master/bip-0011.mediawiki|M-of-N Standard Transactions |Gavin
|
||||
Andresen |Standard |Accepted
|
||||
|
||||
|[[bip0012]]12|https://github.com/bitcoin/bips/blob/master/bip-0012.mediawiki|OP_EVAL |Gavin Andresen |Standard
|
||||
|Withdrawn
|
||||
|
||||
|[[bip0013]]13|https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki|Address Format for pay-to-script-hash
|
||||
|Gavin Andresen |Standard |Final
|
||||
|
||||
|[[bip0014]]14|https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki|Protocol Version and User Agent |Amir
|
||||
Taaki, Patrick Strateman |Standard |Accepted
|
||||
|
||||
|[[bip0015]]15|https://github.com/bitcoin/bips/blob/master/bip-0015.mediawiki|Aliases |Amir Taaki |Standard |Withdrawn
|
||||
|
||||
|[[bip0016]]16|https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki|Pay To Script Hash |Gavin Andresen
|
||||
|Standard |Accepted
|
||||
|
||||
|[[bip0017]]17|https://github.com/bitcoin/bips/blob/master/bip-0017.mediawiki|OP_CHECKHASHVERIFY (CHV) |Luke Dashjr
|
||||
|Withdrawn |Draft
|
||||
|
||||
|[[bip0018]]18|https://github.com/bitcoin/bips/blob/master/bip-0018.mediawikilink:|hashScriptCheck |Luke Dashjr |Standard
|
||||
|Draft
|
||||
|
||||
|[[bip0019]]19|https://github.com/bitcoin/bips/blob/master/bip-0019.mediawiki|M-of-N Standard Transactions (Low SigOp)
|
||||
|Luke Dashjr |Standard |Draft
|
||||
|
||||
|[[bip0020]]20|https://github.com/bitcoin/bips/blob/master/bip-0020.mediawiki|URI Scheme |Luke Dashjr |Standard
|
||||
|Replaced
|
||||
|
||||
|[[bip0021]]21|https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|URI Scheme |Nils Schneider, Matt Corallo
|
||||
|Standard |Accepted
|
||||
|
||||
|[[bip0022]]22|https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki|getblocktemplate - Fundamentals |Luke
|
||||
Dashjr |Standard |Accepted
|
||||
|
||||
|[[bip0023]]23|https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki|getblocktemplate - Pooled Mining |Luke
|
||||
Dashjr |Standard |Accepted
|
||||
|
||||
|[[bip0030]]30|https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki|Duplicate transactions |Pieter Wuille
|
||||
|Standard |Accepted
|
||||
|
||||
|[[bip0031]]31|https://github.com/bitcoin/bips/blob/master/bip-0031.mediawiki|Pong message |Mike Hearn |Standard
|
||||
|Accepted
|
||||
|
||||
|[[bip0032]]32|https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki|Hierarchical Deterministic Wallets |Pieter
|
||||
Wuille |Informational |Accepted
|
||||
|
||||
|[[bip0033]]33|https://github.com/bitcoin/bips/blob/master/bip-0033.mediawiki|Stratized Nodes |Amir Taaki |Standard
|
||||
|Draft
|
||||
|
||||
|[[bip0034]]34|https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki|Block v2, Height in coinbase |Gavin
|
||||
Andresen |Standard |Accepted
|
||||
|
||||
|[[bip0035]]35|https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki|mempool message |Jeff Garzik |Standard
|
||||
|Accepted
|
||||
|
||||
|[[bip0036]]36|https://github.com/bitcoin/bips/blob/master/bip-0036.mediawiki|Custom Services |Stefan Thomas |Standard
|
||||
|Draft
|
||||
|
||||
|[[bip0037]]37|https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki|Bloom filtering |Mike Hearn and Matt
|
||||
Corallo |Standard |Accepted
|
||||
|
||||
|[[bip0038]]38|https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki|Passphrase-protected private key |Mike
|
||||
Caldwell |Standard |Draft
|
||||
|
||||
|[[bip0039]]39|https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki|Mnemonic code for generating deterministic
|
||||
keys |Slush |Standard |Draft
|
||||
|
||||
|[[bip0040]]40||Stratum wire protocol |Slush |Standard |BIP number allocated
|
||||
|
||||
|[[bip0041]]41||Stratum mining protocol |Slush |Standard |BIP number allocated
|
||||
|
||||
|[[bip0042]]42|https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki|A finite monetary supply for bitcoin
|
||||
|Pieter Wuille |Standard |Draft
|
||||
|
||||
|[[bip0043]]43|https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki|Purpose Field for Deterministic Wallets
|
||||
|Slush |Standard |Draft
|
||||
|
||||
|[[bip0044]]44|https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki|Multi-Account Hierarchy for Deterministic
|
||||
Wallets |Slush |Standard |Draft
|
||||
|
||||
|[[bip0050]]50|https://github.com/bitcoin/bips/blob/master/bip-0050.mediawiki|March 2013 Chain Fork Post-Mortem |Gavin
|
||||
Andresen |Informational |Draft
|
||||
|
||||
|[[bip0060]]60|https://github.com/bitcoin/bips/blob/master/bip-0060.mediawiki|Fixed Length "version" Message
|
||||
(Relay-Transactions Field) |Amir Taaki |Standard |Draft
|
||||
|
||||
|[[bip0061]]61|https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki|"reject" P2P message |Gavin Andresen
|
||||
|Standard |Draft
|
||||
|
||||
|[[bip0062]]62|https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki|Dealing with malleability |Pieter Wuille
|
||||
|Standard |Draft
|
||||
|
||||
|[[bip0063]]63||Stealth Addresses |Peter Todd |Standard |BIP number allocated
|
||||
|
||||
|[[bip0064]]64|https://github.com/bitcoin/bips/blob/master/bip-0064.mediawiki|getutxos message |Mike Hearn |Standard
|
||||
|Draft
|
||||
|
||||
|[[bip0070]]70|https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki|Payment protocol |Gavin Andresen |Standard
|
||||
|Draft
|
||||
|
||||
|[[bip0071]]71|https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki|Payment protocol MIME types |Gavin
|
||||
Andresen |Standard |Draft
|
||||
|
||||
|[[bip0072]]72|https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki|Payment protocol URIs |Gavin Andresen
|
||||
|Standard |Draft
|
||||
|
||||
|[[bip0073]]73|https://github.com/bitcoin/bips/blob/master/bip-0073.mediawiki|Use "Accept" header with Payment Request
|
||||
URLs |Stephen Pair |Standard |Draft(((range="endofrange", startref="ix_appdx-bips-asciidoc0")))
|
||||
|=======================================================================
|
||||
|
||||
|
@ -0,0 +1,181 @@
|
||||
[[appdx_bx]]
|
||||
[appendix]
|
||||
|
||||
== Bitcoin Explorer (bx) Commands
|
||||
|
||||
((("Bitcoin Explorer commands","commands in", id="ix_appdx-bx-asciidoc0", range="startofrange")))
|
||||
|
||||
----
|
||||
Usage: bx COMMAND [--help]
|
||||
|
||||
Info: The bx commands are:
|
||||
|
||||
address-decode
|
||||
address-embed
|
||||
address-encode
|
||||
address-validate
|
||||
base16-decode
|
||||
base16-encode
|
||||
base58-decode
|
||||
base58-encode
|
||||
base58check-decode
|
||||
base58check-encode
|
||||
base64-decode
|
||||
base64-encode
|
||||
bitcoin160
|
||||
bitcoin256
|
||||
btc-to-satoshi
|
||||
ec-add
|
||||
ec-add-secrets
|
||||
ec-multiply
|
||||
ec-multiply-secrets
|
||||
ec-new
|
||||
ec-to-address
|
||||
ec-to-public
|
||||
ec-to-wif
|
||||
fetch-balance
|
||||
fetch-header
|
||||
fetch-height
|
||||
fetch-history
|
||||
fetch-stealth
|
||||
fetch-tx
|
||||
fetch-tx-index
|
||||
hd-new
|
||||
hd-private
|
||||
hd-public
|
||||
hd-to-address
|
||||
hd-to-ec
|
||||
hd-to-public
|
||||
hd-to-wif
|
||||
help
|
||||
input-set
|
||||
input-sign
|
||||
input-validate
|
||||
message-sign
|
||||
message-validate
|
||||
mnemonic-decode
|
||||
mnemonic-encode
|
||||
ripemd160
|
||||
satoshi-to-btc
|
||||
script-decode
|
||||
script-encode
|
||||
script-to-address
|
||||
seed
|
||||
send-tx
|
||||
send-tx-node
|
||||
send-tx-p2p
|
||||
settings
|
||||
sha160
|
||||
sha256
|
||||
sha512
|
||||
stealth-decode
|
||||
stealth-encode
|
||||
stealth-public
|
||||
stealth-secret
|
||||
stealth-shared
|
||||
tx-decode
|
||||
tx-encode
|
||||
uri-decode
|
||||
uri-encode
|
||||
validate-tx
|
||||
watch-address
|
||||
wif-to-ec
|
||||
wif-to-public
|
||||
wrap-decode
|
||||
wrap-encode
|
||||
----
|
||||
|
||||
For more information, see the https://github.com/libbitcoin/libbitcoin-explorer[Bitcoin Explorer home page] and https://github.com/libbitcoin/libbitcoin-explorer/wiki[Bitcoin Explorer user documentation].
|
||||
|
||||
=== Examples of bx command use
|
||||
|
||||
Let's look at some examples of using Bitcoin Explorer commands to experiment with keys and addresses:
|
||||
|
||||
Generate a random "seed" value using the((("Bitcoin Explorer","seed command")))((("seed command (bx)"))) +seed+ command, which uses the operating system's random number generator. Pass the seed to the((("Bitcoin Explorer","ec-new command")))((("ec-new command (bx)"))) +ec-new+ command to generate a new private key. We save the standard output into the file _private_key_:
|
||||
|
||||
----
|
||||
$ bx seed | bx ec-new > private_key
|
||||
$ cat private_key
|
||||
73096ed11ab9f1db6135857958ece7d73ea7c30862145bcc4bbc7649075de474
|
||||
----
|
||||
|
||||
Now, generate the public key from that private key using the((("Bitcoin Explorer","ec-to-public command")))((("ec-to-public command (bx)"))) +ec-to-public+ command. We pass the _private_key_ file into the standard input and save the standard output of the command into a new file _public_key_:
|
||||
|
||||
----
|
||||
$ bx ec-to-public < private_key > public_key
|
||||
$ cat public_key
|
||||
02fca46a6006a62dfdd2dbb2149359d0d97a04f430f12a7626dd409256c12be500
|
||||
----
|
||||
|
||||
We can reformat the +public_key+ as an address using the((("Bitcoin Explorer","ec-to-address command")))((("ec-to-address command (bx)"))) +ec-to-address+ command. We pass the _public_key_ into standard input:
|
||||
|
||||
----
|
||||
$ bx ec-to-address < public_key
|
||||
17re1S4Q8ZHyCP8Kw7xQad1Lr6XUzWUnkG
|
||||
----
|
||||
|
||||
Keys generated in this manner produce a type-0 nondeterministic wallet. That means that each key is generated from an independent seed. Bitcoin Explorer commands can also generate keys deterministically, in accordance with BIP0032. In this case, a "master" key is created from a seed and then extended deterministically to produce a tree of subkeys, resulting in a type-2 deterministic wallet.
|
||||
|
||||
First, we we use the((("Bitcoin Explorer","seed command")))((("seed command (bx)"))) +seed+ and((("Bitcoin Explorer","hd-new command")))((("hd-new command (bx)"))) +hd-new+ commands to generate a master key that will be used as the basis to derive a hierarchy of keys.
|
||||
|
||||
----
|
||||
$ bx seed > seed
|
||||
$ cat seed
|
||||
eb68ee9f3df6bd4441a9feadec179ff1
|
||||
|
||||
$ bx hd-new < seed > master
|
||||
$ cat master
|
||||
xprv9s21ZrQH143K2BEhMYpNQoUvAgiEjArAVaZaCTgsaGe6LsAnwubeiTcDzd23mAoyizm9cApe51gNfLMkBqkYoWWMCRwzfuJk8RwF1SVEpAQ
|
||||
----
|
||||
|
||||
We now use the((("Bitcoin Explorer","hd-private command")))((("hd-private command (bx)"))) +hd-private+ command to generate a hardened "account" key and a sequence of two private keys within the account.
|
||||
|
||||
----
|
||||
$ bx hd-private --hard < master > account
|
||||
$ cat account
|
||||
xprv9vkDLt81dTKjwHB8fsVB5QK8cGnzveChzSrtCfvu3aMWvQaThp59ueufuyQ8Qi3qpjk4aKsbmbfxwcgS8PYbgoR2NWHeLyvg4DhoEE68A1n
|
||||
|
||||
$ bx hd-private --index 0 < account
|
||||
xprv9xHfb6w1vX9xgZyPNXVgAhPxSsEkeRcPHEUV5iJcVEsuUEACvR3NRY3fpGhcnBiDbvG4LgndirDsia1e9F3DWPkX7Tp1V1u97HKG1FJwUpU
|
||||
|
||||
$ bx hd-private --index 1 < account
|
||||
xprv9xHfb6w1vX9xjc8XbN4GN86jzNAZ6xHEqYxzbLB4fzHFd6VqCLPGRZFsdjsuMVERadbgDbziCRJru9n6tzEWrASVpEdrZrFidt1RDfn4yA3
|
||||
----
|
||||
|
||||
Next we use the((("Bitcoin Explorer","hd-public command")))((("hd-public command (bx)"))) +hd-public+ command to generate the corresponding sequence of two public keys.
|
||||
|
||||
----
|
||||
$ bx hd-public --index 0 < account
|
||||
xpub6BH1zcTuktiFu43rUZ2gXqLgzu5F3tLEeTQ5t6iE3aQtM2VMTxMcyLN9fYHiGhGpQe9QQYmqL2eYPFJ3vezHz5wzaSW4FiGrseNDR4LKqTy
|
||||
|
||||
$ bx hd-public --index 1 < account
|
||||
xpub6BH1zcTuktiFx6CzhPbGjG3UYQ13WR16CmtbPiagEKpEVtpyjshWyMaMV1cn7nUPUkgQHPVXJVqsrA8xWbGQDhohEcDFTEYMvYzwRD7Juf8
|
||||
----
|
||||
|
||||
The public keys can also be derived from their corresponding private keys using the((("Bitcoin Explorer","hd-to-public command")))((("hd-to-public command (bx)"))) +hd-to-public+ command.
|
||||
|
||||
----
|
||||
$ bx hd-private --index 0 < account | bx hd-to-public
|
||||
xpub6BH1zcTuktiFu43rUZ2gXqLgzu5F3tLEeTQ5t6iE3aQtM2VMTxMcyLN9fYHiGhGpQe9QQYmqL2eYPFJ3vezHz5wzaSW4FiGrseNDR4LKqTy
|
||||
|
||||
$ bx hd-private --index 1 < account | bx hd-to-public
|
||||
xpub6BH1zcTuktiFx6CzhPbGjG3UYQ13WR16CmtbPiagEKpEVtpyjshWyMaMV1cn7nUPUkgQHPVXJVqsrA8xWbGQDhohEcDFTEYMvYzwRD7Juf8
|
||||
----
|
||||
|
||||
We can generate a practically limitless number of keys in a deterministic chain, all derived from a single seed. This technique is used in many wallet applications to generate keys that can be backed up and restored with a single seed value. This is easier than having to back up the wallet with all its randomly generated keys every time a new key is created.
|
||||
|
||||
The seed can be encoded using the((("Bitcoin Explorer","mnemonic-encode command")))((("mnemonic-encode command (bx)"))) +mnemonic-encode+ command.
|
||||
|
||||
----
|
||||
$ bx hd-mnemonic < seed > words
|
||||
adore repeat vision worst especially veil inch woman cast recall dwell appreciate
|
||||
----
|
||||
|
||||
The seed can then be decoded using the((("Bitcoin Explorer","mnemonic-decode command")))((("mnemonic-decode command (bx)"))) +mnemonic-decode+ command.
|
||||
|
||||
----
|
||||
$ bx mnemonic-decode < words
|
||||
eb68ee9f3df6bd4441a9feadec179ff1
|
||||
----
|
||||
|
||||
Mnemonic encoding can make the seed easier to record and even remember.(((range="endofrange", startref="ix_appdx-bx-asciidoc0")))
|
@ -0,0 +1,440 @@
|
||||
[[appdx-pycoin]]
|
||||
[appendix]
|
||||
|
||||
== pycoin, ku, and tx
|
||||
|
||||
|
||||
The Python library http://github.com/richardkiss/pycoin[+pycoin+], originally written and maintained by Richard Kiss, is a Python-based library that supports manipulation of bitcoin keys and transactions, even supporting the scripting language enough to properly deal with nonstandard transactions.
|
||||
|
||||
The pycoin library supports both Python 2 (2.7.x) and Python 3 (after 3.3), and comes with some handy command-line utilities, ku and tx.
|
||||
|
||||
=== Key Utility (KU)
|
||||
|
||||
((("key utility (ku)", id="ix_appdx-pycoin-asciidoc0", range="startofrange")))The command-line utility +ku+ ("key utility") is a Swiss Army knife for manipulating keys. It supports BIP32 keys, WIF, and addresses (bitcoin and alt coins). Following are some examples.
|
||||
|
||||
Create a BIP32 key using the default entropy sources of GPG and _/dev/random_:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku create
|
||||
|
||||
input : create
|
||||
network : Bitcoin
|
||||
wallet key : xprv9s21ZrQH143K3LU5ctPZTBnb9kTjA5Su9DcWHvXJemiJBsY7VqXUG7hipgdWaU
|
||||
m2nhnzdvxJf5KJo9vjP2nABX65c5sFsWsV8oXcbpehtJi
|
||||
public version : xpub661MyMwAqRbcFpYYiuvZpKjKhnJDZYAkWSY76JvvD7FH4fsG3Nqiov2CfxzxY8
|
||||
DGcpfT56AMFeo8M8KPkFMfLUtvwjwb6WPv8rY65L2q8Hz
|
||||
tree depth : 0
|
||||
fingerprint : 9d9c6092
|
||||
parent f'print : 00000000
|
||||
child index : 0
|
||||
chain code : 80574fb260edaa4905bc86c9a47d30c697c50047ed466c0d4a5167f6821e8f3c
|
||||
private key : yes
|
||||
secret exponent : 112471538590155650688604752840386134637231974546906847202389294096567806844862
|
||||
hex : f8a8a28b28a916e1043cc0aca52033a18a13cab1638d544006469bc171fddfbe
|
||||
wif : L5Z54xi6qJusQT42JHA44mfPVZGjyb4XBRWfxAzUWwRiGx1kV4sP
|
||||
uncompressed : 5KhoEavGNNH4GHKoy2Ptu4KfdNp4r56L5B5un8FP6RZnbsz5Nmb
|
||||
public pair x : 76460638240546478364843397478278468101877117767873462127021560368290114016034
|
||||
public pair y : 59807879657469774102040120298272207730921291736633247737077406753676825777701
|
||||
x as hex : a90b3008792432060fa04365941e09a8e4adf928bdbdb9dad41131274e379322
|
||||
y as hex : 843a0f6ed9c0eb1962c74533795406914fe3f1957c5238951f4fe245a4fcd625
|
||||
y parity : odd
|
||||
key pair as sec : 03a90b3008792432060fa04365941e09a8e4adf928bdbdb9dad41131274e379322
|
||||
uncompressed : 04a90b3008792432060fa04365941e09a8e4adf928bdbdb9dad41131274e379322
|
||||
843a0f6ed9c0eb1962c74533795406914fe3f1957c5238951f4fe245a4fcd625
|
||||
hash160 : 9d9c609247174ae323acfc96c852753fe3c8819d
|
||||
uncompressed : 8870d869800c9b91ce1eb460f4c60540f87c15d7
|
||||
Bitcoin address : 1FNNRQ5fSv1wBi5gyfVBs2rkNheMGt86sp
|
||||
uncompressed : 1DSS5isnH4FsVaLVjeVXewVSpfqktdiQAM
|
||||
----
|
||||
====
|
||||
|
||||
Create a BIP32 key from a passphrase:
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
The passphrase in this example is way too easy to guess.
|
||||
====
|
||||
----
|
||||
$ ku P:foo
|
||||
|
||||
input : P:foo
|
||||
network : Bitcoin
|
||||
wallet key : xprv9s21ZrQH143K31AgNK5pyVvW23gHnkBq2wh5aEk6g1s496M8ZMjxncCKZKgb5j
|
||||
ZoY5eSJMJ2Vbyvi2hbmQnCuHBujZ2WXGTux1X2k9Krdtq
|
||||
public version : xpub661MyMwAqRbcFVF9ULcqLdsEa5WnCCugQAcgNd9iEMQ31tgH6u4DLQWoQayvtS
|
||||
VYFvXz2vPPpbXE1qpjoUFidhjFj82pVShWu9curWmb2zy
|
||||
tree depth : 0
|
||||
fingerprint : 5d353a2e
|
||||
parent f'print : 00000000
|
||||
child index : 0
|
||||
chain code : 5eeb1023fd6dd1ae52a005ce0e73420821e1d90e08be980a85e9111fd7646bbc
|
||||
private key : yes
|
||||
secret exponent : 65825730547097305716057160437970790220123864299761908948746835886007793998275
|
||||
hex : 91880b0e3017ba586b735fe7d04f1790f3c46b818a2151fb2def5f14dd2fd9c3
|
||||
wif : L26c3H6jEPVSqAr1usXUp9qtQJw6NHgApq6Ls4ncyqtsvcq2MwKH
|
||||
uncompressed : 5JvNzA5vXDoKYJdw8SwwLHxUxaWvn9mDea6k1vRPCX7KLUVWa7W
|
||||
public pair x : 81821982719381104061777349269130419024493616650993589394553404347774393168191
|
||||
public pair y : 58994218069605424278320703250689780154785099509277691723126325051200459038290
|
||||
x as hex : b4e599dfa44555a4ed38bcfff0071d5af676a86abf123c5b4b4e8e67a0b0b13f
|
||||
y as hex : 826d8b4d3010aea16ff4c1c1d3ae68541d9a04df54a2c48cc241c2983544de52
|
||||
y parity : even
|
||||
key pair as sec : 02b4e599dfa44555a4ed38bcfff0071d5af676a86abf123c5b4b4e8e67a0b0b13f
|
||||
uncompressed : 04b4e599dfa44555a4ed38bcfff0071d5af676a86abf123c5b4b4e8e67a0b0b13f
|
||||
826d8b4d3010aea16ff4c1c1d3ae68541d9a04df54a2c48cc241c2983544de52
|
||||
hash160 : 5d353a2ecdb262477172852d57a3f11de0c19286
|
||||
uncompressed : e5bd3a7e6cb62b4c820e51200fb1c148d79e67da
|
||||
Bitcoin address : 19Vqc8uLTfUonmxUEZac7fz1M5c5ZZbAii
|
||||
uncompressed : 1MwkRkogzBRMehBntgcq2aJhXCXStJTXHT
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
Get info as JSON:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku P:foo -P -j
|
||||
----
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"y_parity": "even",
|
||||
"public_pair_y_hex": "826d8b4d3010aea16ff4c1c1d3ae68541d9a04df54a2c48cc241c2983544de52",
|
||||
"private_key": "no",
|
||||
"parent_fingerprint": "00000000",
|
||||
"tree_depth": "0",
|
||||
"network": "Bitcoin",
|
||||
"btc_address_uncompressed": "1MwkRkogzBRMehBntgcq2aJhXCXStJTXHT",
|
||||
"key_pair_as_sec_uncompressed": "04b4e599dfa44555a4ed38bcfff0071d5af676a86abf123c5b4b4e8e67a0b0b13f826d8b4d3010aea16ff4c1c1d3ae68541d9a04df54a2c48cc241c2983544de52",
|
||||
"public_pair_x_hex": "b4e599dfa44555a4ed38bcfff0071d5af676a86abf123c5b4b4e8e67a0b0b13f",
|
||||
"wallet_key": "xpub661MyMwAqRbcFVF9ULcqLdsEa5WnCCugQAcgNd9iEMQ31tgH6u4DLQWoQayvtSVYFvXz2vPPpbXE1qpjoUFidhjFj82pVShWu9curWmb2zy",
|
||||
"chain_code": "5eeb1023fd6dd1ae52a005ce0e73420821e1d90e08be980a85e9111fd7646bbc",
|
||||
"child_index": "0",
|
||||
"hash160_uncompressed": "e5bd3a7e6cb62b4c820e51200fb1c148d79e67da",
|
||||
"btc_address": "19Vqc8uLTfUonmxUEZac7fz1M5c5ZZbAii",
|
||||
"fingerprint": "5d353a2e",
|
||||
"hash160": "5d353a2ecdb262477172852d57a3f11de0c19286",
|
||||
"input": "P:foo",
|
||||
"public_pair_x": "81821982719381104061777349269130419024493616650993589394553404347774393168191",
|
||||
"public_pair_y": "58994218069605424278320703250689780154785099509277691723126325051200459038290",
|
||||
"key_pair_as_sec": "02b4e599dfa44555a4ed38bcfff0071d5af676a86abf123c5b4b4e8e67a0b0b13f"
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Public BIP32 key:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -w -P P:foo
|
||||
xpub661MyMwAqRbcFVF9ULcqLdsEa5WnCCugQAcgNd9iEMQ31tgH6u4DLQWoQayvtSVYFvXz2vPPpbXE1qpjoUFidhjFj82pVShWu9curWmb2zy
|
||||
----
|
||||
====
|
||||
|
||||
Generate a subkey:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -w -s3/2 P:foo
|
||||
xprv9wTErTSkjVyJa1v4cUTFMFkWMe5eu8ErbQcs9xajnsUzCBT7ykHAwdrxvG3g3f6BFk7ms5hHBvmbdutNmyg6iogWKxx6mefEw4M8EroLgKj
|
||||
----
|
||||
====
|
||||
|
||||
Hardened subkey:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -w -s3/2H P:foo
|
||||
xprv9wTErTSu5AWGkDeUPmqBcbZWX1xq85ZNX9iQRQW9DXwygFp7iRGJo79dsVctcsCHsnZ3XU3DhsuaGZbDh8iDkBN45k67UKsJUXM1JfRCdn1
|
||||
----
|
||||
====
|
||||
|
||||
WIF:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -W P:foo
|
||||
L26c3H6jEPVSqAr1usXUp9qtQJw6NHgApq6Ls4ncyqtsvcq2MwKH
|
||||
----
|
||||
====
|
||||
|
||||
Address:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -a P:foo
|
||||
19Vqc8uLTfUonmxUEZac7fz1M5c5ZZbAii
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
Generate a bunch of subkeys:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku P:foo -s 0/0-5 -w
|
||||
xprv9xWkBDfyBXmZjBG9EiXBpy67KK72fphUp9utJokEBFtjsjiuKUUDF5V3TU8U8cDzytqYnSekc8bYuJS8G3bhXxKWB89Ggn2dzLcoJsuEdRK
|
||||
xprv9xWkBDfyBXmZnzKf3bAGifK593gT7WJZPnYAmvc77gUQVej5QHckc5Adtwxa28ACmANi9XhCrRvtFqQcUxt8rUgFz3souMiDdWxJDZnQxzx
|
||||
xprv9xWkBDfyBXmZqdXA8y4SWqfBdy71gSW9sjx9JpCiJEiBwSMQyRxan6srXUPBtj3PTxQFkZJAiwoUpmvtrxKZu4zfsnr3pqyy2vthpkwuoVq
|
||||
xprv9xWkBDfyBXmZsA85GyWj9uYPyoQv826YAadKWMaaEosNrFBKgj2TqWuiWY3zuqxYGpHfv9cnGj5P7e8EskpzKL1Y8Gk9aX6QbryA5raK73p
|
||||
xprv9xWkBDfyBXmZv2q3N66hhZ8DAcEnQDnXML1J62krJAcf7Xb1HJwuW2VMJQrCofY2jtFXdiEY8UsRNJfqK6DAdyZXoMvtaLHyWQx3FS4A9zw
|
||||
xprv9xWkBDfyBXmZw4jEYXUHYc9fT25k9irP87n2RqfJ5bqbjKdT84Mm7Wtc2xmzFuKg7iYf7XFHKkSsaYKWKJbR54bnyAD9GzjUYbAYTtN4ruo
|
||||
----
|
||||
====
|
||||
|
||||
Generate the corresponding addresses:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku P:foo -s 0/0-5 -a
|
||||
1MrjE78H1R1rqdFrmkjdHnPUdLCJALbv3x
|
||||
1AnYyVEcuqeoVzH96zj1eYKwoWfwte2pxu
|
||||
1GXr1kZfxE1FcK6ZRD5sqqqs5YfvuzA1Lb
|
||||
116AXZc4bDVQrqmcinzu4aaPdrYqvuiBEK
|
||||
1Cz2rTLjRM6pMnxPNrRKp9ZSvRtj5dDUML
|
||||
1WstdwPnU6HEUPme1DQayN9nm6j7nDVEM
|
||||
----
|
||||
====
|
||||
|
||||
Generate the corresponding WIFs:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku P:foo -s 0/0-5 -W
|
||||
L5a4iE5k9gcJKGqX3FWmxzBYQc29PvZ6pgBaePLVqT5YByEnBomx
|
||||
Kyjgne6GZwPGB6G6kJEhoPbmyjMP7D5d3zRbHVjwcq4iQXD9QqKQ
|
||||
L4B3ygQxK6zH2NQGxLDee2H9v4Lvwg14cLJW7QwWPzCtKHdWMaQz
|
||||
L2L2PZdorybUqkPjrmhem4Ax5EJvP7ijmxbNoQKnmTDMrqemY8UF
|
||||
L2oD6vA4TUyqPF8QG4vhUFSgwCyuuvFZ3v8SKHYFDwkbM765Nrfd
|
||||
KzChTbc3kZFxUSJ3Kt54cxsogeFAD9CCM4zGB22si8nfKcThQn8C
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
Check that it works by choosing a BIP32 string (the one corresponding to subkey 0/3):
|
||||
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -W xprv9xWkBDfyBXmZsA85GyWj9uYPyoQv826YAadKWMaaEosNrFBKgj2TqWuiWY3zuqxYGpHfv9cnGj5P7e8EskpzKL1Y8Gk9aX6QbryA5raK73p
|
||||
L2L2PZdorybUqkPjrmhem4Ax5EJvP7ijmxbNoQKnmTDMrqemY8UF
|
||||
$ ku -a xprv9xWkBDfyBXmZsA85GyWj9uYPyoQv826YAadKWMaaEosNrFBKgj2TqWuiWY3zuqxYGpHfv9cnGj5P7e8EskpzKL1Y8Gk9aX6QbryA5raK73p
|
||||
116AXZc4bDVQrqmcinzu4aaPdrYqvuiBEK
|
||||
----
|
||||
====
|
||||
|
||||
Yep, looks familiar.
|
||||
|
||||
From secret exponent:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku 1
|
||||
|
||||
input : 1
|
||||
network : Bitcoin
|
||||
secret exponent : 1
|
||||
hex : 1
|
||||
wif : KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn
|
||||
uncompressed : 5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf
|
||||
public pair x : 55066263022277343669578718895168534326250603453777594175500187360389116729240
|
||||
public pair y : 32670510020758816978083085130507043184471273380659243275938904335757337482424
|
||||
x as hex : 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
y as hex : 483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
|
||||
y parity : even
|
||||
key pair as sec : 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
uncompressed : 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
|
||||
hash160 : 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
uncompressed : 91b24bf9f5288532960ac687abb035127b1d28a5
|
||||
Bitcoin address : 1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH
|
||||
uncompressed : 1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm
|
||||
----
|
||||
====
|
||||
|
||||
Litecoin version:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -nL 1
|
||||
|
||||
input : 1
|
||||
network : Litecoin
|
||||
secret exponent : 1
|
||||
hex : 1
|
||||
wif : T33ydQRKp4FCW5LCLLUB7deioUMoveiwekdwUwyfRDeGZm76aUjV
|
||||
uncompressed : 6u823ozcyt2rjPH8Z2ErsSXJB5PPQwK7VVTwwN4mxLBFrao69XQ
|
||||
public pair x : 55066263022277343669578718895168534326250603453777594175500187360389116729240
|
||||
public pair y : 32670510020758816978083085130507043184471273380659243275938904335757337482424
|
||||
x as hex : 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
y as hex : 483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
|
||||
y parity : even
|
||||
key pair as sec : 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
uncompressed : 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
|
||||
hash160 : 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
uncompressed : 91b24bf9f5288532960ac687abb035127b1d28a5
|
||||
Litecoin address : LVuDpNCSSj6pQ7t9Pv6d6sUkLKoqDEVUnJ
|
||||
uncompressed : LYWKqJhtPeGyBAw7WC8R3F7ovxtzAiubdM
|
||||
----
|
||||
====
|
||||
|
||||
Dogecoin((("Dogecoin"))) WIF:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -nD -W 1
|
||||
QNcdLVw8fHkixm6NNyN6nVwxKek4u7qrioRbQmjxac5TVoTtZuot
|
||||
----
|
||||
====
|
||||
|
||||
From public pair (on Testnet):
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -nT 55066263022277343669578718895168534326250603453777594175500187360389116729240,even
|
||||
|
||||
input : 550662630222773436695787188951685343262506034537775941755001873603
|
||||
89116729240,even
|
||||
network : Bitcoin testnet
|
||||
public pair x : 55066263022277343669578718895168534326250603453777594175500187360389116729240
|
||||
public pair y : 32670510020758816978083085130507043184471273380659243275938904335757337482424
|
||||
x as hex : 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
y as hex : 483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
|
||||
y parity : even
|
||||
key pair as sec : 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
uncompressed : 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
|
||||
hash160 : 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
uncompressed : 91b24bf9f5288532960ac687abb035127b1d28a5
|
||||
Bitcoin testnet address : mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r
|
||||
uncompressed : mtoKs9V381UAhUia3d7Vb9GNak8Qvmcsme
|
||||
----
|
||||
====
|
||||
|
||||
From hash160:
|
||||
|
||||
====
|
||||
----
|
||||
$ ku 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
|
||||
input : 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
network : Bitcoin
|
||||
hash160 : 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
Bitcoin address : 1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH
|
||||
----
|
||||
====
|
||||
|
||||
As a Dogecoin address:(((range="endofrange", startref="ix_appdx-pycoin-asciidoc0")))
|
||||
|
||||
====
|
||||
----
|
||||
$ ku -nD 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
|
||||
input : 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
network : Dogecoin
|
||||
hash160 : 751e76e8199196d454941c45d1b3a323f1433bd6
|
||||
Dogecoin address : DFpN6QqFfUm3gKNaxN6tNcab1FArL9cZLE
|
||||
----
|
||||
|
||||
==== Transaction Utility (TX)
|
||||
|
||||
((("transaction utility (tx)")))The command-line utility +tx+ will display transactions in human-readable form, fetch base transactions from pycoin's transaction cache or from web services (blockchain.info, blockr.io, and biteasy.com are currently supported), merge transactions, add or delete inputs or outputs, and sign transactions.
|
||||
|
||||
Following are some examples.
|
||||
|
||||
|
||||
View the famous "pizza" transaction [PIZZA]:
|
||||
|
||||
====
|
||||
----
|
||||
$ tx 49d2adb6e476fa46d8357babf78b1b501fd39e177ac7833124b3f67b17c40c2a
|
||||
warning: consider setting environment variable PYCOIN_CACHE_DIR=~/.pycoin_cache to cache transactions fetched via web services
|
||||
warning: no service providers found for get_tx; consider setting environment variable PYCOIN_SERVICE_PROVIDERS=BLOCKR_IO:BLOCKCHAIN_INFO:BITEASY:BLOCKEXPLORER
|
||||
usage: tx [-h] [-t TRANSACTION_VERSION] [-l LOCK_TIME] [-n NETWORK] [-a]
|
||||
[-i address] [-f path-to-private-keys] [-g GPG_ARGUMENT]
|
||||
[--remove-tx-in tx_in_index_to_delete]
|
||||
[--remove-tx-out tx_out_index_to_delete] [-F transaction-fee] [-u]
|
||||
[-b BITCOIND_URL] [-o path-to-output-file]
|
||||
argument [argument ...]
|
||||
tx: error: can't find Tx with id 49d2adb6e476fa46d8357babf78b1b501fd39e177ac7833124b3f67b17c40c2a
|
||||
----
|
||||
====
|
||||
|
||||
Oops! We don't have web services set up. Let's do that now:
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
$ PYCOIN_CACHE_DIR=~/.pycoin_cache
|
||||
$ PYCOIN_SERVICE_PROVIDERS=BLOCKR_IO:BLOCKCHAIN_INFO:BITEASY:BLOCKEXPLORER
|
||||
$ export PYCOIN_CACHE_DIR PYCOIN_SERVICE_PROVIDERS
|
||||
----
|
||||
====
|
||||
|
||||
It's not done automatically so a command-line tool won't leak potentially private information about what transactions you're interested in to a third-party website. If you don't care, you could put these lines into your _.profile_.
|
||||
|
||||
Let's try again:
|
||||
|
||||
====
|
||||
----
|
||||
$ tx 49d2adb6e476fa46d8357babf78b1b501fd39e177ac7833124b3f67b17c40c2a
|
||||
Version: 1 tx hash 49d2adb6e476fa46d8357babf78b1b501fd39e177ac7833124b3f67b17c40c2a 159 bytes
|
||||
TxIn count: 1; TxOut count: 1
|
||||
Lock time: 0 (valid anytime)
|
||||
Input:
|
||||
0: (unknown) from 1e133f7de73ac7d074e2746a3d6717dfc99ecaa8e9f9fade2cb8b0b20a5e0441:0
|
||||
Output:
|
||||
0: 1CZDM6oTttND6WPdt3D6bydo7DYKzd9Qik receives 10000000.00000 mBTC
|
||||
Total output 10000000.00000 mBTC
|
||||
including unspents in hex dump since transaction not fully signed
|
||||
010000000141045e0ab2b0b82cdefaf9e9a8ca9ec9df17673d6a74e274d0c73ae77d3f131e000000004a493046022100a7f26eda874931999c90f87f01ff1ffc76bcd058fe16137e0e63fdb6a35c2d78022100a61e9199238eb73f07c8f209504c84b80f03e30ed8169edd44f80ed17ddf451901ffffffff010010a5d4e80000001976a9147ec1003336542cae8bded8909cdd6b5e48ba0ab688ac00000000
|
||||
|
||||
** can't validate transaction as source transactions missing
|
||||
----
|
||||
====
|
||||
|
||||
The final line appears because to validate the transactions' signatures, you technically need the source transactions. So let's add +-a+ to augment the transactions with source information:
|
||||
|
||||
====
|
||||
----
|
||||
$ tx -a 49d2adb6e476fa46d8357babf78b1b501fd39e177ac7833124b3f67b17c40c2a
|
||||
warning: transaction fees recommendations casually calculated and estimates may be incorrect
|
||||
warning: transaction fee lower than (casually calculated) expected value of 0.1 mBTC, transaction might not propogate
|
||||
Version: 1 tx hash 49d2adb6e476fa46d8357babf78b1b501fd39e177ac7833124b3f67b17c40c2a 159 bytes
|
||||
TxIn count: 1; TxOut count: 1
|
||||
Lock time: 0 (valid anytime)
|
||||
Input:
|
||||
0: 17WFx2GQZUmh6Up2NDNCEDk3deYomdNCfk from 1e133f7de73ac7d074e2746a3d6717dfc99ecaa8e9f9fade2cb8b0b20a5e0441:0 10000000.00000 mBTC sig ok
|
||||
Output:
|
||||
0: 1CZDM6oTttND6WPdt3D6bydo7DYKzd9Qik receives 10000000.00000 mBTC
|
||||
Total input 10000000.00000 mBTC
|
||||
Total output 10000000.00000 mBTC
|
||||
Total fees 0.00000 mBTC
|
||||
|
||||
010000000141045e0ab2b0b82cdefaf9e9a8ca9ec9df17673d6a74e274d0c73ae77d3f131e000000004a493046022100a7f26eda874931999c90f87f01ff1ffc76bcd058fe16137e0e63fdb6a35c2d78022100a61e9199238eb73f07c8f209504c84b80f03e30ed8169edd44f80ed17ddf451901ffffffff010010a5d4e80000001976a9147ec1003336542cae8bded8909cdd6b5e48ba0ab688ac00000000
|
||||
|
||||
all incoming transaction values validated
|
||||
----
|
||||
====
|
||||
|
||||
Now, let's look at unspent outputs for a specific address (UTXO). In block #1, we see a coinbase transaction to +12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX+. Let's use +fetch_unspent+ to find all coins in this address:
|
||||
|
||||
====
|
||||
----
|
||||
$ fetch_unspent 12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX
|
||||
a3a6f902a51a2cbebede144e48a88c05e608c2cce28024041a5b9874013a1e2a/0/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/333000
|
||||
cea36d008badf5c7866894b191d3239de9582d89b6b452b596f1f1b76347f8cb/31/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/10000
|
||||
065ef6b1463f552f675622a5d1fd2c08d6324b4402049f68e767a719e2049e8d/86/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/10000
|
||||
a66dddd42f9f2491d3c336ce5527d45cc5c2163aaed3158f81dc054447f447a2/0/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/10000
|
||||
ffd901679de65d4398de90cefe68d2c3ef073c41f7e8dbec2fb5cd75fe71dfe7/0/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/100
|
||||
d658ab87cc053b8dbcfd4aa2717fd23cc3edfe90ec75351fadd6a0f7993b461d/5/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/911
|
||||
36ebe0ca3237002acb12e1474a3859bde0ac84b419ec4ae373e63363ebef731c/1/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/100000
|
||||
fd87f9adebb17f4ebb1673da76ff48ad29e64b7afa02fda0f2c14e43d220fe24/0/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/1
|
||||
dfdf0b375a987f17056e5e919ee6eadd87dad36c09c4016d4a03cea15e5c05e3/1/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/1337
|
||||
cb2679bfd0a557b2dc0d8a6116822f3fcbe281ca3f3e18d3855aa7ea378fa373/0/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/1337
|
||||
d6be34ccf6edddc3cf69842dce99fe503bf632ba2c2adb0f95c63f6706ae0c52/1/76a914119b098e2e980a229e139a9ed01a469e518e6f2688ac/2000000
|
||||
0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098/0/410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac/5000000000
|
||||
----
|
||||
====
|
||||
|
@ -0,0 +1,81 @@
|
||||
[[appdx01]]
|
||||
[appendix]
|
||||
== Bitcoin financial services
|
||||
|
||||
|
||||
|
||||
This appendix describes the main financial services offered in the bitcoin economy, comparing them to traditional financial services that are already familiar to consumers. It's not a list of sites or companies, as that would go stale immediately. Instead it is a list of service primitives with examples of existing implementations. For example, an escrow
|
||||
service would be described as an archetype, by analogy to a real-estate escrow, showing the unique characteristics, use case and need for escrow in the bitcoin world. The escrow service archetype would be followed by two or three examples of well implemented actual escrow services, each demonstrating a capability unique to bitcoin.
|
||||
|
||||
=== Currency Exchanges
|
||||
|
||||
=== Bitcoin market data services
|
||||
|
||||
=== Bitcoin ticker, order book, chart and analysis services
|
||||
|
||||
=== Peer-to-peer exchange
|
||||
|
||||
=== OTC and Web-of-Trust (WoT)
|
||||
|
||||
=== Escrow services
|
||||
|
||||
=== Monitoring services
|
||||
|
||||
=== Alert and notification services
|
||||
|
||||
=== Lending
|
||||
|
||||
=== P2P Lending
|
||||
|
||||
=== Securities
|
||||
|
||||
=== Mutual Funds
|
||||
|
||||
=== Angel investing
|
||||
|
||||
== Appendix: Bitcoin markets and applications
|
||||
|
||||
As above, this appendix describes services offered in the bitcoin economy. Each service is described a a service archetype which is compared to a real-world example familiar to anyone. The description of such a service is followed by real-world examples that express
|
||||
these bitcoin features.
|
||||
|
||||
=== Currency transfer
|
||||
|
||||
=== US domestic
|
||||
|
||||
=== Other in-country
|
||||
|
||||
=== International
|
||||
|
||||
=== Retail commerce
|
||||
|
||||
=== Physical (tangible) goods
|
||||
|
||||
=== Intangible products
|
||||
|
||||
=== Services
|
||||
|
||||
=== Technology services
|
||||
|
||||
=== Re-selling and Cross-selling
|
||||
|
||||
=== Wholesale commerce
|
||||
|
||||
|
||||
== Appendix: Bitcoin Protocol Structure and Conventions
|
||||
|
||||
Reference index of main protocol primitives, packet structure, opcodes, state enumerations, protocol mechanics, time diagrams and protocol validation mechanisms.
|
||||
|
||||
|
||||
== Appendix: Bitcoin Transaction Script Operands and Tokens
|
||||
|
||||
More reference material as above
|
||||
|
||||
|
||||
== Appendix: Bitcoin Cryptography Algorithms, Conventions and Conversions.
|
||||
|
||||
More reference material as above
|
||||
|
||||
|
||||
== Appendix: Bitcoin Meta-protocols: Mining Pool Protocols, Lightweight Client Protocols
|
||||
|
||||
More reference material as above
|
@ -1,9 +0,0 @@
|
||||
<section data-type="appendix">
|
||||
<h1>Appendix Title</h1>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>This Is an A-Head</h1>
|
||||
|
||||
<p>An appendix is generally used for extra material that supplements your main book content.</p>
|
||||
</section>
|
||||
</section>
|
@ -0,0 +1,301 @@
|
||||
[[bitcoin_network_ch06]]
|
||||
== The Bitcoin Network
|
||||
|
||||
=== Peer-to-Peer Network Architecture
|
||||
|
||||
((("bitcoin network", id="ix_ch06-asciidoc0", range="startofrange")))((("bitcoin network","architecture of")))((("peer-to-peer networks")))Bitcoin is structured as a peer-to-peer network architecture on top of the Internet. The term peer-to-peer, or P2P, means that the computers that participate in the network are peers to each other, that they are all equal, that there are no "special" nodes, and that all nodes share the burden of providing network services. The network nodes interconnect in a mesh network with a "flat" topology. There is no server, no centralized service, and no hierarchy within the network. Nodes in a peer-to-peer network both provide and consume services at the same time with reciprocity acting as the incentive for participation. Peer-to-peer networks are inherently resilient, decentralized, and open. The preeminent example of a P2P network architecture was the early Internet itself, where nodes on the IP network were equal. Today's Internet architecture is more hierarchical, but the Internet Protocol still retains its flat-topology essence. Beyond bitcoin, the largest and most successful application of P2P technologies is file sharing with Napster as the pioneer and BitTorrent as the most recent evolution of the architecture.
|
||||
|
||||
Bitcoin's P2P network architecture is much more than a topology choice. Bitcoin is a peer-to-peer digital cash system by design, and the network architecture is both a reflection and a foundation of that core characteristic. Decentralization of control is a core design principle and that can only be achieved and maintained by a flat, decentralized P2P consensus network.
|
||||
|
||||
((("bitcoin network","defined")))The term "bitcoin network" refers to the collection of nodes running the bitcoin P2P protocol. In addition to the bitcoin P2P protocol, there are other protocols such as((("Stratum (STM) mining protocol"))) Stratum, which are used for mining and lightweight or mobile wallets. These additional protocols are provided by gateway routing servers that access the bitcoin network using the bitcoin P2P protocol, and then extend that network to nodes running other protocols. For example, Stratum servers connect Stratum mining nodes via the Stratum protocol to the main bitcoin network and bridge the Stratum protocol to the bitcoin P2P protocol. We use the term "extended bitcoin network" to refer to the overall network that includes the bitcoin P2P protocol, pool-mining protocols, the Stratum protocol, and any other related protocols connecting the components of the bitcoin system.
|
||||
|
||||
=== Nodes Types and Roles
|
||||
|
||||
((("bitcoin network","nodes")))((("nodes","roles of")))((("nodes","types of")))Although nodes in the bitcoin P2P network are equal, they may take on different roles depending on the functionality they are supporting. A bitcoin node is a collection of functions: routing, the blockchain database, mining, and wallet services. A full node with all four of these functions is shown in <<full_node_reference>>.
|
||||
|
||||
[[full_node_reference]]
|
||||
.A bitcoin network node with all four functions: wallet, miner, full blockchain database, and network routing
|
||||
image::images/msbt_0601.png["FullNodeReferenceClient_Small"]
|
||||
|
||||
All nodes include the routing function to participate in the network and might include other functionality. All nodes validate and propagate transactions and blocks, and discover and maintain connections to peers. In the full-node example in <<full_node_reference>>, the routing function is indicated by an orange circle named "Network Routing Node."
|
||||
|
||||
Some nodes, called full nodes, also maintain a complete and up-to-date copy of the blockchain. Full nodes can autonomously and authoritatively verify any transaction without external reference. Some nodes maintain only a subset of the blockchain and verify transactions using a method called((("simplified payment verification (SPV) nodes","defined"))) _simplified payment verification_, or SPV. These nodes are known as SPV or lightweight nodes. In the full-node example in the figure, the full-node blockchain database function is indicated by a blue circle named "Full Blockchain." In <<bitcoin_network>>, SPV nodes are drawn without the blue circle, showing that they do not have a full copy of the blockchain.
|
||||
|
||||
Mining nodes compete to create new blocks by running specialized hardware to solve the proof-of-work algorithm. Some mining nodes are also full nodes, maintaining a full copy of the blockchain, while others are lightweight nodes participating in pool mining and depending on a pool server to maintain a full node. The mining function is shown in the full node as a black circle named "Miner."
|
||||
|
||||
User wallets might be part of a full node, as is usually the case with desktop bitcoin clients. Increasingly, many user wallets, especially those running on resource-constrained devices such as smartphones, are SPV nodes. The wallet function is shown in <<full_node_reference>> as a green circle named "Wallet".
|
||||
|
||||
In addition to the main node types on the bitcoin P2P protocol, there are servers and nodes running other protocols, such as specialized mining pool protocols and lightweight client-access protocols.
|
||||
|
||||
<<node_type_ledgend>> shows the most common node types on the extended bitcoin network.
|
||||
|
||||
=== The Extended Bitcoin Network
|
||||
|
||||
((("bitcoin network","extended")))((("extended bitcoin network")))The main bitcoin network, running the bitcoin P2P protocol, consists of between 7,000 and 10,000 listening nodes running various versions of the bitcoin reference client (Bitcoin Core) and a few hundred nodes running various other implementations of the bitcoin P2P protocol, such as((("BitcoinJ library")))((("btcd")))((("libbitcoin library"))) BitcoinJ, Libbitcoin, and btcd. A small percentage of the nodes on the bitcoin P2P network are also mining nodes, competing in the mining process, validating transactions, and creating new blocks. Various large companies interface with the bitcoin network by running full-node clients based on the Bitcoin Core client, with full copies of the blockchain and a network node, but without mining or wallet functions. These nodes act as network edge routers, allowing various other services (exchanges, wallets, block explorers, merchant payment processing) to be built on top.
|
||||
|
||||
The extended bitcoin network includes the network running the bitcoin P2P protocol, described earlier, as well as nodes running specialized protocols. Attached to the main bitcoin P2P network are a number of((("mining pools","on the bitcoin network"))) pool servers and protocol gateways that connect nodes running other protocols. These other protocol nodes are mostly pool mining nodes (see <<ch8>>) and lightweight wallet clients, which do not carry a full copy of the blockchain.
|
||||
|
||||
<<bitcoin_network>> shows the extended bitcoin network with the various types of nodes, gateway servers, edge routers, and wallet clients and the various protocols they use to connect to each other.
|
||||
|
||||
[[node_type_ledgend]]
|
||||
.Different types of nodes on the extended bitcoin network
|
||||
image::images/msbt_0602.png["BitcoinNodeTypes"]
|
||||
|
||||
[[bitcoin_network]]
|
||||
.The extended bitcoin network showing various node types, gateways, and protocols
|
||||
image::images/msbt_0603.png["BitcoinNetwork"]
|
||||
|
||||
=== Network Discovery
|
||||
|
||||
((("bitcoin network","discovery", id="ix_ch06-asciidoc1", range="startofrange")))((("network discovery", id="ix_ch06-asciidoc2", range="startofrange")))((("nodes","network discovery and", id="ix_ch06-asciidoc3", range="startofrange")))((("peer-to-peer networks","discovery by new nodes", id="ix_ch06-asciidoc4", range="startofrange")))When a new node boots up, it must discover other bitcoin nodes on the network in order to participate. To start this process, a new node must discover at least one existing node on the network and connect to it. The geographic location of other nodes is irrelevant; the bitcoin network topology is not geographically defined. Therefore, any existing bitcoin nodes can be selected at random.
|
||||
|
||||
((("peer-to-peer networks","connections")))To connect to a known peer, nodes establish a TCP connection, usually to port 8333 (the port generally known as the one used by bitcoin), or an alternative port if one is provided. Upon establishing a connection, the node will start a "handshake" (see <<network_handshake>>) by transmitting a((("version message"))) +version+ message, which contains basic identifying information, including:
|
||||
|
||||
+PROTOCOL_VERSION+:: A constant that defines the bitcoin P2P protocol version the client "speaks" (e.g., 70002)
|
||||
+nLocalServices+:: A list of local services supported by the node, currently just +NODE_NETWORK+
|
||||
+nTime+:: The current time
|
||||
+addrYou+:: The IP address of the remote node as seen from this node
|
||||
+addrMe+:: The IP address of the local node, as discovered by the local node
|
||||
+subver+:: A sub-version showing the type of software running on this node (e.g., "/Satoshi:0.9.2.1/")+
|
||||
+BestHeight+:: The block height of this node's blockchain
|
||||
|
||||
(See http://bit.ly/1qlsC7w[GitHub] for an example of the +version+ network message.)
|
||||
|
||||
The peer node responds with +verack+ to acknowledge and establish a connection, and optionally sends its own +version+ message if it wishes to reciprocate the connection and connect back as a peer.
|
||||
|
||||
How does a new node find peers? The first method is to query DNS using a number of ((("nodes","seed")))((("DNS seed")))"DNS seeds," which are DNS servers that provide a list of IP addresses of bitcoin nodes. Some of those DNS seeds provide a static list of IP addresses of stable bitcoin listening nodes. Some of the DNS seeds are custom implementations of BIND (Berkeley Internet Name Daemon) that return a random subset from a list of bitcoin node addresses collected by a crawler or a long-running bitcoin node. The Bitcoin Core client contains the names of five different DNS seeds. The diversity of ownership and diversity of implementation of the different DNS seeds offers a high level or reliability for the initial bootstrapping process. In the Bitcoin Core client, the option to use the DNS seeds is controlled by the option switch +-dnsseed+ (set to 1 by default, to use the DNS seed).
|
||||
|
||||
Alternatively, a bootstrapping node that knows nothing of the network must be given the IP address of at least one bitcoin node, after which it can establish connections through further introductions. The command-line argument +-seednode+ can be used to connect to one node just for introductions, using it as a seed. After the initial seed node is used to form introductions, the client will disconnect from it and use the newly discovered peers.
|
||||
|
||||
[[network_handshake]]
|
||||
.The initial handshake between peers
|
||||
image::images/msbt_0604.png["NetworkHandshake"]
|
||||
|
||||
Once one or more connections are established, the new node will send an((("addr message"))) +addr+ message containing its own IP address to its neighbors. The neighbors will, in turn, forward the +addr+ message to their neighbors, ensuring that the newly connected node becomes well known and better connected. Additionally, the newly connected node can send +getaddr+ to the neighbors, asking them to return a list of IP addresses of other peers. That way, a node can find peers to connect to and advertise its existence on the network for other nodes to find it. <<address_propagation>> shows the address discovery protocol.
|
||||
|
||||
|
||||
[[address_propagation]]
|
||||
.Address propagation and discovery
|
||||
image::images/msbt_0605.png["AddressPropagation"]
|
||||
|
||||
A node must connect to a few different peers in order to establish diverse paths into the bitcoin network. Paths are not reliable—nodes come and go—and so the node must continue to discover new nodes as it loses old connections as well as assist other nodes when they bootstrap. Only one connection is needed to bootstrap, because the first node can offer introductions to its peer nodes and those peers can offer further introductions. It's also unnecessary and wasteful of network resources to connect to more than a handful of nodes. After bootstrapping, a node will remember its most recent successful peer connections, so that if it is rebooted it can quickly reestablish connections with its former peer network. If none of the former peers respond to its connection request, the node can use the seed nodes to bootstrap again.
|
||||
|
||||
On a node running the Bitcoin Core client, you can list the peer connections with the command((("getpeerinfo command"))) +getpeerinfo+:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
$ bitcoin-cli getpeerinfo
|
||||
----
|
||||
[source,json]
|
||||
----
|
||||
[
|
||||
{
|
||||
"addr" : "85.213.199.39:8333",
|
||||
"services" : "00000001",
|
||||
"lastsend" : 1405634126,
|
||||
"lastrecv" : 1405634127,
|
||||
"bytessent" : 23487651,
|
||||
"bytesrecv" : 138679099,
|
||||
"conntime" : 1405021768,
|
||||
"pingtime" : 0.00000000,
|
||||
"version" : 70002,
|
||||
"subver" : "/Satoshi:0.9.2.1/",
|
||||
"inbound" : false,
|
||||
"startingheight" : 310131,
|
||||
"banscore" : 0,
|
||||
"syncnode" : true
|
||||
},
|
||||
{
|
||||
"addr" : "58.23.244.20:8333",
|
||||
"services" : "00000001",
|
||||
"lastsend" : 1405634127,
|
||||
"lastrecv" : 1405634124,
|
||||
"bytessent" : 4460918,
|
||||
"bytesrecv" : 8903575,
|
||||
"conntime" : 1405559628,
|
||||
"pingtime" : 0.00000000,
|
||||
"version" : 70001,
|
||||
"subver" : "/Satoshi:0.8.6/",
|
||||
"inbound" : false,
|
||||
"startingheight" : 311074,
|
||||
"banscore" : 0,
|
||||
"syncnode" : false
|
||||
}
|
||||
]
|
||||
----
|
||||
|
||||
((("peer-to-peer networks","automatic management, overriding")))To override the automatic management of peers and to specify a list of IP addresses, users can provide the option +-connect=<IPAddress>+ and specify one or more IP addresses. If this option is used, the node will only connect to the selected IP addresses, instead of discovering and maintaining the peer connections automatically.
|
||||
|
||||
If there is no traffic on a connection, nodes will periodically send a message to maintain the connection. If a node has not communicated on a connection for more than 90 minutes, it is assumed to be disconnected and a new peer will be sought. Thus, the network dynamically adjusts to transient nodes and network problems, and can organically grow and shrink as needed without any central control.(((range="endofrange", startref="ix_ch06-asciidoc4")))(((range="endofrange", startref="ix_ch06-asciidoc3")))(((range="endofrange", startref="ix_ch06-asciidoc2")))(((range="endofrange", startref="ix_ch06-asciidoc1")))
|
||||
|
||||
=== Full Nodes
|
||||
|
||||
((("blockchains","full nodes and")))((("full nodes")))((("nodes","full")))Full nodes are nodes that maintain a full blockchain with all transactions. More accurately, they probably should be called "full blockchain nodes." In the early years of bitcoin, all nodes were full nodes and currently the Bitcoin Core client is a full blockchain node. In the past two years, however, new forms of bitcoin clients have been introduced that do not maintain a full blockchain but run as lightweight clients. We'll examine these in more detail in the next section.
|
||||
|
||||
((("blockchains","on full nodes")))Full blockchain nodes maintain a complete and up-to-date copy of the bitcoin blockchain with all the transactions, which they independently build and verify, starting with the very first block (genesis block) and building up to the latest known block in the network. A full blockchain node can independently and authoritatively verify any transaction without recourse or reliance on any other node or source of information. The full blockchain node relies on the network to receive updates about new blocks of transactions, which it then verifies and incorporates into its local copy of the blockchain.
|
||||
|
||||
Running a full blockchain node gives you the pure bitcoin experience: independent verification of all transactions without the need to rely on, or trust, any other systems. It's easy to tell if you're running a full node because it requires 20+ gigabytes of persistent storage (disk space) to store the full blockchain. If you need a lot of disk and it takes two to three days to sync to the network, you are running a full node. That is the price of complete independence and freedom from central authority.
|
||||
|
||||
There are a few alternative implementations of full blockchain bitcoin clients, built using different programming languages and software architectures. However, the most common implementation is the reference client((("Bitcoin Core client","and full nodes"))) Bitcoin Core, also known as the Satoshi client. More than 90% of the nodes on the bitcoin network run various versions of Bitcoin Core. It is identified as "Satoshi" in the sub-version string sent in the +version+ message and shown by the command +getpeerinfo+ as we saw earlier; for example, +/Satoshi:0.8.6/+.
|
||||
|
||||
=== Exchanging "Inventory"
|
||||
|
||||
((("blockchains","creating on nodes")))((("blockchains","on new nodes")))((("blocks","on new nodes")))((("full nodes","creating full blockchains on")))The first thing a full node will do once it connects to peers is try to construct a complete blockchain. If it is a brand-new node and has no blockchain at all, it only knows one block, the genesis block, which is statically embedded in the client software. Starting with block #0 (the genesis block), the new node will have to download hundreds of thousands of blocks to synchronize with the network and re-establish the full blockchain.
|
||||
|
||||
((("syncing the blockchain")))The process of syncing the blockchain starts with the +version+ message, because that contains +BestHeight+, a node's current blockchain height (number of blocks). A node will see the +version+ messages from its peers, know how many blocks they each have, and be able to compare to how many blocks it has in its own blockchain. Peered nodes will exchange a +getblocks+ message that contains the hash (fingerprint) of the top block on their local blockchain. One of the peers will be able to identify the received hash as belonging to a block that is not at the top, but rather belongs to an older block, thus deducing that its own local blockchain is longer than its peer's.
|
||||
|
||||
The peer that has the longer blockchain has more blocks than the other node and can identify which blocks the other node needs in order to "catch up." It will identify the first 500 blocks to share and transmit their hashes using an((("inv messages"))) +inv+ (inventory) message. The node missing these blocks will then retrieve them, by issuing a series of +getdata+ messages requesting the full block data and identifying the requested blocks using the hashes from the +inv+ message.
|
||||
|
||||
Let's assume, for example, that a node only has the genesis block. It will then receive an +inv+ message from its peers containing the hashes of the next 500 blocks in the chain. It will start requesting blocks from all of its connected peers, spreading the load and ensuring that it doesn't overwhelm any peer with requests. The node keeps track of how many blocks are "in transit" per peer connection, meaning blocks that it has requested but not received, checking that it does not exceed a limit((("MAX_BLOCKS_IN_TRANSIT_PER_PEER constant"))) (+MAX_BLOCKS_IN_TRANSIT_PER_PEER+). This way, if it needs a lot of blocks, it will only request new ones as previous requests are fulfilled, allowing the peers to control the pace of updates and not overwhelming the network. As each block is received, it is added to the blockchain, as we will see in <<blockchain>>. As the local blockchain is gradually built up, more blocks are requested and received, and the process continues until the node catches up to the rest of the network.
|
||||
|
||||
This process of comparing the local blockchain with the peers and retrieving any missing blocks happens any time a node goes offline for any period of time. Whether a node has been offline for a few minutes and is missing a few blocks, or a month and is missing a few thousand blocks, it starts by sending +getblocks+, gets an +inv+ response, and starts downloading the missing blocks. <<inventory_synchronization>> shows the inventory and block propagation protocol.
|
||||
|
||||
|
||||
[[spv_nodes]]
|
||||
=== Simplified Payment Verification (SPV) Nodes
|
||||
|
||||
((("nodes","SPV", id="ix_ch06-asciidoc5", range="startofrange")))((("nodes","lightweight", id="ix_ch06-asciidoc5a", range="startofrange")))((("simplified payment verification (SPV) nodes", id="ix_ch06-asciidoc6", range="startofrange")))Not all nodes have the ability to store the full blockchain. Many bitcoin clients are designed to run on space- and power-constrained devices, such as smartphones, tablets, or embedded systems. For such devices, a _simplified payment verification_ (SPV) method is used to allow them to operate without storing the full blockchain. These types of clients are called SPV clients or lightweight clients. As bitcoin adoption surges, the SPV node is becoming the most common form of bitcoin node, especially for bitcoin wallets.
|
||||
|
||||
((("blockchains","on SPV nodes")))SPV nodes download only the block headers and do not download the transactions included in each block. The resulting chain of blocks, without transactions, is 1,000 times smaller than the full blockchain. SPV nodes cannot construct a full picture of all the UTXOs that are available for spending because they do not know about all the transactions on the network. SPV nodes verify transactions using a slightly different methodology that relies on peers to provide partial views of relevant parts of the blockchain on demand.
|
||||
|
||||
[[inventory_synchronization]]
|
||||
.Node synchronizing the blockchain by retrieving blocks from a peer
|
||||
image::images/msbt_0606.png["InventorySynchronization"]
|
||||
|
||||
As an analogy, a full node is like a tourist in a strange city, equipped with a detailed map of every street and every address. By comparison, an SPV node is like a tourist in a strange city asking random strangers for turn-by-turn directions while knowing only one main avenue. Although both tourists can verify the existence of a street by visiting it, the tourist without a map doesn't know what lies down any of the side streets and doesn't know what other streets exist. Positioned in front of 23 Church Street, the tourist without a map cannot know if there are a dozen other "23 Church Street" addresses in the city and whether this is the right one. The mapless tourist's best chance is to ask enough people and hope some of them are not trying to mug him.
|
||||
|
||||
Simplified payment verification verifies transactions by reference to their _depth_ in the blockchain instead of their _height_. Whereas a full blockchain node will construct a fully verified chain of thousands of blocks and transactions reaching down the blockchain (back in time) all the way to the genesis block, an SPV node will verify the chain of all blocks (but not all transactions) and link that chain to the transaction of interest.
|
||||
|
||||
For example, when examining a transaction in block 300,000, a full node links all 300,000 blocks down to the genesis block and builds a full database of UTXO, establishing the validity of the transaction by confirming that the UTXO remains unspent. An SPV node cannot validate whether the UTXO is unspent. Instead, the SPV node will establish a link between the transaction and the block that contains it, using a((("merkle trees","SPV and"))) _merkle path_ (see <<merkle_trees>>). Then, the SPV node waits until it sees the six blocks 300,001 through 300,006 piled on top of the block containing the transaction and verifies it by establishing its depth under blocks 300,006 to 300,001. The fact that other nodes on the network accepted block 300,000 and then did the necessary work to produce six more blocks on top of it is proof, by proxy, that the transaction was not a double-spend.
|
||||
|
||||
An SPV node cannot be persuaded that a transaction exists in a block when the transaction does not in fact exist. The SPV node establishes the existence of a transaction in a block by requesting a merkle path proof and by validating the proof of work in the chain of blocks. However, a transaction's existence can be "hidden" from an SPV node. An SPV node can definitely prove that a transaction exists but cannot verify that a transaction, such as a double-spend of the same UTXO, doesn't exist because it doesn't have a record of all transactions. This vulnerability can be used in a denial-of-service attack or for a double-spending attack against SPV nodes. To defend against this, an SPV node needs to connect randomly to several nodes, to increase the probability that it is in contact with at least one honest node. This need to randomly connect means that SPV nodes also are vulnerable to network partitioning attacks or Sybil attacks, where they are connected to fake nodes or fake networks and do not have access to honest nodes or the real bitcoin network.
|
||||
|
||||
For most practical purposes, well-connected SPV nodes are secure enough, striking the right balance between resource needs, practicality, and security. For infallible security, however, nothing beats running a full blockchain node.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
((("simplified payment verification (SPV) nodes","verification")))A full blockchain node verifies a transaction by checking the entire chain of thousands of blocks below it in order to guarantee that the UTXO is not spent, whereas an SPV node checks how deep the block is buried by a handful of blocks above it.
|
||||
====
|
||||
|
||||
((("block headers","getting on SPV nodes")))To get the block headers, SPV nodes use a((("getheaders message"))) +getheaders+ message instead of +getblocks+. The responding peer will send up to 2,000 block headers using a single +headers+ message. The process is otherwise the same as that used by a full node to retrieve full blocks. SPV nodes also set a filter on the connection to peers, to filter the stream of future blocks and transactions sent by the peers. Any transactions of interest are retrieved using a +getdata+ request. The peer generates a((("tx messages"))) +tx+ message containing the transactions, in response. <<spv_synchronization>> shows the synchronization of block headers.
|
||||
|
||||
[[spv_synchronization]]
|
||||
.SPV node synchronizing the block headers
|
||||
image::images/msbt_0607.png["SPVSynchronization"]
|
||||
|
||||
Because SPV nodes need to retrieve specific transactions in order to selectively verify them, they also create a privacy risk. Unlike full blockchain nodes, which collect all transactions within each block, the SPV node's requests for specific data can inadvertently reveal the addresses in their wallet. For example, a third party monitoring a network could keep track of all the transactions requested by a wallet on an SPV node and use those to associate bitcoin addresses with the user of that wallet, destroying the user's privacy.
|
||||
|
||||
Shortly after the introduction of SPV/lightweight nodes, the bitcoin developers added a feature called _bloom filters_ to address the privacy risks of SPV nodes. Bloom filters allow SPV nodes to receive a subset of the transactions without revealing precisely which addresses they are interested in, through a filtering mechanism that uses probabilities rather than fixed patterns.(((range="endofrange", startref="ix_ch06-asciidoc6")))(((range="endofrange", startref="ix_ch06-asciidoc5a")))(((range="endofrange", startref="ix_ch06-asciidoc5")))
|
||||
|
||||
=== Bloom Filters
|
||||
|
||||
((("bitcoin network","bloom filters and", id="ix_ch06-asciidoc7", range="startofrange")))((("bloom filters", id="ix_ch06-asciidoc8", range="startofrange")))((("Simplified Payment Verification (SPV) nodes","bloom filters and", id="ix_ch06-asciidoc9", range="startofrange")))A bloom filter is a probabilistic search filter, a way to describe a desired pattern without specifying it exactly. Bloom filters offer an efficient way to express a search pattern while protecting privacy. They are used by SPV nodes to ask their peers for transactions matching a specific pattern, without revealing exactly which addresses they are searching for.
|
||||
|
||||
In our previous analogy, a tourist without a map is asking for directions to a specific address, "23 Church St." If she asks strangers for directions to this street, she inadvertently reveals her destination. A bloom filter is like asking, "Are there any streets in this neighborhood whose name ends in R-C-H?" A question like that reveals slightly less about the desired destination than asking for "23 Church St." Using this technique, a tourist could specify the desired address in more detail as "ending in U-R-C-H" or less detail as "ending in H." By varying the precision of the search, the tourist reveals more or less information, at the expense of getting more or less specific results. If she asks a less specific pattern, she gets a lot more possible addresses and better privacy, but many of the results are irrelevant. If she asks for a very specific pattern, she gets fewer results but loses privacy.
|
||||
|
||||
Bloom filters serve this function by allowing an SPV node to specify a search pattern for transactions that can be tuned toward precision or privacy. A more specific bloom filter will produce accurate results, but at the expense of revealing what addresses are used in the user's wallet. A less specific bloom filter will produce more data about more transactions, many irrelevant to the node, but will allow the node to maintain better privacy.
|
||||
|
||||
An SPV node will initialize a bloom filter as "empty" and in that state the bloom filter will not match any patterns. The SPV node will then make a list of all the addresses in its wallet and create a search pattern matching the transaction output that corresponds to each address. Usually, the search pattern is a((("pay-to-public-key-hash (P2PKH)","bloom filters and"))) pay-to-public-key-hash script that is the expected locking script that will be present in any transaction paying to the public-key-hash (address). If the SPV node is tracking the balance of a((("pay-to-script-hash (P2SH)","bloom filters and"))) P2SH address, the search pattern will be a pay-to-script-hash script, instead. The SPV node then adds each of the search patterns to the bloom filter, so that the bloom filter can recognize the search pattern if it is present in a transaction. Finally, the bloom filter is sent to the peer and the peer uses it to match transactions for transmission to the SPV node.
|
||||
|
||||
Bloom filters are implemented as a variable-size array of N binary digits (a bit field) and a variable number of M hash functions. The hash functions are designed to always produce an output that is between 1 and N, corresponding to the array of binary digits. The hash functions are generated deterministically, so that any node implementing a bloom filter will always use the same hash functions and get the same results for a specific input. By choosing different length (N) bloom filters and a different number (M) of hash functions, the bloom filter can be tuned, varying the level of accuracy and therefore privacy.
|
||||
|
||||
In <<bloom1>>, we use a very small array of 16 bits and a set of three hash functions to demonstrate how bloom filters work.
|
||||
|
||||
[[bloom1]]
|
||||
.An example of a simplistic bloom filter, with a 16-bit field and three hash functions
|
||||
image::images/msbt_0608.png["Bloom1"]
|
||||
|
||||
The bloom filter is initialized so that the array of bits is all zeros. To add a pattern to the bloom filter, the pattern is hashed by each hash function in turn. Applying the first hash function to the input results in a number between 1 and N. The corresponding bit in the array (indexed from 1 to N) is found and set to +1+, thereby recording the output of the hash function. Then, the next hash function is used to set another bit and so on. Once all M hash functions have been applied, the search pattern will be "recorded" in the bloom filter as M bits that have been changed from +0+ to +1+.
|
||||
|
||||
<<bloom2>> is an example of adding a pattern "A" to the simple bloom filter shown in <<bloom1>>.
|
||||
|
||||
|
||||
Adding a second pattern is as simple as repeating this process. The pattern is hashed by each hash function in turn and the result is recorded by setting the bits to +1+. Note that as a bloom filter is filled with more patterns, a hash function result might coincide with a bit that is already set to +1+, in which case the bit is not changed. In essence, as more patterns record on overlapping bits, the bloom filter starts to become saturated with more bits set to +1+ and the accuracy of the filter decreases. This is why the filter is a probabilistic data structure—it gets less accurate as more patterns are added. The accuracy depends on the number of patterns added versus the size of the bit array (N) and number of hash functions (M). A larger bit array and more hash functions can record more patterns with higher accuracy. A smaller bit array or fewer hash functions will record fewer patterns and produce less accuracy.
|
||||
|
||||
[[bloom2]]
|
||||
.Adding a pattern "A" to our simple bloom filter
|
||||
image::images/msbt_0609.png["Bloom2"]
|
||||
|
||||
<<bloom3>> is an example of adding a second pattern "B" to the simple bloom filter.
|
||||
|
||||
[[bloom3]]
|
||||
.Adding a second pattern "B" to our simple bloom filter
|
||||
image::images/msbt_0610.png["Bloom3"]
|
||||
|
||||
To test if a pattern is part of a bloom filter, the pattern is hashed by each hash function and the resulting bit pattern is tested against the bit array. If all the bits indexed by the hash functions are set to +1+, then the pattern is _probably_ recorded in the bloom filter. Because the bits may be set because of overlap from multiple patterns, the answer is not certain, but is rather probabilistic. In simple terms, a bloom filter positive match is a "Maybe, Yes."
|
||||
|
||||
<<bloom4>> is an example of testing the existence of pattern "X" in the simple bloom filter. The corresponding bits are set to +1+, so the pattern is probably a match.
|
||||
|
||||
[[bloom4]]
|
||||
.Testing the existence of pattern "X" in the bloom filter. The result is probabilistic positive match, meaning "Maybe."
|
||||
image::images/msbt_0611.png["Bloom4"]
|
||||
|
||||
On the contrary, if a pattern is tested against the bloom filter and any one of the bits is set to +0+, this proves that the pattern was not recorded in the bloom filter. A negative result is not a probability, it is a certainty. In simple terms, a negative match on a bloom filter is a "Definitely Not!"
|
||||
|
||||
<<bloom5>> is an example of testing the existence of pattern "Y" in the simple bloom filter. One of the corresponding bits is set to +0+, so the pattern is definitely not a match.
|
||||
|
||||
[[bloom5]]
|
||||
.Testing the existence of pattern "Y" in the bloom filter. The result is a definitive negative match, meaning "Definitely Not!"
|
||||
image::images/msbt_0612.png[]
|
||||
|
||||
Bitcoin's implementation of bloom filters is described in Bitcoin Improvement Proposal 37 (BIP0037). See <<appdxbitcoinimpproposals>> or visit http://bit.ly/1x6qCiO[GitHub].
|
||||
|
||||
=== Bloom Filters and Inventory Updates
|
||||
|
||||
((("inventory updates, bloom filters and")))Bloom filters are used to filter the transactions (and blocks containing them) that an SPV node receives from its peers. SPV nodes will create a filter that matches only the addresses held in the SPV node's wallet. The SPV node will then send a((("filterload message"))) +filterload+ message to the peer, containing the bloom filter to use on the connection. After a filter is established, the peer will then test each transaction's outputs against the bloom filter. Only transactions that match the filter are sent to the node.
|
||||
|
||||
In response to a +getdata+ message from the node, peers will send a +merkleblock+ message that contains only block headers for blocks matching the filter and a merkle path (see <<merkle_trees>>) for each matching transaction. The peer will then also send +tx+ messages containing the transactions matched by the filter.
|
||||
|
||||
The node setting the bloom filter can interactively add patterns to the filter by sending a((("filteradd message"))) +filteradd+ message. To clear the bloom filter, the node can send a((("filterclear message"))) +filterclear+ message. Because it is not possible to remove a pattern from a bloom filter, a node has to clear and resend a new bloom filter if a pattern is no longer desired.(((range="endofrange", startref="ix_ch06-asciidoc9")))(((range="endofrange", startref="ix_ch06-asciidoc8")))(((range="endofrange", startref="ix_ch06-asciidoc7")))
|
||||
|
||||
[[transaction_pools]]
|
||||
=== Transaction Pools
|
||||
|
||||
((("bitcoin network","transaction pools")))((("transaction pools")))((("memory pool")))((("mempool")))((("transactions","unconfirmed, pools of")))((("unconfirmed transactions")))Almost every node on the bitcoin network maintains a temporary list of unconfirmed transactions called the _memory pool_, _mempool_, or _transaction pool_. Nodes use this pool to keep track of transactions that are known to the network but are not yet included in the blockchain. For example, a node that holds a user's wallet will use the transaction pool to track incoming payments to the user's wallet that have been received on the network but are not yet confirmed.
|
||||
|
||||
As transactions are received and verified, they are added to the transaction pool and relayed to the neighboring nodes to propagate on the network.
|
||||
|
||||
((("orphan transaction pool")))Some node implementations also maintain a separate pool of orphaned transactions. If a transaction's inputs refer to a transaction that is not yet known, such as a missing parent, the orphan transaction will be stored temporarily in the orphan pool until the parent transaction arrives.
|
||||
|
||||
When a transaction is added to the transaction pool, the orphan pool is checked for any orphans that reference this transaction's outputs (its children). Any matching orphans are then validated. If valid, they are removed from the orphan pool and added to the transaction pool, completing the chain that started with the parent transaction. In light of the newly added transaction, which is no longer an orphan, the process is repeated recursively looking for any further descendants, until no more descendants are found. Through this process, the arrival of a parent transaction triggers a cascade reconstruction of an entire chain of interdependent transactions by re-uniting the orphans with their parents all the way down the chain.
|
||||
|
||||
((("orphan transaction pool","storage")))((("transaction pools","storage")))Both the transaction pool and orphan pool (where implemented) are stored in local memory and are not saved on persistent storage; rather, they are dynamically populated from incoming network messages. When a node starts, both pools are empty and are gradually populated with new transactions received on the network.
|
||||
|
||||
Some implementations of the bitcoin client also maintain a UTXO database or UTXO pool, which is the set of all unspent outputs on the blockchain. Although the name "UTXO pool" sounds similar to the transaction pool, it represents a different set of data. Unlike the transaction and orphan pools, the UTXO pool is not initialized empty but instead contains millions of entries of unspent transaction outputs, including some dating back to 2009. The UTXO pool may be housed in local memory or as an indexed database table on persistent storage.
|
||||
|
||||
Whereas the transaction and orphan pools represent a single node's local perspective and might vary significantly from node to node depending upon when the node was started or restarted, the UTXO pool represents the emergent consensus of the network and therefore will vary little between nodes. Furthermore, the transaction and orphan pools only contain unconfirmed transactions, while the UTXO pool only contains confirmed outputs.
|
||||
|
||||
=== Alert Messages
|
||||
|
||||
((("alert messages")))((("bitcoin network","alert messages")))Alert messages are a seldom used function, but are nevertheless implemented in most nodes. Alert messages are bitcoin's "emergency broadcast system," a means by which the core bitcoin developers can send an emergency text message to all bitcoin nodes. This feature is implemented to allow the core developer team to notify all bitcoin users of a serious problem in the bitcoin network, such as a critical bug that requires user action. The alert system has only been used a handful of times, most notably in early 2013 when a critical database bug caused a multiblock fork to occur in the bitcoin blockchain.
|
||||
|
||||
Alert messages are propagated by the +alert+ message. The alert message contains several fields, including:
|
||||
|
||||
ID::
|
||||
An alert identified so that duplicate alerts can be detected
|
||||
|
||||
Expiration::
|
||||
A time after which the alert expires
|
||||
|
||||
RelayUntil::
|
||||
A time after which the alert should not be relayed
|
||||
|
||||
MinVer, MaxVer::
|
||||
The range of bitcoin protocol versions that this alert applies to
|
||||
|
||||
subVer::
|
||||
The client software version that this alert applies to
|
||||
|
||||
Priority::
|
||||
An alert priority level, currently unused
|
||||
|
||||
Alerts are cryptographically signed by a public key. The corresponding private key is held by a few select members of the core development team. The digital signature ensures that fake alerts will not be propagated on the network.
|
||||
|
||||
Each node receiving this alert message will verify it, check for expiration, and propagate it to all its peers, thus ensuring rapid propagation across the entire network. In addition to propagating the alert, the nodes might implement a user interface function to present the alert to the user.
|
||||
|
||||
((("Bitcoin Core client","alerts, configuring")))In the Bitcoin Core client, the alert is configured with the command-line option +-alertnotify+, which specifies a command to run when an alert is received. The alert message is passed as a parameter to the +alertnotify+ command. Most commonly, the +alertnotify+ command is set to generate an email message to the administrator of the node, containing the alert message. The alert is also displayed as a pop-up dialog in the graphical user interface (bitcoin-Qt) if it is running.
|
||||
|
||||
Other implementations of the bitcoin protocol might handle the alert in different ways. ((("mining","hardware, alerts and")))Many hardware-embedded bitcoin mining systems do not implement the alert message function because they have no user interface. It is strongly recommended that miners running such mining systems subscribe to alerts via a mining pool operator or by running a lightweight node just for alert purposes.(((range="endofrange", startref="ix_ch06-asciidoc0")))
|
||||
|
||||
|
||||
|
@ -0,0 +1,79 @@
|
||||
[[ch10]]
|
||||
== Bitcoin Security
|
||||
|
||||
((("security", id="ix_ch10-asciidoc0", range="startofrange")))Securing bitcoin is challenging because bitcoin is not an abstract reference to value, like a balance in a bank account. Bitcoin is very much like digital cash or gold. You've probably heard the expression, "Possession is nine-tenths of the law." Well, in bitcoin, possession is ten-tenths of the law. Possession of the keys to unlock the bitcoin is equivalent to possession of cash or a chunk of precious metal. You can lose it, misplace it, have it stolen, or accidentally give the wrong amount to someone. In every one of these cases, users have no recourse, just as if they dropped cash on a public sidewalk.
|
||||
|
||||
However, bitcoin has capabilities that cash, gold, and bank accounts do not. A bitcoin wallet, containing your keys, can be backed up like any file. It can be stored in multiple copies, even printed on paper for hard-copy backup. You can't "back up" cash, gold, or bank accounts. Bitcoin is different enough from anything that has come before that we need to think about bitcoin security in a novel way too.
|
||||
|
||||
=== Security Principles
|
||||
|
||||
((("security","principles of")))The core principle in bitcoin is decentralization and it has important implications for security. A centralized model, such as a traditional bank or payment network, depends on access control and vetting to keep bad actors out of the system. By comparison, a decentralized system like bitcoin pushes the responsibility and control to the users. Because security of the network is based on proof of work, not access control, the network can be open and no encryption is required for bitcoin traffic.
|
||||
|
||||
On a((("credit card payment system")))((("payment networks, traditional"))) traditional payment network, such as a credit card system, the payment is open-ended because it contains the user's private identifier (the credit card number). After the initial charge, anyone with access to the identifier can "pull" funds and charge the owner again and again. Thus, the payment network has to be secured end-to-end with encryption and must ensure that no((("eavesdroppers"))) eavesdroppers or intermediaries can compromise the payment traffic, in transit or when it is stored (at rest). If a bad actor gains access to the system, he can compromise current transactions _and_ payment tokens that can be used to create new transactions. Worse, when customer data is compromised, the customers are exposed to identity theft and must take action to prevent fraudulent use of the compromised accounts.
|
||||
|
||||
Bitcoin is dramatically different. A bitcoin transaction authorizes only a specific value to a specific recipient and cannot be forged or modified. It does not reveal any private information, such as the identities of the parties, and cannot be used to authorize additional payments. Therefore, a bitcoin payment network does not need to be encrypted or protected from eavesdropping. In fact, you can broadcast bitcoin transactions over an open public channel, such as unsecured WiFi or Bluetooth, with no loss of security.
|
||||
|
||||
Bitcoin's decentralized security model puts a lot of power in the hands of the users. With that power comes responsibility for maintaining the secrecy of the keys. For most users that is not easy to do, especially on general-purpose computing devices such as Internet-connected smartphones or laptops. Although bitcoin's decentralized model prevents the type of mass compromise seen with credit cards, many users are not able to adequately secure their keys and get hacked, one by one.
|
||||
|
||||
|
||||
==== Developing Bitcoin Systems Securely
|
||||
|
||||
((("bitcoin","system security")))((("security","centralized controls and")))The most important principle for bitcoin developers is decentralization. Most developers will be familiar with centralized security models and might be tempted to apply these models to their bitcoin applications, with disastrous results.
|
||||
|
||||
Bitcoin's security relies on decentralized control over keys and on independent transaction validation by miners. If you want to leverage Bitcoin's security, you need to ensure that you remain within the Bitcoin security model. In simple terms: don't take control of keys away from users and don't take transactions off the blockchain.
|
||||
|
||||
For example, many early bitcoin exchanges concentrated all user funds in a single "hot" wallet with keys stored on a single server. Such a design removes control from users and centralizes control over keys in a single system. Many such systems have been hacked, with disastrous consequences for their customers.
|
||||
|
||||
((("transactions","taking off blockchain")))Another common mistake is to take transactions "off blockchain" in a misguided effort to reduce transaction fees or accelerate transaction processing. An "off blockchain" system will record transactions on an internal, centralized ledger and only occasionally synchronize them to the bitcoin blockchain. This practice, again, substitutes decentralized bitcoin security with a proprietary and centralized approach. When transactions are off blockchain, improperly secured centralized ledgers can be falsified, diverting funds and depleting reserves, unnoticed.
|
||||
|
||||
Unless you are prepared to invest heavily in operational security, multiple layers of access control, and audits (as the traditional banks do) you should think very carefully before taking funds outside of Bitcoin's decentralized security context. Even if you have the funds and discipline to implement a robust security model, such a design merely replicates the fragile model of traditional financial networks, plagued by identity theft, corruption, and embezzlement. To take advantage of Bitcoin's unique decentralized security model, you have to avoid the temptation of centralized architectures that might feel familiar but ultimately subvert Bitcoin's security.
|
||||
|
||||
==== The Root of Trust
|
||||
|
||||
((("root of trust")))((("security","root of trust")))Traditional security architecture is based upon a concept called the _root of trust_, which is a trusted core used as the foundation for the security of the overall system or application. Security architecture is developed around the root of trust as a series of concentric circles, like layers in an onion, extending trust outward from the center. Each layer builds upon the more-trusted inner layer using access controls, digital signatures, encryption, and other security primitives. As software systems become more complex, they are more likely to contain bugs, which make them vulnerable to security compromise. As a result, the more complex a software system becomes, the harder it is to secure. The root of trust concept ensures that most of the trust is placed within the least complex part of the system, and therefore least vulnerable, parts of the system, while more complex software is layered around it. This security architecture is repeated at different scales, first establishing a root of trust within the hardware of a single system, then extending that root of trust through the operating system to higher-level system services, and finally across many servers layered in concentric circles of diminishing trust.
|
||||
|
||||
Bitcoin security architecture is different. In Bitcoin, the consensus system creates a trusted public ledger that is completely decentralized. A correctly validated blockchain uses the genesis block as the root of trust, building a chain of trust up to the current block. Bitcoin systems can and should use the blockchain as their root of trust. When designing a complex bitcoin application that consists of services on many different systems, you should carefully examine the security architecture in order to ascertain where trust is being placed. Ultimately, the only thing that should be explicitly trusted is a fully validated blockchain. If your application explicitly or implicitly vests trust in anything but the blockchain, that should be a source of concern because it introduces vulnerability. A good method to evaluate the security architecture of your application is to consider each individual component and evaluate a hypothetical scenario where that component is completely compromised and under the control of a malicious actor. Take each component of your application, in turn, and assess the impacts on the overall security if that component is compromised. If your application is no longer secure when components are compromised, that shows you have misplaced trust in those components. A bitcoin application without vulnerabilities should be vulnerable only to a compromise of the bitcoin consensus mechanism, meaning that its root of trust is based on the strongest part of the bitcoin security architecture.
|
||||
|
||||
The numerous examples of hacked bitcoin exchanges serve to underscore this point because their security architecture and design fails even under the most casual scrutiny. These centralized implementations had invested trust explicitly in numerous components outside the bitcoin blockchain, such as hot wallets, centralized ledger databases, vulnerable encryption keys, and similar schemes.
|
||||
|
||||
|
||||
=== User Security Best Practices
|
||||
|
||||
((("security","user", id="ix_ch10-asciidoc1", range="startofrange")))((("user security", id="ix_ch10-asciidoc2", range="startofrange")))Humans have used physical security controls for thousands of years. By comparison, our experience with digital security is less than 50 years old. ((("operating systems, bitcoin security and")))Modern general-purpose operating systems are not very secure and not particularly suited to storing digital money. Our computers are constantly exposed to external threats via always-on Internet connections. They run thousands of software components from hundreds of authors, often with unconstrained access to the user's files. A single piece of rogue software, among the many thousands installed on your computer, can compromise your keyboard and files, stealing any bitcoin stored in wallet applications. The level of computer maintenance required to keep a computer virus-free and trojan-free is beyond the skill level of all but a tiny minority of computer users.
|
||||
|
||||
Despite decades of research and advancements in information security, digital assets are still woefully vulnerable to a determined adversary. Even the most highly protected and restricted systems, in financial services companies, intelligence agencies, and defense contractors, are frequently breached. Bitcoin creates digital assets that have intrinsic value and can be stolen and diverted to new owners instantly and irrevocably. ((("hackers")))This creates a massive incentive for hackers. Until now, hackers had to convert identity information or account tokens—such as credit cards, and bank accounts—into value after compromising them. Despite the difficulty of fencing and laundering financial information, we have seen ever-escalating thefts. Bitcoin escalates this problem because it doesn't need to be fenced or laundered; it is intrinsic value within a digital asset.
|
||||
|
||||
Fortunately, bitcoin also creates the incentives to improve computer security. Whereas previously the risk of computer compromise was vague and indirect, bitcoin makes these risks clear and obvious. Holding bitcoin on a computer serves to focus the user's mind on the need for improved computer security. As a direct result of the proliferation and increased adoption of bitcoin and other digital currencies, we have seen an escalation in both hacking techniques and security solutions. In simple terms, hackers now have a very juicy target and users have a clear incentive to defend themselves.
|
||||
|
||||
Over the past three years, as a direct result of bitcoin adoption, we have seen tremendous innovation in the realm of information security in the form of hardware encryption, key storage and hardware wallets, multi-signature technology, and digital escrow. In the following sections we will examine various best practices for practical user security.
|
||||
|
||||
==== Physical Bitcoin Storage
|
||||
|
||||
((("backups","cold-storage wallets")))((("bitcoin","storage, physical")))((("cold-storage wallets")))((("paper wallets")))((("user security","physical bitcoin storage")))Because most users are far more comfortable with physical security than information security, a very effective method for protecting bitcoins is to convert them into physical form. Bitcoin keys are nothing more than long numbers. This means that they can be stored in a physical form, such as printed on paper or etched on a metal coin. Securing the keys then becomes as simple as physically securing the printed copy of the bitcoin keys. A set of bitcoin keys that is printed on paper is called a "paper wallet," and there are many free tools that can be used to create them. I personally keep the vast majority of my bitcoins (99% or more) stored on paper wallets, encrypted with BIP0038, with multiple copies locked in safes. Keeping bitcoin offline is called _cold storage_ and it is one of the most effective security techniques. A cold storage system is one where the keys are generated on an offline system (one never connected to the Internet) and stored offline either on paper or on digital media, such as a USB memory stick.
|
||||
|
||||
==== Hardware Wallets
|
||||
|
||||
((("hardware wallets")))((("user security","hardware wallets")))((("wallets","hardware")))In the long term, bitcoin security increasingly will take the form of hardware tamper-proof wallets. Unlike a smartphone or desktop computer, a bitcoin hardware wallet has just one purpose: to hold bitcoins securely. Without general-purpose software to compromise and with limited interfaces, hardware wallets can deliver an almost foolproof level of security to nonexpert users. I expect to see hardware wallets become the predominant method of bitcoin storage. For an example of such a hardware wallet, see the((("Trezor wallet"))) http://www.bitcointrezor.com/[Trezor].
|
||||
|
||||
==== Balancing Risk
|
||||
|
||||
((("risk, security")))((("user security","risk, balancing")))Although most users are rightly concerned about bitcoin theft, there is an even bigger risk. Data files get lost all the time. If they contain bitcoin, the loss is much more painful. In the effort to secure their bitcoin wallets, users must be very careful not to go too far and end up losing the bitcoin. In July of 2011, a well-known bitcoin awareness and education project lost almost 7,000 bitcoins. In their effort to prevent theft, the owners had implemented a complex series of encrypted backups. In the end they accidentally lost the encryption keys, making the backups worthless and losing a fortune. Like hiding money by burying it in the desert, if you secure your bitcoin too well you might not be able to find it again.
|
||||
|
||||
==== Diversifying Risk
|
||||
|
||||
((("user security","risk, diversifying")))Would you carry your entire net worth in cash in your wallet? Most people would consider that reckless, yet bitcoin users often keep all their bitcoin in a single wallet. Instead, users should spread the risk among multiple and diverse bitcoin wallets. Prudent users will keep only a small fraction, perhaps less than 5%, of their bitcoins in an online or mobile wallet as "pocket change." The rest should be split between a few different storage mechanisms, such as a desktop wallet and offline (cold storage).
|
||||
|
||||
==== Multi-sig and Governance
|
||||
|
||||
((("corporations, multi-sig governance and")))((("governance")))((("multi-signature addresses","security and")))((("security","governance")))((("security","multi-signature addresses and")))Whenever a company or individual stores large amounts of bitcoin, they should consider using a multi-signature bitcoin address. Multi-signature addresses secure funds by requiring more than one signature to make a payment. The signing keys should be stored in a number of different locations and under the control of different people. In a corporate environment, for example, the keys should be generated independently and held by several company executives, to ensure no single person can compromise the funds. Multi-signature addresses can also offer redundancy, where a single person holds several keys that are stored in different locations.
|
||||
|
||||
==== Survivability
|
||||
|
||||
((("bitcoin","death of owner and")))((("death of owners")))((("security","death of owner and")))((("security","survivability")))((("survivability")))One important security consideration that is often overlooked is availability, especially in the context of incapacity or death of the key holder. Bitcoin users are told to use complex passwords and keep their keys secure and private, not sharing them with anyone. Unfortunately, that practice makes it almost impossible for the user's family to recover any funds if the user is not available to unlock them. In most cases, in fact, the families of bitcoin users might be completely unaware of the existence of the bitcoin funds.
|
||||
|
||||
If you have a lot of bitcoin, you should consider sharing access details with a trusted relative or lawyer. A more complex survivability scheme can be set up with multi-signature access and estate planning through a lawyer specialized as a "digital asset executor."
|
||||
|
||||
=== Conclusion
|
||||
|
||||
Bitcoin is a completely new, unprecedented, and complex technology. Over time we will develop better security tools and practices that are easier to use by nonexperts. For now, bitcoin users can use many of the tips discussed here to enjoy a secure and trouble-free bitcoin experience.(((range="endofrange", startref="ix_ch10-asciidoc2")))(((range="endofrange", startref="ix_ch10-asciidoc1")))(((range="endofrange", startref="ix_ch10-asciidoc0")))
|
||||
|
@ -1,41 +0,0 @@
|
||||
<section data-type="chapter">
|
||||
<h1>Chapter Title</h1>
|
||||
|
||||
<section data-type="sect1">
|
||||
<h1>This Is an A-Head</h1>
|
||||
|
||||
<p>Start writing here! Replace any of this placeholder text with your opus. We've included a few examples of commonly used book elements, but you can delete them. You can add any of these elements using the buttons in the toolbar, as well.</p>
|
||||
|
||||
<blockquote data-type="epigraph">
|
||||
<p>Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice 'without pictures or conversation?'</p>
|
||||
|
||||
<p data-type="attribution">Lewis Carroll, <em>Alice in Wonderland</em></p>
|
||||
</blockquote>
|
||||
|
||||
<p>The above is a blockquote, and specifically it's an epigraph, with an attribution to the author. (Epigraphs are a subset of blockquotes.)</p>
|
||||
|
||||
<div data-type="note">
|
||||
<h1>This Is a Note</h1>
|
||||
|
||||
<p>Many people use notes to qualify a statement they made in the preceding paragraphs, or to warn their readers about pitfalls they might run into.</p>
|
||||
</div>
|
||||
|
||||
<p>Now, let's take a look at a figure with a caption:</p>
|
||||
|
||||
<figure><img alt="Drawing of tarsiers" src="images/tarsier.png" />
|
||||
<figcaption>This is a caption describing the drawing of tarsiers.</figcaption>
|
||||
</figure>
|
||||
|
||||
<section data-type="sect2">
|
||||
<h2>This Is a B-Head</h2>
|
||||
|
||||
<p>Add your text here.</p>
|
||||
|
||||
<aside data-type="sidebar">
|
||||
<h5>Sidebar Title</h5>
|
||||
|
||||
<p>Here's a sidebar. Sidebars are great for setting aside a section of text that is related to the surrounding content but that doesn't necessarily fit into the main flow.</p>
|
||||
</aside>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
@ -0,0 +1,42 @@
|
||||
#include <bitcoin/bitcoin.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Private secret key.
|
||||
bc::ec_secret secret;
|
||||
bool success = bc::decode_base16(secret,
|
||||
"038109007313a5807b2eccc082c8c3fbb988a973cacf1a7df9ce725c31b14776");
|
||||
assert(success);
|
||||
// Get public key.
|
||||
bc::ec_point public_key = bc::secret_to_public_key(secret);
|
||||
std::cout << "Public key: " << bc::encode_hex(public_key) << std::endl;
|
||||
|
||||
// Create Bitcoin address.
|
||||
// Normally you can use:
|
||||
// bc::payment_address payaddr;
|
||||
// bc::set_public_key(payaddr, public_key);
|
||||
// const std::string address = payaddr.encoded();
|
||||
|
||||
// Compute hash of public key for P2PKH address.
|
||||
const bc::short_hash hash = bc::bitcoin_short_hash(public_key);
|
||||
|
||||
bc::data_chunk unencoded_address;
|
||||
// Reserve 25 bytes
|
||||
// [ version:1 ]
|
||||
// [ hash:20 ]
|
||||
// [ checksum:4 ]
|
||||
unencoded_address.reserve(25);
|
||||
// Version byte, 0 is normal BTC address (P2PKH).
|
||||
unencoded_address.push_back(0);
|
||||
// Hash data
|
||||
bc::extend_data(unencoded_address, hash);
|
||||
// Checksum is computed by hashing data, and adding 4 bytes from hash.
|
||||
bc::append_checksum(unencoded_address);
|
||||
// Finally we must encode the result in Bitcoin's base58 encoding
|
||||
assert(unencoded_address.size() == 25);
|
||||
const std::string address = bc::encode_base58(unencoded_address);
|
||||
|
||||
std::cout << "Address: " << address << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
import ecdsa
|
||||
import os
|
||||
from ecdsa.util import string_to_number, number_to_string
|
||||
|
||||
# secp256k1, http://www.oid-info.com/get/1.3.132.0.10
|
||||
_p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL
|
||||
_r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L
|
||||
_b = 0x0000000000000000000000000000000000000000000000000000000000000007L
|
||||
_a = 0x0000000000000000000000000000000000000000000000000000000000000000L
|
||||
_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L
|
||||
_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L
|
||||
curve_secp256k1 = ecdsa.ellipticcurve.CurveFp(_p, _a, _b)
|
||||
generator_secp256k1 = ecdsa.ellipticcurve.Point(curve_secp256k1, _Gx, _Gy, _r)
|
||||
oid_secp256k1 = (1, 3, 132, 0, 10)
|
||||
SECP256k1 = ecdsa.curves.Curve("SECP256k1", curve_secp256k1, generator_secp256k1, oid_secp256k1)
|
||||
ec_order = _r
|
||||
|
||||
curve = curve_secp256k1
|
||||
generator = generator_secp256k1
|
||||
|
||||
def random_secret():
|
||||
convert_to_int = lambda array: int("".join(array).encode("hex"), 16)
|
||||
|
||||
# Collect 256 bits of random data from the OS's cryptographically secure random generator
|
||||
byte_array = os.urandom(32)
|
||||
|
||||
return convert_to_int(byte_array)
|
||||
|
||||
def get_point_pubkey(point):
|
||||
if point.y() & 1:
|
||||
key = '03' + '%064x' % point.x()
|
||||
else:
|
||||
key = '02' + '%064x' % point.x()
|
||||
return key.decode('hex')
|
||||
|
||||
def get_point_pubkey_uncompressed(point):
|
||||
key = '04' + \
|
||||
'%064x' % point.x() + \
|
||||
'%064x' % point.y()
|
||||
return key.decode('hex')
|
||||
|
||||
|
||||
# Generate a new private key.
|
||||
secret = random_secret()
|
||||
print "Secret: ", secret
|
||||
|
||||
# Get the public key point.
|
||||
point = secret * generator
|
||||
print "EC point:", point
|
||||
|
||||
print "BTC public key:", get_point_pubkey(point).encode("hex")
|
||||
|
||||
# Given the point (x, y) we can create the object using:
|
||||
point1 = ecdsa.ellipticcurve.Point(curve, point.x(), point.y(), ec_order)
|
||||
assert point1 == point
|
||||
|
@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/conformal/btcnet"
|
||||
"github.com/conformal/btcscript"
|
||||
)
|
||||
|
||||
// go run extract-from-pk-script.go
|
||||
|
||||
// This example demonstrates extracting information from a standard public key
|
||||
// script.
|
||||
|
||||
func main() {
|
||||
scriptHex := "76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac"
|
||||
|
||||
ExtractPkScriptAddrs(scriptHex)
|
||||
// Output:
|
||||
// Script Class: pubkeyhash
|
||||
// Addresses: [12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV]
|
||||
// Required Signatures: 1
|
||||
}
|
||||
|
||||
func ExtractPkScriptAddrs(scriptHex string) {
|
||||
script, err := hex.DecodeString(scriptHex)
|
||||
handle(err)
|
||||
|
||||
// Extract and print details from the script.
|
||||
scriptClass, addresses, reqSigs, err := btcscript.ExtractPkScriptAddrs(script, &btcnet.MainNetParams)
|
||||
handle(err)
|
||||
|
||||
fmt.Println("Script Class:", scriptClass)
|
||||
fmt.Println("Addresses:", addresses)
|
||||
fmt.Println("Required Signatures:", reqSigs)
|
||||
}
|
||||
|
||||
func handle(err error) {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
# get unspent outputs from blockchain API
|
||||
|
||||
import json
|
||||
import requests
|
||||
|
||||
# example address
|
||||
address = '1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX'
|
||||
|
||||
# The API URL is https://blockchain.info/unspent?active=<address>
|
||||
# It returns a JSON object with a list "unspent_outputs", containing UTXO, like this:
|
||||
#{ "unspent_outputs":[
|
||||
# {
|
||||
# "tx_hash":"ebadfaa92f1fd29e2fe296eda702c48bd11ffd52313e986e99ddad9084062167",
|
||||
# "tx_index":51919767,
|
||||
# "tx_output_n": 1,
|
||||
# "script":"76a9148c7e252f8d64b0b6e313985915110fcfefcf4a2d88ac",
|
||||
# "value": 8000000,
|
||||
# "value_hex": "7a1200",
|
||||
# "confirmations":28691
|
||||
# },
|
||||
# ...
|
||||
#]}
|
||||
|
||||
resp = requests.get('https://blockchain.info/unspent?active=%s' % address)
|
||||
utxo_set = json.loads(resp.text)["unspent_outputs"]
|
||||
|
||||
for utxo in utxo_set:
|
||||
print "%s:%d - %ld Satoshis" % (utxo['tx_hash'], utxo['tx_output_n'], utxo['value'])
|
@ -0,0 +1,18 @@
|
||||
|
||||
# example of iterating a nonce in a hashing algorithm's input
|
||||
|
||||
import hashlib
|
||||
|
||||
text = "I am Satoshi Nakamoto"
|
||||
|
||||
# iterate nonce from 0 to 19
|
||||
for nonce in xrange(20):
|
||||
|
||||
# add the nonce to the end of the text
|
||||
input = text + str(nonce)
|
||||
|
||||
# calculate the SHA-256 hash of the input (text+nonce)
|
||||
hash = hashlib.sha256(input).hexdigest()
|
||||
|
||||
# show the input and hash result
|
||||
print input, '=>', hash
|
@ -0,0 +1,49 @@
|
||||
import bitcoin
|
||||
|
||||
# Generate a random private key
|
||||
valid_private_key = False
|
||||
while not valid_private_key:
|
||||
private_key = bitcoin.random_key()
|
||||
decoded_private_key = bitcoin.decode_privkey(private_key, 'hex')
|
||||
valid_private_key = 0 < decoded_private_key < bitcoin.N
|
||||
|
||||
print "Private Key (hex) is: ", private_key
|
||||
print "Private Key (decimal) is: ", decoded_private_key
|
||||
|
||||
# Convert private key to WIF format
|
||||
wif_encoded_private_key = bitcoin.encode_privkey(decoded_private_key, 'wif')
|
||||
print "Private Key (WIF) is: ", wif_encoded_private_key
|
||||
|
||||
# Add suffix "01" to indicate a compressed private key
|
||||
compressed_private_key = private_key + '01'
|
||||
print "Private Key Compressed (hex) is: ", compressed_private_key
|
||||
|
||||
# Generate a WIF format from the compressed private key (WIF-compressed)
|
||||
wif_compressed_private_key = bitcoin.encode_privkey(
|
||||
bitcoin.decode_privkey(compressed_private_key, 'hex'), 'wif')
|
||||
print "Private Key (WIF-Compressed) is: ", wif_compressed_private_key
|
||||
|
||||
# Multiply the EC generator point G with the private key to get a public key point
|
||||
public_key = bitcoin.fast_multiply(bitcoin.G, decoded_private_key)
|
||||
print "Public Key (x,y) coordinates is:", public_key
|
||||
|
||||
# Encode as hex, prefix 04
|
||||
hex_encoded_public_key = bitcoin.encode_pubkey(public_key,'hex')
|
||||
print "Public Key (hex) is:", hex_encoded_public_key
|
||||
|
||||
# Compress public key, adjust prefix depending on whether y is even or odd
|
||||
(public_key_x, public_key_y) = public_key
|
||||
if (public_key_y % 2) == 0:
|
||||
compressed_prefix = '02'
|
||||
else:
|
||||
compressed_prefix = '03'
|
||||
hex_compressed_public_key = compressed_prefix + bitcoin.encode(public_key_x, 16)
|
||||
print "Compressed Public Key (hex) is:", hex_compressed_public_key
|
||||
|
||||
# Generate bitcoin address from public key
|
||||
print "Bitcoin Address (b58check) is:", bitcoin.pubkey_to_address(public_key)
|
||||
|
||||
# Generate compressed bitcoin address from compressed public key
|
||||
print "Compressed Bitcoin Address (b58check) is:", \
|
||||
bitcoin.pubkey_to_address(hex_compressed_public_key)
|
||||
|
@ -0,0 +1,16 @@
|
||||
# Original block reward for miners was 50 BTC
|
||||
start_block_reward = 50
|
||||
# 210000 is around every 4 years with a 10 minute block interval
|
||||
reward_interval = 210000
|
||||
|
||||
def max_money():
|
||||
# 50 BTC = 50 0000 0000 Satoshis
|
||||
current_reward = 50 * 10**8
|
||||
total = 0
|
||||
while current_reward > 0:
|
||||
total += reward_interval * current_reward
|
||||
current_reward /= 2
|
||||
return total
|
||||
|
||||
print "Total BTC to ever be created:", max_money(), "Satoshis"
|
||||
|
@ -0,0 +1,62 @@
|
||||
#include <bitcoin/bitcoin.hpp>
|
||||
|
||||
bc::hash_digest create_merkle(bc::hash_list& merkle)
|
||||
{
|
||||
// Stop if hash list is empty.
|
||||
if (merkle.empty())
|
||||
return bc::null_hash;
|
||||
else if (merkle.size() == 1)
|
||||
return merkle[0];
|
||||
|
||||
// While there is more than 1 hash in the list, keep looping...
|
||||
while (merkle.size() > 1)
|
||||
{
|
||||
// If number of hashes is odd, duplicate last hash in the list.
|
||||
if (merkle.size() % 2 != 0)
|
||||
merkle.push_back(merkle.back());
|
||||
// List size is now even.
|
||||
assert(merkle.size() % 2 == 0);
|
||||
|
||||
// New hash list.
|
||||
bc::hash_list new_merkle;
|
||||
// Loop through hashes 2 at a time.
|
||||
for (auto it = merkle.begin(); it != merkle.end(); it += 2)
|
||||
{
|
||||
// Join both current hashes together (concatenate).
|
||||
bc::data_chunk concat_data(bc::hash_size * 2);
|
||||
auto concat = bc::make_serializer(concat_data.begin());
|
||||
concat.write_hash(*it);
|
||||
concat.write_hash(*(it + 1));
|
||||
assert(concat.iterator() == concat_data.end());
|
||||
// Hash both of the hashes.
|
||||
bc::hash_digest new_root = bc::bitcoin_hash(concat_data);
|
||||
// Add this to the new list.
|
||||
new_merkle.push_back(new_root);
|
||||
}
|
||||
// This is the new list.
|
||||
merkle = new_merkle;
|
||||
|
||||
// DEBUG output -------------------------------------
|
||||
std::cout << "Current merkle hash list:" << std::endl;
|
||||
for (const auto& hash: merkle)
|
||||
std::cout << " " << bc::encode_hex(hash) << std::endl;
|
||||
std::cout << std::endl;
|
||||
// --------------------------------------------------
|
||||
}
|
||||
// Finally we end up with a single item.
|
||||
return merkle[0];
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Replace these hashes with ones from a block to reproduce the same merkle root.
|
||||
bc::hash_list tx_hashes{{
|
||||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000011"),
|
||||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000022"),
|
||||
}};
|
||||
const bc::hash_digest merkle_root = create_merkle(tx_hashes);
|
||||
std::cout << "Result: " << bc::encode_hex(merkle_root) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/conformal/btcnet"
|
||||
"github.com/conformal/btcscript"
|
||||
"github.com/conformal/btcutil"
|
||||
)
|
||||
|
||||
// This example demonstrates creating a script which pays to a bitcoin address.
|
||||
// It also prints the created script hex and uses the DisasmString function to
|
||||
// display the disassembled script.
|
||||
|
||||
func main() {
|
||||
addressStr := "12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV"
|
||||
|
||||
PayToAddrScript(addressStr)
|
||||
// Output:
|
||||
// Script Hex: 76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac
|
||||
// Script Disassembly: OP_DUP OP_HASH160 128004ff2fcaf13b2b91eb654b1dc2b674f7ec61 OP_EQUALVERIFY OP_CHECKSIG
|
||||
}
|
||||
|
||||
func PayToAddrScript(addressStr string) {
|
||||
// Parse the address to send the coins to into a btcutil.Address
|
||||
// which is useful to ensure the accuracy of the address and determine
|
||||
// the address type. It is also required for the upcoming call to
|
||||
// PayToAddrScript.
|
||||
address, err := btcutil.DecodeAddress(addressStr, &btcnet.MainNetParams)
|
||||
handle(err)
|
||||
|
||||
// Create a public key script that pays to the address.
|
||||
script, err := btcscript.PayToAddrScript(address)
|
||||
handle(err)
|
||||
fmt.Printf("Script Hex: %x\n", script)
|
||||
|
||||
disasm, err := btcscript.DisasmString(script)
|
||||
handle(err)
|
||||
fmt.Println("Script Disassembly:", disasm)
|
||||
}
|
||||
|
||||
func handle(err error) {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# example of proof-of-work algorithm
|
||||
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
max_nonce = 2 ** 32 # 4 billion
|
||||
|
||||
def proof_of_work(header, difficulty_bits):
|
||||
|
||||
# calculate the difficulty target
|
||||
target = 2 ** (256-difficulty_bits)
|
||||
|
||||
for nonce in xrange(max_nonce):
|
||||
hash_result = hashlib.sha256(str(header)+str(nonce)).hexdigest()
|
||||
|
||||
# check if this is a valid result, below the target
|
||||
if long(hash_result, 16) < target:
|
||||
print "Success with nonce %d" % nonce
|
||||
print "Hash is %s" % hash_result
|
||||
return (hash_result,nonce)
|
||||
|
||||
print "Failed after %d (max_nonce) tries" % nonce
|
||||
return nonce
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
nonce = 0
|
||||
hash_result = ''
|
||||
|
||||
# difficulty from 0 to 31 bits
|
||||
for difficulty_bits in xrange(32):
|
||||
|
||||
difficulty = 2 ** difficulty_bits
|
||||
print "Difficulty: %ld (%d bits)" % (difficulty, difficulty_bits)
|
||||
|
||||
print "Starting search..."
|
||||
|
||||
# checkpoint the current time
|
||||
start_time = time.time()
|
||||
|
||||
# make a new block which includes the hash from the previous block
|
||||
# we fake a block of transactions - just a string
|
||||
new_block = 'test block with transactions' + hash_result
|
||||
|
||||
# find a valid nonce for the new block
|
||||
(hash_result, nonce) = proof_of_work(new_block, difficulty_bits)
|
||||
|
||||
# checkpoint how long it took to find a result
|
||||
end_time = time.time()
|
||||
|
||||
elapsed_time = end_time - start_time
|
||||
print "Elapsed Time: %.4f seconds" % elapsed_time
|
||||
|
||||
if elapsed_time > 0:
|
||||
|
||||
# estimate the hashes per second
|
||||
hash_power = float(long(nonce)/elapsed_time)
|
||||
print "Hashing Power: %ld hashes per second" % hash_power
|
||||
|
||||
|
||||
|
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from pycoin.key import Key
|
||||
|
||||
from pycoin.key.validate import is_address_valid, is_wif_valid
|
||||
from pycoin.services import spendables_for_address
|
||||
from pycoin.tx.tx_utils import create_signed_tx
|
||||
|
||||
def get_address(which):
|
||||
while 1:
|
||||
print("enter the %s address=> " % which, end='')
|
||||
address = input()
|
||||
is_valid = is_address_valid(address)
|
||||
if is_valid:
|
||||
return address
|
||||
print("invalid address, please try again")
|
||||
|
||||
src_address = get_address("source")
|
||||
spendables = spendables_for_address(src_address)
|
||||
print(spendables)
|
||||
|
||||
while 1:
|
||||
print("enter the WIF for %s=> " % src_address, end='')
|
||||
wif = input()
|
||||
is_valid = is_wif_valid(wif)
|
||||
if is_valid:
|
||||
break
|
||||
print("invalid wif, please try again")
|
||||
|
||||
key = Key.from_text(wif)
|
||||
if src_address not in (key.address(use_uncompressed=False), key.address(use_uncompressed=True)):
|
||||
print("** WIF doesn't correspond to %s" % src_address)
|
||||
print("The secret exponent is %d" % key.secret_exponent())
|
||||
|
||||
dst_address = get_address("destination")
|
||||
|
||||
tx = create_signed_tx(spendables, payables=[dst_address], wifs=[wif])
|
||||
|
||||
print("here is the signed output transaction")
|
||||
print(tx.as_hex())
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
Display the genesis block message by Satoshi.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <bitcoin/bitcoin.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Create genesis block.
|
||||
bc::block_type block = bc::genesis_block();
|
||||
// Genesis block contains a single coinbase transaction.
|
||||
assert(block.transactions.size() == 1);
|
||||
// Get first transaction in block (coinbase).
|
||||
const bc::transaction_type& coinbase_tx = block.transactions[0];
|
||||
// Coinbase tx has a single input.
|
||||
assert(coinbase_tx.inputs.size() == 1);
|
||||
const bc::transaction_input_type& coinbase_input = coinbase_tx.inputs[0];
|
||||
// Convert the input script to its raw format.
|
||||
const bc::data_chunk& raw_message = save_script(coinbase_input.script);
|
||||
// Convert this to an std::string.
|
||||
std::string message;
|
||||
message.resize(raw_message.size());
|
||||
std::copy(raw_message.begin(), raw_message.end(), message.begin());
|
||||
// Display the genesis block message.
|
||||
std::cout << message << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
# Selects outputs from a UTXO list using a greedy algorithm.
|
||||
|
||||
from sys import argv
|
||||
|
||||
class OutputInfo:
|
||||
|
||||
def __init__(self, tx_hash, tx_index, value):
|
||||
self.tx_hash = tx_hash
|
||||
self.tx_index = tx_index
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s:%s with %s Satoshis>" % (self.tx_hash, self.tx_index,
|
||||
self.value)
|
||||
|
||||
# Select optimal outputs for a send from unspent outputs list.
|
||||
# Returns output list and remaining change to be sent to
|
||||
# a change address.
|
||||
def select_outputs_greedy(unspent, min_value):
|
||||
# Fail if empty.
|
||||
if not unspent:
|
||||
return None
|
||||
# Partition into 2 lists.
|
||||
lessers = [utxo for utxo in unspent if utxo.value < min_value]
|
||||
greaters = [utxo for utxo in unspent if utxo.value >= min_value]
|
||||
key_func = lambda utxo: utxo.value
|
||||
if greaters:
|
||||
# Not-empty. Find the smallest greater.
|
||||
min_greater = min(greaters)
|
||||
change = min_greater.value - min_value
|
||||
return [min_greater], change
|
||||
# Not found in greaters. Try several lessers instead.
|
||||
# Rearrange them from biggest to smallest. We want to use the least
|
||||
# amount of inputs as possible.
|
||||
lessers.sort(key=key_func, reverse=True)
|
||||
result = []
|
||||
accum = 0
|
||||
for utxo in lessers:
|
||||
result.append(utxo)
|
||||
accum += utxo.value
|
||||
if accum >= min_value:
|
||||
change = accum - min_value
|
||||
return result, "Change: %d Satoshis" % change
|
||||
# No results found.
|
||||
return None, 0
|
||||
|
||||
def main():
|
||||
unspent = [
|
||||
OutputInfo("ebadfaa92f1fd29e2fe296eda702c48bd11ffd52313e986e99ddad9084062167", 1, 8000000),
|
||||
OutputInfo("6596fd070679de96e405d52b51b8e1d644029108ec4cbfe451454486796a1ecf", 0, 16050000),
|
||||
OutputInfo("b2affea89ff82557c60d635a2a3137b8f88f12ecec85082f7d0a1f82ee203ac4", 0, 10000000),
|
||||
OutputInfo("7dbc497969c7475e45d952c4a872e213fb15d45e5cd3473c386a71a1b0c136a1", 0, 25000000),
|
||||
OutputInfo("55ea01bd7e9afd3d3ab9790199e777d62a0709cf0725e80a7350fdb22d7b8ec6", 17, 5470541),
|
||||
OutputInfo("12b6a7934c1df821945ee9ee3b3326d07ca7a65fd6416ea44ce8c3db0c078c64", 0, 10000000),
|
||||
OutputInfo("7f42eda67921ee92eae5f79bd37c68c9cb859b899ce70dba68c48338857b7818", 0, 16100000),
|
||||
]
|
||||
|
||||
if len(argv) > 1:
|
||||
target = long(argv[1])
|
||||
else:
|
||||
target = 55000000
|
||||
|
||||
print "For transaction amount %d Satoshis (%f bitcoin) use: " % (target, target/10.0**8)
|
||||
print select_outputs_greedy(unspent, target)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -0,0 +1,74 @@
|
||||
#include <bitcoin/bitcoin.hpp>
|
||||
|
||||
// The string we are searching for
|
||||
const std::string search = "1kid";
|
||||
|
||||
// Generate a random secret key. A random 32 bytes.
|
||||
bc::ec_secret random_secret(std::default_random_engine& engine);
|
||||
// Extract the Bitcoin address from an EC secret.
|
||||
std::string bitcoin_address(const bc::ec_secret& secret);
|
||||
// Case insensitive comparison with the search string.
|
||||
bool match_found(const std::string& address);
|
||||
|
||||
int main()
|
||||
{
|
||||
// random_device on Linux uses "/dev/urandom"
|
||||
// CAUTION: Depending on implementation this RNG may not be secure enough!
|
||||
// Do not use vanity keys generated by this example in production
|
||||
std::random_device random;
|
||||
std::default_random_engine engine(random());
|
||||
|
||||
// Loop continuously...
|
||||
while (true)
|
||||
{
|
||||
// Generate a random secret.
|
||||
bc::ec_secret secret = random_secret(engine);
|
||||
// Get the address.
|
||||
std::string address = bitcoin_address(secret);
|
||||
// Does it match our search string? (1kid)
|
||||
if (match_found(address))
|
||||
{
|
||||
// Success!
|
||||
std::cout << "Found vanity address! " << address << std::endl;
|
||||
std::cout << "Secret: " << bc::encode_hex(secret) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Should never reach here!
|
||||
return 0;
|
||||
}
|
||||
|
||||
bc::ec_secret random_secret(std::default_random_engine& engine)
|
||||
{
|
||||
// Create new secret...
|
||||
bc::ec_secret secret;
|
||||
// Iterate through every byte setting a random value...
|
||||
for (uint8_t& byte: secret)
|
||||
byte = engine() % std::numeric_limits<uint8_t>::max();
|
||||
// Return result.
|
||||
return secret;
|
||||
}
|
||||
|
||||
std::string bitcoin_address(const bc::ec_secret& secret)
|
||||
{
|
||||
// Convert secret to pubkey...
|
||||
bc::ec_point pubkey = bc::secret_to_public_key(secret);
|
||||
// Finally create address.
|
||||
bc::payment_address payaddr;
|
||||
bc::set_public_key(payaddr, pubkey);
|
||||
// Return encoded form.
|
||||
return payaddr.encoded();
|
||||
}
|
||||
|
||||
bool match_found(const std::string& address)
|
||||
{
|
||||
auto addr_it = address.begin();
|
||||
// Loop through the search string comparing it to the lower case
|
||||
// character of the supplied address.
|
||||
for (auto it = search.begin(); it != search.end(); ++it, ++addr_it)
|
||||
if (*it != std::tolower(*addr_it))
|
||||
return false;
|
||||
// Reached end of search string, so address matches.
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/conformal/btcrpcclient"
|
||||
"github.com/conformal/btcutil"
|
||||
"github.com/conformal/btcwire"
|
||||
)
|
||||
|
||||
// This example demonstrates a connection to the bitcoin network
|
||||
// by using websockets via btcd, use of notifications and an rpc
|
||||
// call to getblockcount.
|
||||
//
|
||||
// Install and run btcd:
|
||||
// $ go get github.com/conformal/btcd/...
|
||||
// $ btcd -u rpcuser -P rpcpass
|
||||
//
|
||||
// Install btcrpcclient:
|
||||
// $ go get github.com/conformal/btcrpcclient
|
||||
//
|
||||
// Run this example:
|
||||
// $ go run websocket-example.go
|
||||
//
|
||||
func main() {
|
||||
// Only override the handlers for notifications you care about.
|
||||
// Also note most of these handlers will only be called if you register
|
||||
// for notifications. See the documentation of the btcrpcclient
|
||||
// NotificationHandlers type for more details about each handler.
|
||||
ntfnHandlers := btcrpcclient.NotificationHandlers{
|
||||
OnBlockConnected: func(hash *btcwire.ShaHash, height int32) {
|
||||
log.Printf("Block connected: %v (%d)", hash, height)
|
||||
},
|
||||
OnBlockDisconnected: func(hash *btcwire.ShaHash, height int32) {
|
||||
log.Printf("Block disconnected: %v (%d)", hash, height)
|
||||
},
|
||||
}
|
||||
|
||||
// Connect to local btcd RPC server using websockets.
|
||||
btcdHomeDir := btcutil.AppDataDir("btcd", false)
|
||||
certs, err := ioutil.ReadFile(filepath.Join(btcdHomeDir, "rpc.cert"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
connCfg := &btcrpcclient.ConnConfig{
|
||||
Host: "localhost:8334",
|
||||
Endpoint: "ws",
|
||||
User: "rpcuser",
|
||||
Pass: "rpcpass",
|
||||
Certificates: certs,
|
||||
}
|
||||
client, err := btcrpcclient.New(connCfg, &ntfnHandlers)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Register for block connect and disconnect notifications.
|
||||
if err := client.NotifyBlocks(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("NotifyBlocks: Registration Complete")
|
||||
|
||||
// Get the current block count.
|
||||
blockCount, err := client.GetBlockCount()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("Block count: %d", blockCount)
|
||||
|
||||
// For this example gracefully shutdown the client after 10 seconds.
|
||||
// Ordinarily when to shutdown the client is highly application
|
||||
// specific.
|
||||
log.Println("Client shutdown in 10 seconds...")
|
||||
time.AfterFunc(time.Second*10, func() {
|
||||
log.Println("Client shutting down...")
|
||||
client.Shutdown()
|
||||
log.Println("Client shutdown complete.")
|
||||
})
|
||||
|
||||
// Wait until the client either shuts down gracefully (or the user
|
||||
// terminates the process with Ctrl+C).
|
||||
client.WaitForShutdown()
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
[colophon]
|
||||
= Colophon
|
||||
|
||||
The animal on the cover of _Mastering Bitcoin_ is a leafcutter ant (__Atta colombica__). The leafcutter ant, a nongeneric name, are tropical, fungus-growing ants endemic to South and Central America, Mexico, and southern United States. Aside from humans, leafcutter ants form the largest and most complex animal societies on the planet. They are named for the way they chew leaves, which serve as nutrition for their fungal garden.
|
||||
|
||||
Winged ants, both male and female, take part in a mass exit of their nest known as the _revoada_, or a nuptial flight. Females mate with multiple males to collect the 300 million sperm necessary to set up a colony. Females also store bits of the parental fungus garden mycelium in the infrabuccal pocket located in their oral cavity; they will use this to start their own fungal gardens. Once grounded, the female loses its wings and sets up an underground lair for her colony. The success rate for new queens is low: 2.5% establish a long-lived colony.
|
||||
|
||||
Once a colony has matured, ants are divided into castes based on size, with each caste performing various functions. There are usually four castes: minims, the smallest workers that tend to the young and fungus gardens; minors, slightly larger than minima, are the first line of defense for the colony and patrol the surrounding terrain and attack enemies; mediae, the general foragers that cut leaves and bring back leaf fragments to the nest; and majors, the largest worker ants that act as soldiers, defending the nest from intruders. Recent research has shown that majors also clear main foraging trails and carry bulky items back to the nest.
|
||||
|
||||
Many of the animals on O'Reilly covers are endangered; all of them are important to the world. To learn more about how you can help, go to http://animals.oreilly.com[animals.oreilly.com].
|
||||
|
||||
The cover image is from __Insects Abroad__. The cover fonts are URW Typewriter and Guardian Sans. The text font is Adobe Minion Pro; the heading font is Adobe Myriad Condensed; and the code font is Dalton Maag's Ubuntu Mono.
|
@ -1,11 +0,0 @@
|
||||
<section data-type="copyright-page">
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
<p>by Author Name</p>
|
||||
|
||||
<p>Copyright © 2015</p>
|
||||
|
||||
<p>This is a legal notice of some kind. You can add notes about the kind of license you are using for your book (e.g., Creative Commons), or anything else you feel you need to specify.</p>
|
||||
|
||||
<p>If your book has an ISBN or a book ID number, add it here as well.</p>
|
||||
</section>
|
@ -1 +0,0 @@
|
||||
<figure data-type="cover"><img alt="cover" src="images/cover.png" /></figure>
|
@ -0,0 +1,61 @@
|
||||
[preface]
|
||||
== Quick Glossary
|
||||
|
||||
This quick glossary contains many of the terms used in relation to bitcoin. These terms are used throughout the book, so bookmark this for a quick reference.
|
||||
|
||||
address::
|
||||
A bitcoin address looks like +1DSrfJdB2AnWaFNgSbv3MZC2m74996JafV+. It consists of a string of letters and numbers starting with a "1" (number one). Just like you ask others to send an email to your email address, you would ask others to send you bitcoin to your bitcoin address.((("bitcoin address")))((("address", see="bitcoin address")))((("public key", see="bitcoin address")))
|
||||
|
||||
bip::
|
||||
Bitcoin Improvement Proposals. A set of proposals that members of the bitcoin community have submitted to improve bitcoin. For example, BIP0021 is a proposal to improve the bitcoin uniform resource identifier (URI) scheme.((("bip")))
|
||||
|
||||
bitcoin::
|
||||
The name of the currency unit (the coin), the network, and the software.((("bitcoin")))
|
||||
|
||||
block::
|
||||
A grouping of transactions, marked with a timestamp, and a fingerprint of the previous block. The block header is hashed to produce a proof of work, thereby validating the transactions. Valid blocks are added to the main blockchain by network consensus.((("block")))
|
||||
|
||||
blockchain::
|
||||
A list of validated blocks, each linking to its predecessor all the way to the genesis block.((("blockchain")))
|
||||
|
||||
confirmations::
|
||||
Once a transaction is included in a block, it has one confirmation. As soon as _another_ block is mined on the same blockchain, the transaction has two confirmations, and so on. Six or more confirmations is considered sufficient proof that a transaction cannot be reversed.((("confirmations")))
|
||||
|
||||
difficulty::
|
||||
A network-wide setting that controls how much computation is required to produce a proof of work.((("difficulty")))
|
||||
|
||||
difficulty target::
|
||||
A difficulty at which all the computation in the network will find blocks approximately every 10 minutes.((("target difficulty")))
|
||||
|
||||
difficulty retargeting::
|
||||
A network-wide recalculation of the difficulty that occurs once every 2,106 blocks and considers the hashing power of the previous 2,106 blocks.((("difficulty retargeting")))
|
||||
|
||||
fees::
|
||||
The sender of a transaction often includes a fee to the network for processing the requested transaction. Most transactions require a minimum fee of 0.5 mBTC.((("fees")))
|
||||
|
||||
hash::
|
||||
A digital fingerprint of some binary input.((("hash")))
|
||||
|
||||
genesis block::
|
||||
The first block in the blockchain, used to initialize the cryptocurrency.((("genesis block")))
|
||||
|
||||
miner::
|
||||
A network node that finds valid proof of work for new blocks, by repeated hashing.((("miner")))
|
||||
|
||||
network::
|
||||
A peer-to-peer network that propagates transactions and blocks to every bitcoin node on the network.((("network")))
|
||||
|
||||
Proof-Of-Work::
|
||||
A piece of data that requires significant computation to find. In bitcoin, miners must find a numeric solution to the SHA256 algorithm that meets a network-wide target, the difficulty target. ((("proof-of-work")))
|
||||
|
||||
reward::
|
||||
An amount included in each new block as a reward by the network to the miner who found the Proof-Of-Work solution. It is currently 25BTC per block.((("reward")))
|
||||
|
||||
secret key (aka private key)::
|
||||
The secret number that unlocks bitcoins sent to the corresponding address. A secret key looks like +5J76sF8L5jTtzE96r66Sf8cka9y44wdpJjMwCxR3tzLh3ibVPxh+.((("secret key")))((("private key", see="secret key")))
|
||||
|
||||
transaction::
|
||||
In simple terms, a transfer of bitcoins from one address to another. More precisely, a transaction is a signed data structure expressing a transfer of value. Transactions are transmitted over the bitcoin network, collected by miners, and included into blocks, made permanent on the blockchain.((("transaction")))
|
||||
|
||||
wallet::
|
||||
Software that holds all your bitcoin addresses and secret keys. Use it to send, receive, and store your bitcoin.((("wallet")))
|
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 459 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 118 KiB |
After Width: | Height: | Size: 249 KiB |
After Width: | Height: | Size: 174 KiB |
After Width: | Height: | Size: 464 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 167 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 292 KiB |
After Width: | Height: | Size: 564 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 194 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 666 KiB |
After Width: | Height: | Size: 323 KiB |
After Width: | Height: | Size: 690 KiB |
After Width: | Height: | Size: 360 KiB |