Browse Source

lint: run prettier on all the files

fix/enable-imgix
Thomas Osmonson 5 years ago
parent
commit
7951653582
  1. 11
      src/common/_includes/architecture.md
  2. 60
      src/common/_includes/commandline.md
  3. 12
      src/common/_includes/contribute_code.md
  4. 9
      src/common/_includes/contribute_community.md
  5. 18
      src/common/_includes/contribute_issues.md
  6. 7
      src/common/_includes/contribute_ovr.md
  7. 36
      src/common/_includes/create_id.md
  8. 2
      src/common/_includes/required-fields.md
  9. 2
      src/common/_includes/scaffolding.md
  10. 12
      src/common/_includes/sign_in.md
  11. 4
      src/pages/404.tsx
  12. 2
      src/pages/common/android_ref.md
  13. 2
      src/pages/common/community_ref.md
  14. 6
      src/pages/common/core_ref.md
  15. 2
      src/pages/common/ios_ref.md
  16. 2
      src/pages/common/javascript_ref.md
  17. 70
      src/pages/core/atlas/howitworks.md
  18. 31
      src/pages/core/atlas/howtouse.md
  19. 67
      src/pages/core/atlas/overview.md
  20. 64
      src/pages/core/best-practices.md
  21. 13
      src/pages/core/faq_developer.md
  22. 9
      src/pages/core/install-api.md
  23. 58
      src/pages/core/naming/architecture.md
  24. 112
      src/pages/core/naming/comparison.md
  25. 23
      src/pages/core/naming/creationhowto.md
  26. 44
      src/pages/core/naming/did.md
  27. 86
      src/pages/core/naming/forks.md
  28. 155
      src/pages/core/naming/introduction.md
  29. 55
      src/pages/core/naming/manage.md
  30. 89
      src/pages/core/naming/namespaces.md
  31. 84
      src/pages/core/naming/pickname.md
  32. 62
      src/pages/core/naming/register.md
  33. 50
      src/pages/core/naming/resolving.md
  34. 15
      src/pages/core/naming/search.md
  35. 78
      src/pages/core/naming/subdomains.md
  36. 35
      src/pages/core/naming/tutorial_subdomains.md
  37. 36
      src/pages/core/smart/clarityRef.md
  38. 4
      src/pages/core/smart/cli-wallet-quickstart.md
  39. 2
      src/pages/core/smart/install-source.md
  40. 26
      src/pages/core/smart/overview.md
  41. 12
      src/pages/core/smart/principals.md
  42. 24
      src/pages/core/smart/rpc-api.md
  43. 3
      src/pages/core/smart/testnet-node.md
  44. 104
      src/pages/core/smart/tutorial-counter.md
  45. 22
      src/pages/core/smart/tutorial-test.md
  46. 40
      src/pages/core/smart/tutorial.md
  47. 280
      src/pages/core/wire-format.md
  48. 3
      src/pages/develop/cliDocs.md
  49. 92
      src/pages/develop/collection-type.md
  50. 130
      src/pages/develop/collections.md
  51. 40
      src/pages/develop/connect/get-started.md
  52. 26
      src/pages/develop/deploy-tips.md
  53. 60
      src/pages/develop/overview_auth.md
  54. 35
      src/pages/develop/profiles.md
  55. 25
      src/pages/develop/radiks-collaborate.md
  56. 15
      src/pages/develop/radiks-intro.md
  57. 79
      src/pages/develop/radiks-models.md
  58. 18
      src/pages/develop/radiks-server-extras.md
  59. 162
      src/pages/develop/radiks-setup.md
  60. 7
      src/pages/develop/storage.md
  61. 10
      src/pages/faqs/allFAQS.md
  62. 547
      src/pages/ios/tutorial.md
  63. 6
      src/pages/org/address_check.md
  64. 20
      src/pages/org/faq.md
  65. 15
      src/pages/org/overview.md
  66. 13
      src/pages/org/secureref.md
  67. 5
      src/pages/org/terms.md
  68. 11
      src/pages/org/token.md
  69. 12
      src/pages/org/tokenholders.md
  70. 33
      src/pages/org/wallet-install.md
  71. 10
      src/pages/org/wallet-intro.md
  72. 20
      src/pages/org/wallet-troubleshoot.md
  73. 76
      src/pages/org/wallet-use.md
  74. 291
      src/pages/storage/amazon-s3-deploy.md
  75. 13
      src/pages/storage/authentication.md
  76. 5
      src/pages/storage/cliDocs.md
  77. 350
      src/pages/storage/config-schema.md
  78. 296
      src/pages/storage/digital-ocean-deploy.md
  79. 55
      src/pages/storage/gaia-admin.md
  80. 110
      src/pages/storage/hello-hub-choice.md
  81. 19
      src/pages/storage/hub-operation.md
  82. 17
      src/pages/storage/overview.md
  83. 11
      src/pages/storage/write-to-read.md

11
src/common/_includes/architecture.md

@ -1,16 +1,15 @@
![Blockstack Architecture](/common/images/architecture.png)
Blockchains require consensus among large numbers of people, so they can be slow. Additionally, a blockchain is not designed to hold a lot of data. This means using a blockchain for every bit of data a user might write and store is expensive. For example, imagine if an application were storing every tweet in the chain.
Blockstack addresses blockchain performance problems using a layered approach. The base layer consists of the Stacks blockchain and the Blockstack Naming System (BNS). The blockchain governs ownership of identities in the Blockstack network. Identities can be names such as domain names, usernames, or application names.
Blockstack addresses blockchain performance problems using a layered approach. The base layer consists of the Stacks blockchain and the Blockstack Naming System (BNS). The blockchain governs ownership of identities in the Blockstack network. Identities can be names such as domain names, usernames, or application names.
When an identity is created, its creation is recorded in the Stacks blockchain. Identities make up the primary data stored into the Stacks blockchain. These identities correspond to routing data in the OSI stack. The routing data is stored in the Atlas Peer Network, the second layer. Every core node that joins the Blockstack Network is able to obtain an entire copy of this routing data. Blockstack uses the routing data to associate identities (domain names, user names, and application names) with a particular storage location in the final layer, the Gaia Storage System.
When an identity is created, its creation is recorded in the Stacks blockchain. Identities make up the primary data stored into the Stacks blockchain. These identities correspond to routing data in the OSI stack. The routing data is stored in the Atlas Peer Network, the second layer. Every core node that joins the Blockstack Network is able to obtain an entire copy of this routing data. Blockstack uses the routing data to associate identities (domain names, user names, and application names) with a particular storage location in the final layer, the Gaia Storage System.
A Gaia Storage System consists of a _hub service_ and storage resource on a cloud software provider. The storage provider can be any commercial provider such as Azure, DigitalOcean, Amazon EC2, and so forth. Typically the compute resource and the storage resource reside same cloud vendor, though this is not a requirement. Gaia currently has driver support for S3 and Azure Blob Storage, but the driver model allows for other backend support as well.
A Gaia Storage System consists of a _hub service_ and storage resource on a cloud software provider. The storage provider can be any commercial provider such as Azure, DigitalOcean, Amazon EC2, and so forth. Typically the compute resource and the storage resource reside same cloud vendor, though this is not a requirement. Gaia currently has driver support for S3 and Azure Blob Storage, but the driver model allows for other backend support as well.
Gaia stores data as a simple key-value store. When an identity is created, a corresponding data store is associated with that identity on Gaia. When a user logs into a dApp,
Gaia stores data as a simple key-value store. When an identity is created, a corresponding data store is associated with that identity on Gaia. When a user logs into a dApp,
the authentication process gives the application the URL of a Gaia hub, which
then writes to storage on behalf of that user.
Within Blockstack, then, the Stacks blockchain stores only identity data. Data created by the actions of an identity is stored in a Gaia Storage System. Each user has profile data. When a user interacts with a decentralized dApp that application stores application data on behalf of the user. Because Gaia stores user and application data off the blockchain, a Blockstack DApp is typically more performant than DApps created on other blockchains.
Within Blockstack, then, the Stacks blockchain stores only identity data. Data created by the actions of an identity is stored in a Gaia Storage System. Each user has profile data. When a user interacts with a decentralized dApp that application stores application data on behalf of the user. Because Gaia stores user and application data off the blockchain, a Blockstack DApp is typically more performant than DApps created on other blockchains.

60
src/common/_includes/commandline.md

@ -1,31 +1,31 @@
The command line is intended for developers only. Developers can use the command
line to test and debug Blockstack applications in ways that the Blockstack
Browser does not yet support. Using the command line, developers can:
* Generate and Broadcast all supported types of Blockstack transactions
* Load, store, and list data in Gaia hubs
* Generate owner, payment and application keys from a seed phrase
* Query Stacks Nodes
* Implement a minimum viable authentication flow
- Generate and Broadcast all supported types of Blockstack transactions
- Load, store, and list data in Gaia hubs
- Generate owner, payment and application keys from a seed phrase
- Query Stacks Nodes
- Implement a minimum viable authentication flow
{% include warning.html content="Many of the commands operate on unencrypted
private keys. For this reason, DO NOT use this tool for day-to-day tasks as you
risk the security of your keys." %}
You must <a href="#installCommandLine">install the command line</a> before you
can use the commands.
can use the commands.
## List of commands
{:.no_toc}
To see the usage and options for the command in general, enter `blockstack-cli` without any subcommands. To see a list of subcommands enter `blockstack-cli help`. Enter `blockstack-cli SUBCOMMAND_NAME help` to see a subcommand with its usage. The following are the available subcommands:
* TOC
{:toc}
- TOC
{:toc}
{% for entry in site.data.cliRef %}
## {{ entry.command }}
**Group**: {{ entry.group }}
@ -33,6 +33,7 @@ To see the usage and options for the command in general, enter `blockstack-cli`
{{ entry.usage }}
### Arguments
{:.no_toc}
<table class="uk-table uk-table-small uk-table-striped">
@ -50,21 +51,23 @@ To see the usage and options for the command in general, enter `blockstack-cli`
<td><code style="font-size:10px">{{ arg.format }}</code></td>
</tr>
{% endfor %}
{% endfor %}
</table>
{% endfor %}
<p><a name="installCommandLine">&nbsp;</a></p>
## How to install the command line
## How to install the command line
{:.no_toc}
You must have [Node.js](https://nodejs.org/en/download/) v8 or higher (v10 recommended). macOS and Linux users can avoid `sudo` or [permissions problems](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) or by using [`nvm`](https://github.com/nvm-sh/nvm). These instructions assume you are using a macOS or Linux system.
You must have [Node.js](https://nodejs.org/en/download/) v8 or higher (v10 recommended). macOS and Linux users can avoid `sudo` or [permissions problems](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) or by using [`nvm`](https://github.com/nvm-sh/nvm). These instructions assume you are using a macOS or Linux system.
To install the command line, do the following:
1. <a href="https://github.com/blockstack/cli-blockstack" target="\_blank">Download or `git clone` the command line repository code</a>.
1. <a href="https://github.com/blockstack/cli-blockstack" target="\_blank">Download or `git clone` the command line repository code</a>.
Downloading or cloning the repo creates a `cli-blockstack` repository on your system.
@ -72,29 +75,38 @@ To install the command line, do the following:
```
cd cli-blockstack
```
```
```
3. Install the dependencies with `npm`.
```
npm install
```
```
npm install
```
4. Build the command line command.
```
npm run build
```
```
npm run build
```
5. Link the command.
```
sudo npm link
```
```
sudo npm link
```
### Troubleshooting the CLI installation
If you run into `EACCES` permissions errors, try the following:
* See https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally.
* Use [`Node Version Manager`](https://github.com/nvm-sh/nvm).
```

12
src/common/_includes/contribute_code.md

@ -1,7 +1,9 @@
### Sections in this article
{:.no_toc}
* TOC
{:toc}
- TOC
{:toc}
Good pull requests—patches, improvements, new features—are a fantastic help. They should remain focused in scope and avoid containing unrelated commits.
@ -58,7 +60,7 @@ Adhering to the following process is the best way to get your work included in t
```
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
with a clear title and description against the `master` branch.
with a clear title and description against the `master` branch.
**IMPORTANT**: By submitting a patch, you agree to allow the project owners to
license your work under the terms of the [MPL-2.0 License](LICENSE.md) (if it
@ -66,7 +68,6 @@ includes code changes) and under the terms of the
[Creative Commons Attribution 3.0 Unported License](docs/LICENSE.md)
(if it includes documentation changes).
## Code guidelines
### HTML
@ -81,13 +82,12 @@ includes code changes) and under the terms of the
- 2 spaces (no tabs)
- strict mode
- "Attractive"
- Don't use jQuery (no "$" allowed)
- Don't use jQuery (no "\$" allowed)
### Checking code
Run `npm run dev` before committing to ensure your changes follow our coding standards.
## License
By contributing your code, you agree to license your contribution under the [MPL-2.0 License](LICENSE.md).

9
src/common/_includes/contribute_community.md

@ -1,14 +1,15 @@
### Sections in this article
{:.no_toc}
* TOC
{:toc}
- TOC
{:toc}
## Community Rewards
Blockstack Community Reward Program
We’ve set up a community portal with all kinds of tasks you can complete to earn Stacks tokens by contributing to and supporting the community - these stay in your account and convert into tokens when the network goes live. Many are really easy and they’re all fun and helpful for the community, more information here - https://contribute.blockstack.org/.
## Blockstack on Social Media
Musce libero nunc, dignissim quis turpis quis, semper vehicula dolor. Suspendisse tincidunt consequat quam, ac posuere leo dapibus id. Cras fringilla convallis elit, at eleifend mi interam.
@ -18,7 +19,6 @@ Musce libero nunc, dignissim quis turpis quis, semper vehicula dolor. Suspendiss
- Telegram
- Reddit
## Meeting fact to face
- Events Calendar
@ -26,7 +26,6 @@ Musce libero nunc, dignissim quis turpis quis, semper vehicula dolor. Suspendiss
- Blockstack Community Rewards Program
- Request Sponsorship for your Event
## Become an evangelist
Musce libero nunc, dignissim quis turpis quis, semper vehicula dolor. Suspendisse tincidunt consequat quam, ac posuere leo dapibus id. Cras fringilla convallis elit, at eleifend mi interam.

18
src/common/_includes/contribute_issues.md

@ -1,19 +1,20 @@
### Sections in this article
{:.no_toc}
* TOC
{:toc}
- TOC
{:toc}
## Using the issue tracker
The [issue tracker](https://github.com/blockstack/blockstack-browser/issues) is the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) and [submitting pull requests](#pull-requests), but please respect the following
restrictions:
* Please **do not** use the issue tracker for personal support requests. Please use the [Forum](https://forum.blockstack.org) or [Slack](https://chat.blockstack.org) as they are better places to get help.
* Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others.
- Please **do not** use the issue tracker for personal support requests. Please use the [Forum](https://forum.blockstack.org) or [Slack](https://chat.blockstack.org) as they are better places to get help.
* Please **do not** post comments consisting solely of "+1" or ":thumbsup:". Use [GitHub's "reactions" feature](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) instead. We reserve the right to delete comments which violate this rule.
- Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others.
- Please **do not** post comments consisting solely of "+1" or ":thumbsup:". Use [GitHub's "reactions" feature](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) instead. We reserve the right to delete comments which violate this rule.
## Issues and labels
@ -29,7 +30,6 @@ Our bug tracker utilizes several labels to help organize and identify issues. He
For a complete look at our labels, see the [project labels page](https://github.com/blockstack/blockstack-browser/labels).
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository. Good bug reports are extremely helpful, so thanks!
@ -44,7 +44,6 @@ Guidelines for bug reports:
3. **Isolate the problem** &mdash; ideally create a [reduced test case](https://css-tricks.com/reduced-test-cases/) and a live example. [This JS Bin](https://jsbin.com/lolome/edit?html,output) is a helpful template.
A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report. What is your environment? What steps will reproduce the issue? What browser(s) and OS experience the problem? Do other browsers show the bug differently? What would you expect to be the outcome? All these details will help people to fix any potential bugs.
Example:
@ -65,7 +64,6 @@ Example:
> causing the bug, and potential solutions (and your opinions on their
> merits).
## Feature requests
Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to *you* to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible.
Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to _you_ to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible.

7
src/common/_includes/contribute_ovr.md

@ -1,7 +1,9 @@
### Sections in this article
{:.no_toc}
* TOC
{:toc}
- TOC
{:toc}
Looking to contribute something to Blockstack? **Here's how you can help.**
@ -20,6 +22,7 @@ Musce libero nunc, dignissim quis turpis quis, semper vehicula dolor. Suspendiss
Nulla non sollicitudin. Morbi sit amet laoreet ipsum, vel pretium mi. Morbi varius, tellus in accumsan blandit, elit ligula eleifend velit, luctus mattis ante nulla condimentum nulla. Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit.
## What can you contribute?
Nunc porta malesuada porta. Etiam tristique vestibulum dolor at ultricies. Proin hendrerit sapien sed erat fermentum, at commodo velit consectetur.
{% include image.html img="image1.png" style="wide" lightbox="true" alt="Alt for image" caption="Image in lightbox" %}

36
src/common/_includes/create_id.md

@ -21,17 +21,17 @@ To create an initial Blockstack ID, do the following:
The **Check Availability** buttom makes sure your name is unique.
2. Press **Continue** when you find an available name you like.
3. Press **Continue** when you find an available name you like.
The application prompts you to enter a password. Blockstack uses this
password to encrypt your recovery code. You must record and save this
initial password.
![]({{ site.baseurl }}/browser/images/create-id-2.png)
![]({{ site.baseurl }}/browser/images/create-id-2.png)
{% include note.html content="The Blockstack team cannot restore your password for you." %}
3. Enter a password, confirm it, and press **Register ID**.
4. Enter a password, confirm it, and press **Register ID**.
Blockstack creates an id for you and then prompts you for an email.
@ -39,36 +39,34 @@ To create an initial Blockstack ID, do the following:
Blockstack uses this email address to send you recovery information. This email is only sent once.
4. Press **Next**.
5. Press **Next**.
Blockstack presents you with the completed ID.
Blockstack presents you with the completed ID.
![]({{ site.baseurl }}/browser/images/create-id-4.png)
![]({{ site.baseurl }}/browser/images/create-id-4.png)
The system prompts you to save your **recovery code**.
The system prompts you to save your **recovery code**.
5. Click **Secret Recovery Key** to record your key.
The system warns you to save your key:
6. Click **Secret Recovery Key** to record your key.
![]({{ site.baseurl }}/browser/images/secret-key-recovery.png)
The system warns you to save your key:
6. Click **Secret Recovery Key** to record your key.
![]({{ site.baseurl }}/browser/images/secret-key-recovery.png)
![]({{ site.baseurl }}/browser/images/create-id-5.png)
7. Click **Secret Recovery Key** to record your key.
A recovery code is a sequence of words. These words allow you to recover
an `id.blockstack` that you've created. You should store the words along
with their order, for example, `#1 applied` and so forth.
![]({{ site.baseurl }}/browser/images/create-id-5.png)
A recovery code is a sequence of words. These words allow you to recover
an `id.blockstack` that you've created. You should store the words along
with their order, for example, `#1 applied` and so forth.
6. Copy your **Secret Recovery Key** and press **Continue**.
6) Copy your **Secret Recovery Key** and press **Continue**.
The system confirms you have saved your key by asking you to select two words.
7. Choose **Go to Blockstack**.
7) Choose **Go to Blockstack**.
It may take several moments for your username to be recorded on the blockchain. You can still use it but you may see a computer-friendly ID sequence such as `ID-1G9318bjf6FAZvD3gnaSyzUojM6f8xKWK1` until the recording is finalized.
Congratulations you have created your first ID. You are now ready to start using DApps.

2
src/common/_includes/required-fields.md

@ -53,4 +53,4 @@
<td><strong>Authentication</strong></td>
<td>Choose Blockstack; Blockstack Authentication is required to participate in Animal Kingdom.</td>
</tr>
</table>
</table>

2
src/common/_includes/scaffolding.md

@ -20,4 +20,4 @@ You use the Blockstack App Generator to create scaffolding for a starter applica
</tr>
</table>
For example, to install a Vue scaffolding, you would use the `npx generator-blockstack --vue` command.
For example, to install a Vue scaffolding, you would use the `npx generator-blockstack --vue` command.

12
src/common/_includes/sign_in.md

@ -4,16 +4,16 @@ A decentralized application and [the Blockstack App](https://github.com/blocksta
![](/storage/images/app-sign-in.png)
When a user chooses to authenticate a decentralized application, it calls the `doOpenAuth()` method which sends an `authRequest` to the Blockstack App. Blockstack passes the token in via a URL query string in the `authRequest` parameter:
When a user chooses to authenticate a decentralized application, it calls the `doOpenAuth()` method which sends an `authRequest` to the Blockstack App. Blockstack passes the token in via a URL query string in the `authRequest` parameter:
`https://app.blockstack.org/#/sign-up?authRequest=j902120cn829n1jnvoa...`
When the Blockstack App receives the request, it generates an (`authResponse`) token to the application using an _ephemeral transit key_ . The ephemeral transit key is just used for the particular instance of the application, in this case, to sign the `authRequest`. The application stores the ephemeral transit key during the request generation. The public portion of the transit key is passed in the `authRequest` token. The Blockstack App uses the public portion of the key to encrypt an _app-private key_ which is returned via the `authResponse`.
When the Blockstack App receives the request, it generates an (`authResponse`) token to the application using an _ephemeral transit key_ . The ephemeral transit key is just used for the particular instance of the application, in this case, to sign the `authRequest`. The application stores the ephemeral transit key during the request generation. The public portion of the transit key is passed in the `authRequest` token. The Blockstack App uses the public portion of the key to encrypt an _app-private key_ which is returned via the `authResponse`.
During sign in, the Blockstack App generates the app-private key from the user's _identity-address private_ key and the application's `appDomain`. The app private key serves three functions:
* It is used to create the credentials that give an app access to the Gaia storage bucket for that specific app.
* It is used in the end-to-end encryption of files stored for the app in the user's Gaia storage.
* It serves as a cryptographic secret that apps can use to perform other cryptographic functions.
- It is used to create the credentials that give an app access to the Gaia storage bucket for that specific app.
- It is used in the end-to-end encryption of files stored for the app in the user's Gaia storage.
- It serves as a cryptographic secret that apps can use to perform other cryptographic functions.
Finally, the app private key is deterministic, meaning that for a given user ID and domain name, the same private key is generated each time.
Finally, the app private key is deterministic, meaning that for a given user ID and domain name, the same private key is generated each time.

4
src/pages/404.tsx

@ -58,9 +58,7 @@ const NotFoundPage = () => {
</Box>
</Box>
<Box mx="auto" maxWidth="40ch" textAlign="center">
<Text>
Looks like there's nothing here yet.
</Text>
<Text>Looks like there's nothing here yet.</Text>
<Box mt={space('base')}>
<Link
as="a"

2
src/pages/common/android_ref.md

@ -1,5 +1,5 @@
---
layout: externalurl
redirect_url: https://blockstack.github.io/blockstack-android/
title: "Blockstack Android Reference"
title: 'Blockstack Android Reference'
---

2
src/pages/common/community_ref.md

@ -1,5 +1,5 @@
---
layout: externalurl
redirect_url: https://community.blockstack.org/
title: "Blockstack Community"
title: 'Blockstack Community'
---

6
src/pages/common/core_ref.md

@ -1,16 +1,18 @@
---
title: "Stacks Blockchain APIs"
title: 'Stacks Blockchain APIs'
description: Interacting with the Stacks 2.0 Blockchain
---
With the launch of Stacks 2.0, a new version of the Blockstack blockchain was released. There are two ways of interacting with the blockchain, either using the Stacks Blockchain API or by making RPC calls to a Stacks Core directly.
## Stacks Core API
The Stacks 2.0 blockchain's Rust implementation exposes RPC endpoints (in JSON format), which can be used to interface with the Stacks blockchain. [You can find the RPC API references here](https://docs.blockstack.org/core/smart/rpc-api.html).
## Stacks Blockchain API
The Stacks Blockchain API was built to maintain pageable materialized views of the Stacks 2.0 Blockchain. It is a server that exposes a RESTful JSON API, hosted by PBC. It introduces aidditonal functionality (e.g. get all transactions), as well as proxies calls directly to Stacks Node. [You can find the OpenAPI specification and documentation here](https://blockstack.github.io/stacks-blockchain-sidecar/).
*Note: Using this API requires you to trust the server, but provides a faster onboarding experience. It also addresses performance issues for which querying a node itself would be too slow or difficult.*
_Note: Using this API requires you to trust the server, but provides a faster onboarding experience. It also addresses performance issues for which querying a node itself would be too slow or difficult._
{% include note.html content="If you are looking for the Stacks 1.0 RPC endpoint references, please follow [this link](https://core.blockstack.org/)." %}

2
src/pages/common/ios_ref.md

@ -1,5 +1,5 @@
---
layout: externalurl
redirect_url: https://blockstack.github.io/blockstack-ios/
title: "Blockstack iOS Reference"
title: 'Blockstack iOS Reference'
---

2
src/pages/common/javascript_ref.md

@ -1,5 +1,5 @@
---
layout: externalurl
redirect_url: https://blockstack.github.io/blockstack.js/
title: "Blockstack Javascript Reference"
title: 'Blockstack Javascript Reference'
---

70
src/pages/core/atlas/howitworks.md

@ -1,12 +1,11 @@
---
description: "Blockstack Atlas network"
description: 'Blockstack Atlas network'
---
# How Atlas Works
Atlas was designed to overcome the structural weaknesses inherent to all
distributed hash tables. In particular, it uses an unstructured peer network to
distributed hash tables. In particular, it uses an unstructured peer network to
maximize resilience against network link failure, and it uses the underlying
blockchain (through BNS) to rate-limit chunk announcements.
@ -16,36 +15,35 @@ This section contains the following sections:
Atlas peers self-organize into an unstructured peer-to-peer network.
The Atlas peer network is a [random K-regular
graph](https://en.wikipedia.org/wiki/Random_regular_graph). Each node maintains
*K* neighbors chosen at random from the set of Atlas peers.
graph](https://en.wikipedia.org/wiki/Random_regular_graph). Each node maintains
_K_ neighbors chosen at random from the set of Atlas peers.
Atlas nodes select peers by carrying out an unbiased random walk of the peer
graph. When "visiting" a node *N*, it will ask for *N*'s neighbors and then
"step" to one of them with a probability dependent on *N*'s out-degree and the
graph. When "visiting" a node _N_, it will ask for _N_'s neighbors and then
"step" to one of them with a probability dependent on _N_'s out-degree and the
neighbor's in-degree.
The sampling algorithm is based on the Metropolis-Hastings (MH) random graph walk
algorithm, but with a couple key differences. In particular, the algorithm
algorithm, but with a couple key differences. In particular, the algorithm
attempts to calculate an unbiased peer graph sample that accounts for the fact
that most nodes will be short-lived or unreliable, while a few persistent nodes
will remain online for long periods of time. The sampling algorithm accounts
will remain online for long periods of time. The sampling algorithm accounts
for this with the following tweaks:
* If the neighbors of the visited node *N* are all unresponsive, the random
walk resets to a randomly-chosen known neighbor. There is no back-tracking on
the peer graph in this case.
- If the neighbors of the visited node _N_ are all unresponsive, the random
walk resets to a randomly-chosen known neighbor. There is no back-tracking on
the peer graph in this case.
* The transition probability from *N* to a live neighbor is *NOT* `min(1,
degree(neighbor)/degree(N))` like it is in the vanilla MH algorithm. Instead,
the transition probability discourages backtracking to the previous neighbor *N_prev*,
but in a way that still guarantees that the sampling will remain unbiased.
- The transition probability from _N_ to a live neighbor is _NOT_ `min(1, degree(neighbor)/degree(N))` like it is in the vanilla MH algorithm. Instead,
the transition probability discourages backtracking to the previous neighbor _N_prev_,
but in a way that still guarantees that the sampling will remain unbiased.
* A peer does not report its entire neighbor set when queried,
but only reports a random subset of peers that have met a minimium health threshold.
- A peer does not report its entire neighbor set when queried,
but only reports a random subset of peers that have met a minimium health threshold.
* A new neighbor is only selected if it belongs to the same [BNS
- A new neighbor is only selected if it belongs to the same [BNS
fork-set]({{site.baseurl}}/core/naming/introduction.html#bns-forks) (i.e. it reports
as having a recent valid consensus hash).
as having a recent valid consensus hash).
The algorithm was adapted from the work from [Lee, Xu, and
Eun](https://arxiv.org/pdf/1204.4140.pdf) in the proceedings of
@ -55,7 +53,7 @@ ACM SIGMETRICS 2012.
The reason Atlas uses an unstructured random peer network
instead of a [distributed hash table](https://en.wikipedia.org/wiki/Distributed_hash_table)
(DHT) is that DHTs are susceptbile to Sybil attacks. An adaptive adversary can
(DHT) is that DHTs are susceptbile to Sybil attacks. An adaptive adversary can
insert malicious nodes into the DHT in order to stop victims from
resolving chunks or finding honest neighbors.
@ -65,7 +63,7 @@ In a DHT, an attacker can censor a chunk by inserting nodes into the peers' rout
such that the attacker takes control over all of the chunk's hash buckets.
It can do so at any point in time after the chunk was first stored,
because only the peers who maintain the chunk's hash bucket have to store it.
This is a *fundamental* problem with structured overlay networks
This is a _fundamental_ problem with structured overlay networks
that perform request routing based on content hash---they give the attacker
insight as to the path(s) the queries take through the peer graph, and thus
reduce the number of paths the attacker must disrupt in order to censor the
@ -75,8 +73,8 @@ Atlas uses an unstructured overlay network combined with a 100% chunk
replication strategy in order to maximize
the amount of work an adversary has to do to censor a chunk.
In Atlas, all peers replicate a chunk, and the paths the chunk take through the
network are *independent* of the content and *randomized* by the software
(so the paths cannot be predicted in advance). The attacker's only
network are _independent_ of the content and _randomized_ by the software
(so the paths cannot be predicted in advance). The attacker's only
recourse is to quickly identify the nodes that can serve the chunk and partition them from
the rest of the network in order to carry out a censorship attack.
This requires them to have visibility into the vast majority of network links in
@ -87,23 +85,23 @@ when asked).
### Neighbor Censorship
Another problem with DHTs is that their overlay
network structure is determined by preferential attachment. Not every peer that
network structure is determined by preferential attachment. Not every peer that
contacts a given DHT node has an equal chance of becoming its neighbor.
The node will instead rank a set of peers as being more or less ideal
for being neighbors. In DHTs, the degree of preference a node exhibits to
for being neighbors. In DHTs, the degree of preference a node exhibits to
another node is usually a function of the node's self-given node identifier
(e.g. a node might want to select neighbors based on proximity in the key
space).
The preferential attachment property means that an adaptive adversary can game the node's
neighbor selection algorithm by inserting malicious nodes that do not
forward routing or lookup requests. The attacker does not even have to eclipse
forward routing or lookup requests. The attacker does not even have to eclipse
the victim node---the victim node will simply prefer to talk to the attacker's unhelpful nodes
instead of helpful honest nodes. In doing so, the attacker can prevent honest peers from discovering each
instead of helpful honest nodes. In doing so, the attacker can prevent honest peers from discovering each
other and each other's chunks.
Atlas's neighbor selection strategy does not exhibit preferential attachment
based on any self-reported node properties. A
based on any self-reported node properties. A
node is selected as a neighbor only if it is reached through an unbiased random graph
walk, and if it responds to queries correctly.
In doing so, an attacker is forced to completely eclipse a set of nodes
@ -111,21 +109,21 @@ in order to cut them off from the rest of the network.
## Chunk Propagation
Atlas nodes maintain an *inventory* of chunks that are known to exist. Each
Atlas nodes maintain an _inventory_ of chunks that are known to exist. Each
node independently calculates the chunk inventory from its BNS database.
Because the history of name operations in BNS is linearized, each node can
construct a linearized sub-history of name operations that can set chunk
hashes as their name state. This gives them a linearized sequence of chunks,
hashes as their name state. This gives them a linearized sequence of chunks,
and every Atlas peer will independently arrive at the same sequence by reading
the same blockchain.
Atlas peers keep track of which chunks are present and which are absent. They
each construct an *inventory vector* of chunks *V* such that *V[i]* is set to 1
Atlas peers keep track of which chunks are present and which are absent. They
each construct an _inventory vector_ of chunks _V_ such that _V[i]_ is set to 1
if the node has the chunk whose hash is in the *i*th position in the chunk
sequence (and set to 0 if it is absent).
Atlas peers exchange their inventory vectors with their neighbors in order to
find out which chunks they each have. Atlas nodes download chunks from
find out which chunks they each have. Atlas nodes download chunks from
neighbors in rarest-first order in order to prioritize data replication for the
chunks that are currently most at-risk for disappearing due to node failure.
@ -173,7 +171,7 @@ Developers can query a node's inventory vector as follows:
```
The variable `result['inv']` here is a big-endian bit vector, where the *i*th
bit is set to 1 if the *i*th chunk in the chunk sequence is present. The bit at
bit is set to 1 if the *i*th chunk in the chunk sequence is present. The bit at
`i=0` (the earliest chunk) refers to the leftmost bit.
A sample program that inspects a set of Atlas nodes' inventory vectors and determines

31
src/pages/core/atlas/howtouse.md

@ -1,8 +1,7 @@
---
description: "Blockstack Atlas network"
description: 'Blockstack Atlas network'
---
# How to Use the Atlas Network
This section teaches you how to use the Atlas network, it contains the
@ -12,23 +11,23 @@ following sections:
While the Blockstack software stack expects that Atlas-hosted data is made up of
DNS zone files, Atlas itself does not enforce this (nor does it care about the
format of its chunks). It is designed as a general-purpose chunk store.
format of its chunks). It is designed as a general-purpose chunk store.
Nevertheless, the ubiquitous use of Atlas to store data as DNS zone files has
had an influence on its API design---fields and method names frequently allude
to zone files and zone file hashes. This is intentional.
to zone files and zone file hashes. This is intentional.
The [public BNS API endpoint](https://core.blockstack.org) does not support
resolving Atlas chunks that do not encode Gaia routing information or subdomain
information. To directly interact with Atlas, developers will need to install
information. To directly interact with Atlas, developers will need to install
[Stacks Node](https://github.com/blockstack/blockstack-core) and use its
Python client libraries for these examples.
## Looking up Chunks
All Atlas chunks are addressed by the RIPEMD160 hash of the SHA256 hash of the
chunk data. A client can query up to 100 chunks in one RPC call.
chunk data. A client can query up to 100 chunks in one RPC call.
A client can look up a chunk with the `get_zonefiles()` method. If successful,
A client can look up a chunk with the `get_zonefiles()` method. If successful,
the returned payload will be a `dict` with a `zonefiles` key that maps the chunk
hashes to their respective data.
@ -49,11 +48,11 @@ tor TXT "3g2upl4pq6kufc4m.onion"
## Adding a New Chunk
The only way to add a chunk to Atlas is to do so through an on-chain name in
BNS. Adding a new chunk is a two-step process:
BNS. Adding a new chunk is a two-step process:
* The name owner announces the chunk hash as a name's state
via a `NAME_REGISTRATION`, `NAME_UPDATE`, `NAME_RENEWAL`, or `NAME_IMPORT` transaction.
* Once the transaction is confirmed and processed by BNS, the name owner
- The name owner announces the chunk hash as a name's state
via a `NAME_REGISTRATION`, `NAME_UPDATE`, `NAME_RENEWAL`, or `NAME_IMPORT` transaction.
- Once the transaction is confirmed and processed by BNS, the name owner
broadcasts the matching zone file.
Setting a name's state to be the hash of a chunk is beyond the scope of this
@ -63,7 +62,7 @@ See the relevant documentation for
Browser](https://github.com/blockstack/blockstack-browser) for doing this.
Once the name operation is confirmed, you can announce the data to the
Atlas network. You can do so with the Python client as follows:
Atlas network. You can do so with the Python client as follows:
```python
>>> import blockstack
@ -79,7 +78,7 @@ At most five chunks can be announced in one RPC call.
Note that the data must be base64-encoded before it can be announced.
When the `put_zonefiles()` method succeeds, it returns a `dict` with a list
under the `saved` key. Here, `result['saved'][i]` will be 1 if the `i`th
under the `saved` key. Here, `result['saved'][i]` will be 1 if the `i`th
chunk given to `put_zonefiles()` was saved by the node, and 0 if not.
The node will not save a chunk if it is too big, or if it has not yet processed
the name operation that contained the chunk's hash.
@ -88,10 +87,10 @@ The `put_zonefiles()` method is idempotent.
## Propagating Chunks
Atlas peers will each store a copy of the chunks you announce. In the
Atlas peers will each store a copy of the chunks you announce. In the
background, they will asynchronously announce to one another which chunks they
have available, and replicate them to one another in a rarest-first order (much
like how BitTorrent works). Eventually, every Atlas peer will receive the
like how BitTorrent works). Eventually, every Atlas peer will receive the
chunk.
However, developers can accelerate this process by eagerly propagating chunks.

67
src/pages/core/atlas/overview.md

@ -1,21 +1,20 @@
---
description: "Blockstack Atlas network"
description: 'Blockstack Atlas network'
---
# Overview of the Atlas network
# Overview of the Atlas network
This document describes the Atlas network, a peer-to-peer content-addressed
storage system whose chunks' hashes are announced on a public blockchain. Atlas
allows users and developers to **permanently store** chunks of data that are
**replicated across every peer.** As long as at least one Atlas peer is online,
**replicated across every peer.** As long as at least one Atlas peer is online,
all chunks are available to clients.
This document is aimed at developers and technical users. The following
This document is aimed at developers and technical users. The following
concepts are discussed:
The reader of this document is expected to be familiar with the [Blockstack Naming Service]({{site.baseurl}}/core/naming/introduction.html)(BNS), as well as Blockstack's
storage system [Gaia](https://github.com/blockstack/gaia). We advise the reader
storage system [Gaia](https://github.com/blockstack/gaia). We advise the reader
to familiarize themselves with both systems before approaching this document.
## Architecture
@ -24,15 +23,15 @@ Atlas is designed to integrate with BNS in order to allow users to
store name state off-chain, encoded as a DNS zone file.
The overwhelmingly-common use-cases in Blockstack are:
* Storing a name's routing information for its owners' [Gaia](https://github.com/blockstack/gaia)
datastores.
* Storing BNS subdomain transactions and associated state.
- Storing a name's routing information for its owners' [Gaia](https://github.com/blockstack/gaia)
datastores.
- Storing BNS subdomain transactions and associated state.
Atlas is a middleware system in Blockstack. Most developers do not
interact with it directly. BNS clients like the
Atlas is a middleware system in Blockstack. Most developers do not
interact with it directly. BNS clients like the
[Blockstack Browser](https://github.com/blockstack/blockstack-browser)
automatically generate zone files for the names they register, and automatically
propagate them to the Atlas network. BNS API endpoints, including our
propagate them to the Atlas network. BNS API endpoints, including our
[public endpoint](https://core.blockstack.org) and the
[blockstack.js](https://github.com/blockstack/blockstack.js) library,
will automatically fetch zone files from Atlas when they need to look
@ -78,46 +77,46 @@ allowing Blockstack apps to read and write data in Gaia.
Nevertheless, Atlas is a general-purpose content-addressed storage
system that advanced developers can use to **host data in an immutable
and durable manner.** Beyond its default use-case in Blockstack,
and durable manner.** Beyond its default use-case in Blockstack,
Atlas is ideal for tasks like:
* Announcing PGP public keys under a human-readable name
* Storing package hashes for a software release
* Securely deploying shell scripts to remote VMs
* Binding human-readable names to Tor .onion addresses
- Announcing PGP public keys under a human-readable name
- Storing package hashes for a software release
- Securely deploying shell scripts to remote VMs
- Binding human-readable names to Tor .onion addresses
([example](https://github.com/blockstack-packages/blockstack-tor))
## Motivation
Atlas was designed to augment BNS. BNS allows each name to store a small
amount of state---on the order of 20 bytes. The size is so small because the
Atlas was designed to augment BNS. BNS allows each name to store a small
amount of state---on the order of 20 bytes. The size is so small because the
state must be recorded to a public blockchain, where the cost per byte is
high and the blockchain protocol limits the size of transactions.
To compensate for this, we developed an off-chain storage system allows BNS
names to bind and store a large amount of state to each name in a way that
*preserves the security properties of having written that state to the
blockchain*. Instead of storing 20 bytes of data on the blockchain, a BNS name
owner would store the *cryptograhpic hash* of its state, and then store the actual state
Atlas. This decouples the name's state size from the blockchain.
_preserves the security properties of having written that state to the
blockchain_. Instead of storing 20 bytes of data on the blockchain, a BNS name
owner would store the _cryptograhpic hash_ of its state, and then store the actual state
Atlas. This decouples the name's state size from the blockchain.
The reference implementation of Atlas currently allows up to 40kb of state to be
bound to a BNS name, instead of a measly 20 bytes. The 40kb of data is
bound to a BNS name, instead of a measly 20 bytes. The 40kb of data is
replicated to each BNS node, where it is stored forever.
## Feature Comparison
Atlas is not the only peer-to-peer content-addressible chunk store in existance. The following
Atlas is not the only peer-to-peer content-addressible chunk store in existance. The following
feature table describes Atlas in relation to other popular chunk stores.
| **Features** | Atlas | BitTorrent | [DAT](https://datproject.org/) | [IPFS](https://ipfs.io) | [Swarm](https://github.com/ethersphere/swarm) |
|-----------------------------|-------|------------|--------------------------------|-------------------------|-----------------------------------------------|
| Each peer stores all chunks | X | X | | | |
| Replicas are permanent [1] | X | X | X | | |
| Replicas are free | | X | X | X | |
| Sybil-resistant chunk discovery | X | X | | | X |
| Sybil-resistant peer discovery | X | | | | |
| Fixed chunk size | X | | X | X | X |
| **Features** | Atlas | BitTorrent | [DAT](https://datproject.org/) | [IPFS](https://ipfs.io) | [Swarm](https://github.com/ethersphere/swarm) |
| ------------------------------- | ----- | ---------- | ------------------------------ | ----------------------- | --------------------------------------------- |
| Each peer stores all chunks | X | X | | | |
| Replicas are permanent [1] | X | X | X | | |
| Replicas are free | | X | X | X | |
| Sybil-resistant chunk discovery | X | X | | | X |
| Sybil-resistant peer discovery | X | | | | |
| Fixed chunk size | X | | X | X | X |
[1] Here, "permanent" means that once a peer has data, they will never evict it
as part of the protocol.

64
src/pages/core/best-practices.md

@ -1,47 +1,57 @@
## Hardware and OS requirements
* A 64-bit CPU running at at least 1 GHz is *highly* recommended (but not strictly required)
* You will need ~250MB RAM and ~10 GB disk free. Do **not** attempt to use a network-attached disk for this.
* You should have at least 30,000 inodes free in your filesystem. Unless you are using a very small VM image, you almost certainly have enough (you can check with `df -i`).
* TCP port 6264 should be open and support bidirectional traffic. If you want to use SSL, then port 6263 should be open.
* A reliable Internet connection of DSL-like quality or higher
- A 64-bit CPU running at at least 1 GHz is _highly_ recommended (but not strictly required)
- You will need ~250MB RAM and ~10 GB disk free. Do **not** attempt to use a network-attached disk for this.
- You should have at least 30,000 inodes free in your filesystem. Unless you are using a very small VM image, you almost certainly have enough (you can check with `df -i`).
- TCP port 6264 should be open and support bidirectional traffic. If you want to use SSL, then port 6263 should be open.
- A reliable Internet connection of DSL-like quality or higher
## Deployment
### The Easy Way
* Install from `pip`, source code, or Docker
* Run `blockstack-core fast_sync`
* Run `blockstack-core start`
- Install from `pip`, source code, or Docker
- Run `blockstack-core fast_sync`
- Run `blockstack-core start`
### The Less Easy Way
* Install from `pip`, source code, or Docker
* Run `blockstack-core start`
* Wait a few days
- Install from `pip`, source code, or Docker
- Run `blockstack-core start`
- Wait a few days
#### Best Practices for the Less Easy Way
* Take a `blockstack-server.snapshots` database from a known-good node and pass `--expected_snapshots=/path/to/blockstack-server.snapshots`. This will force your bootstrapping node to verify that it reaches the same sequence of consensus hashes as it bootstraps (i.e. your node will detect any divergence from Blockstack's name history and abort early, instead of wasting your time).
* Make sure you're in a position to leave the node online at 100% CPU use for the duration of its bootstrapping period
- Take a `blockstack-server.snapshots` database from a known-good node and pass `--expected_snapshots=/path/to/blockstack-server.snapshots`. This will force your bootstrapping node to verify that it reaches the same sequence of consensus hashes as it bootstraps (i.e. your node will detect any divergence from Blockstack's name history and abort early, instead of wasting your time).
- Make sure you're in a position to leave the node online at 100% CPU use for the duration of its bootstrapping period
### The Hard Way
* Install `bitcoind` (version 0.16.x is recommended for now)
* Start `bitcoind` as `bitcoind -daemon -txindex=1`
* Wait for `bitcoind` to download the entire blockchain. This can take between 1 hour and 1 day.
* Install `blockstack-core` from source, `pip`, or Docker
* Run `blockstack-core configure` and enter your `bitcoind` node's IP address, port, RPC username, and RPC password when prompted
* Run `blockstack-core start`
* Wait a few days
- Install `bitcoind` (version 0.16.x is recommended for now)
- Start `bitcoind` as `bitcoind -daemon -txindex=1`
- Wait for `bitcoind` to download the entire blockchain. This can take between 1 hour and 1 day.
- Install `blockstack-core` from source, `pip`, or Docker
- Run `blockstack-core configure` and enter your `bitcoind` node's IP address, port, RPC username, and RPC password when prompted
- Run `blockstack-core start`
- Wait a few days
#### Best Practices for the Hard Way
* You're going to need ~500 GB of space for the Bitcoin blockchain state
* You can safely store its chain state on a network-attached disk, if you're doing this in a cloud-hosted environment
* Your `bitcoind` host will need TCP:8332-8333 open for bidirectional traffic
- You're going to need ~500 GB of space for the Bitcoin blockchain state
- You can safely store its chain state on a network-attached disk, if you're doing this in a cloud-hosted environment
- Your `bitcoind` host will need TCP:8332-8333 open for bidirectional traffic
## Troubleshooting
### The node stops responding to TCP:6264
* Check `dmesg` for TCP SYN flooding. The solution here is to kill and restart the node.
* To mitigate, install a rate-limiting proxy HTTP server in front of the node. We have a sample config for `nginx` [here](https://github.com/blockstack/atlas/blob/master/public_fleet/node/default).
- Check `dmesg` for TCP SYN flooding. The solution here is to kill and restart the node.
- To mitigate, install a rate-limiting proxy HTTP server in front of the node. We have a sample config for `nginx` [here](https://github.com/blockstack/atlas/blob/master/public_fleet/node/default).
### No other Blockstack nodes contact my node
* Verify that your IP address is publicly-routable, and that peers can communicate on TCP:6264
- Verify that your IP address is publicly-routable, and that peers can communicate on TCP:6264
### People are attacking my Bitcoin node
* Stick an `nginx` reverse proxy in front of your `bitcoind` node, and use our [nginx](https://github.com/blockstack/atlas/tree/master/public_fleet/bitcoind) scripts to limit APi access to only the JSON-RPC methods Blockstack actually needs. Better yet, do what we do---build a statically-linked `bitcoind` binary from source that simply omits all of the RPC methods except the ones listed in the linked config file.
- Stick an `nginx` reverse proxy in front of your `bitcoind` node, and use our [nginx](https://github.com/blockstack/atlas/tree/master/public_fleet/bitcoind) scripts to limit APi access to only the JSON-RPC methods Blockstack actually needs. Better yet, do what we do---build a statically-linked `bitcoind` binary from source that simply omits all of the RPC methods except the ones listed in the linked config file.

13
src/pages/core/faq_developer.md

@ -1,6 +1,7 @@
---
description: Blockstack DApp technical FAQs
---
# DApp Developer FAQs
This document lists frequently-asked questions developers about Blockstack application development. If you are new to Blockstack, you should read the [general questions]({{site.baseurl}}/faqs/allFAQs.html) first.
@ -12,15 +13,19 @@ If you have a technical question that gets frequently asked on the
feel free to send a pull-request with the question and answer.
{% for faq in site.data.theFAQs.faqs %}
{% if faq.category == 'dappdevs' %}
{% if faq.category == 'dappdevs' %}
### {{ faq.question }}
{{ faq.answer }}
{% endif %}
{% endif %}
{% endfor %}
{% for faq in site.data.theFAQs.faqs %}
{% if faq.category == 'opensource' %}
{% if faq.category == 'opensource' %}
### {{ faq.question }}
{{ faq.answer }}
{% endif %}
{% endif %}
{% endfor %}

9
src/pages/core/install-api.md

@ -5,7 +5,8 @@ Step-by-step instructions for deploying a Blockstack API node on Debian or Ubunt
- **Step 1:** Make sure you have a Stacks Node running locally (see [instructions](https://github.com/blockstack/blockstack-core/blob/master/README.md#quick-start)).
- **Step 2:** Make sure you have [virtualenv installed](http://docs.python-guide.org/en/latest/dev/virtualenvs/).
Then, setup the API:
Then, setup the API:
```
$ sudo apt-get install -y python-pip memcached rng-tools python-dev libmemcached-dev zlib1g-dev libgmp-dev libffi-dev libssl-dev
$ sudo service memcached start
@ -32,19 +33,23 @@ follow the instructions [here](search.html).
For a production deployment we recommend using nginx and uwsgi:
- **Step 1:** Install nginx and uWSGI:
```
$ sudo apt-get install -y nginx
$ sudo pip install uwsgi
```
- **Step 2:** Copy [this sample nginx sites file](../api/nginx/config/nginx_sites-available/blockstack_api) to
> /etc/nginx/sites-available/blockstack_api
and edit the paths depending on the uwsgi blockstack_api socket directory (defaults to /tmp/blockstack_api.sock)
You can test your nginx settings:
```
$ sudo nginx -t
```
- **Step 3:** Copy [this sample systemd service file](../api/nginx/config/systemd_system/blockstack_api.service) to
> /etc/systemd/system/blockstack_api.service
@ -61,6 +66,7 @@ $ sudo sed -i "s#/path/to/virtualenv#$VIRTUAL_ENV#" /etc/systemd/system/blocksta
```
- **Step 4:** Get a security certificate from [Let's Encrypt](https://letsencrypt.org/).
```
$ git clone https://github.com/certbot/certbot.git
$ cd certbot/
@ -70,6 +76,7 @@ $ ./certbot-auto --nginx -d <your_domain>
And copy the cert files to the path given in the nginx sites file earlier.
- **Step 5:** Start nginx and the Blockstack API uwsgi server:
```
sudo systemctl restart blockstack_api
sudo systemctl restart nginx

58
src/pages/core/naming/architecture.md

@ -1,29 +1,28 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Understand the Architecture
The BNS node is the heart of the system. It is responsible for building up
The BNS node is the heart of the system. It is responsible for building up
and replicating global name state.
There are three parts to BNS that developers should be aware of. They are:
There are three parts to BNS that developers should be aware of. They are:
* **The BNS indexer**. This module crawls the blockchain and builds
up its name database. BNS indexers do not contain any private or sensitive
state, and can be deployed publicly. We maintain a fleet of them at
`https://node.blockstack.org:6263` for developers to use to get started.
- **The BNS indexer**. This module crawls the blockchain and builds
up its name database. BNS indexers do not contain any private or sensitive
state, and can be deployed publicly. We maintain a fleet of them at
`https://node.blockstack.org:6263` for developers to use to get started.
* **The BNS API**. This module gives
developers a *stable RESTful API* for interacting with the BNS network.
We provide one for developers to experiment with at `https://core.blockstack.org`.
- **The BNS API**. This module gives
developers a _stable RESTful API_ for interacting with the BNS network.
We provide one for developers to experiment with at `https://core.blockstack.org`.
* **BNS clients**. These communicate with the BNS API module in order to
resolve names. Internally, they generate and send transactions to register
and modify names.
- **BNS clients**. These communicate with the BNS API module in order to
resolve names. Internally, they generate and send transactions to register
and modify names.
The BNS indexer and BNS API comprise the **BNS node**. An architectural schematic appears below.
The BNS indexer and BNS API comprise the **BNS node**. An architectural schematic appears below.
```
+-------------------------------------------------------+
@ -44,34 +43,33 @@ The BNS indexer and BNS API comprise the **BNS node**. An architectural schemat
+--------------------+
```
The above diagram depicts the BNS architecture. Clients talk to the BNS API module to resolve names, and generate and send blockchain transactions to register and modify names. The API module talks to the indexer module and gives clients a stable, Web-accessible interface for resolving names. The indexer module reads the blockchain via a blockchain peer, over the blockchain's peer network.
The above diagram depicts the BNS architecture. Clients talk to the BNS API module to resolve names, and generate and send blockchain transactions to register and modify names. The API module talks to the indexer module and gives clients a stable, Web-accessible interface for resolving names. The indexer module reads the blockchain via a blockchain peer, over the blockchain's peer network.
Stacks Blockchain currently implements the API module and indexer module as separate
daemons (`blockstack api` and `blockstack-core`, respectively). However, this
daemons (`blockstack api` and `blockstack-core`, respectively). However, this
is an implementation detail, and may change in the future.
The BNS indexer implements the blockchain consensus rules and network protocols.
Its main responsibility is to build up and replicate all of the name state. It does
Its main responsibility is to build up and replicate all of the name state. It does
not have any public APIs of its own.
The BNS API modules allows users and developers to resolve names via a RESTful
interface. Resolution can be done with vanilla `curl` or `wget`.
interface. Resolution can be done with vanilla `curl` or `wget`.
BNS applications should use the BNS API module for name resolution.
They should not attempt to talk to a BNS indexer directly, because its API is not stable and is not meant
for consumption by any other process except for the API module.
Registering and managing names require generating and sending blockchain
transactions, which requires running a BNS client. We provide two reference
transactions, which requires running a BNS client. We provide two reference
BNS clients:
* The [Blockstack Browser](https://github.com/blockstack/blockstack-browser) gives users
and developers a graphical UI to resolve, register and manage names. This is the recommended
way to interact with BNS.
* The Blockstack CLI gives developers low-level
control over resolving, registering, and managing names.
A new CLI that uses [blockstack.js](https://github.com/blockstack/blockstack.js)
is under development, and will replace the existing CLI program.
- The [Blockstack Browser](https://github.com/blockstack/blockstack-browser) gives users
and developers a graphical UI to resolve, register and manage names. This is the recommended
way to interact with BNS.
- The Blockstack CLI gives developers low-level
control over resolving, registering, and managing names.
A new CLI that uses [blockstack.js](https://github.com/blockstack/blockstack.js)
is under development, and will replace the existing CLI program.
We recommend that new developers use the [Blockstack
Browser](https://github.com/blockstack/blockstack-browser).
@ -81,5 +79,5 @@ the reference client library code should read the
[BNS transaction wire format]({{ site.baseurl }}/core/wire-format.html) document for generating and
sending their own transactions.
The examples in this document focus on resolving names using `curl`. We refer
The examples in this document focus on resolving names using `curl`. We refer
the reader to client-specific documentation for registering and managing names.

112
src/pages/core/naming/comparison.md

@ -1,8 +1,7 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Naming system feature comparison
BNS is not the only naming system in wide-spread use, nor is it the only
@ -13,50 +12,50 @@ comparison to Blockstack:
## Blockstack vs DNS
Blockstack and DNS both implement naming systems, but in fundamentally
different ways. Blockstack *can be used* for resolving host names to IP
addresses, but this is not its default use-case. The [Blockstack Naming
different ways. Blockstack _can be used_ for resolving host names to IP
addresses, but this is not its default use-case. The [Blockstack Naming
Service]({{ site.baseurl }}/core/naming/introduction.html) (BNS) instead behaves
more like a decentralized
[LDAP](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) system for
resolving user names to user data.
While DNS and BNS handle different problems, they share some terminology and
serialization formats. However, it is important to recognize that this is the
*only* thing they have in common---BNS has fundamentally different semantics
serialization formats. However, it is important to recognize that this is the
_only_ thing they have in common---BNS has fundamentally different semantics
than DNS:
* **Zone files**: Blockstack stores a DNS zone file for each name. However,
the semantics of a BNS zone file are nothing like the semantics of a DNS zone
file---the only thing they have in common is their format.
A "standard" Blockstack zone files only have `URI` and `TXT` resource records
that point to the user's application data. Moreover, a Blockstack ID has a
*history* of zone files, and historic zone files can alter the way in which a
Blockstack ID gets resolved (DNS has no such concept). It is conceivable that an advanced
user could add `A` and `AAAA` records to their Blockstack ID's zone file,
but these are not honored by any Blockstack software at this time.
* **Subdomains**: Blockstack has the concept of a subdomain, but it is
semantically very different from a DNS subdomain. In Blockstack, a subdomain
is a Blockstack ID whose state and transaction history are anchored to the
blockchain, but stored within an on-chain Blockstack ID's zone file history.
Unlike DNS subdomains, a BNS subdomain has
its own owner and is a first-class BNS name---all subdomains are resolvable,
and only the subdomain's owner can update the subdomain's records. The only thing BNS subdomains and DNS
subdomains have in common is the name format (e.g. `foo.bar.baz` is a subdomain
of `bar.baz` in both DNS and BNS).
- **Zone files**: Blockstack stores a DNS zone file for each name. However,
the semantics of a BNS zone file are nothing like the semantics of a DNS zone
file---the only thing they have in common is their format.
A "standard" Blockstack zone files only have `URI` and `TXT` resource records
that point to the user's application data. Moreover, a Blockstack ID has a
_history_ of zone files, and historic zone files can alter the way in which a
Blockstack ID gets resolved (DNS has no such concept). It is conceivable that an advanced
user could add `A` and `AAAA` records to their Blockstack ID's zone file,
but these are not honored by any Blockstack software at this time.
- **Subdomains**: Blockstack has the concept of a subdomain, but it is
semantically very different from a DNS subdomain. In Blockstack, a subdomain
is a Blockstack ID whose state and transaction history are anchored to the
blockchain, but stored within an on-chain Blockstack ID's zone file history.
Unlike DNS subdomains, a BNS subdomain has
its own owner and is a first-class BNS name---all subdomains are resolvable,
and only the subdomain's owner can update the subdomain's records. The only thing BNS subdomains and DNS
subdomains have in common is the name format (e.g. `foo.bar.baz` is a subdomain
of `bar.baz` in both DNS and BNS).
More details can be found in the [Blockstack vs
DNS]({{ site.baseurl }}/core/naming/comparison.html) document. A feature
DNS]({{ site.baseurl }}/core/naming/comparison.html) document. A feature
comparison can be found at the end of the [Blockstack Naming
Service]({{ site.baseurl }}/core/naming/introduction.html) document.
## Blockstack vs Namecoin
Namecoin also implements a decentralized naming service on top of a blockchain,
just like BNS. In fact, early versions of Blockstack were built on Namecoin.
just like BNS. In fact, early versions of Blockstack were built on Namecoin.
However, [it was discovered](https://www.usenix.org/node/196209) that Namecoin's
merged mining with Bitcoin regularly placed it under the *de facto* control of a single
miner. This prompted a re-architecting of the system to be *portable* across
merged mining with Bitcoin regularly placed it under the _de facto_ control of a single
miner. This prompted a re-architecting of the system to be _portable_ across
blockchains, so that if Blockstack's underlying blockchain (currently Bitcoin)
ever became insecure, the system could migrate to a more secure blockchain.
@ -66,17 +65,17 @@ Service]({{ site.baseurl }}/core/naming/introduction.html) document.
## Blockstack vs ENS
ENS also implements a decentralized naming system on top of a blockchain, but as
a smart contract on Ethereum. Like BNS, ENS is geared towards resolving names
to off-chain state (ENS names resolve to a hash, for example). Moreover, ENS is
a smart contract on Ethereum. Like BNS, ENS is geared towards resolving names
to off-chain state (ENS names resolve to a hash, for example). Moreover, ENS is
geared towards providing programmatic control over names with Turing-complete
on-chain resolvers.
BNS has a fundamentally different relationship with blockchains than ENS.
Whereas ENS tries to use on-chain logic as much as possible, BNS
tries to use the blockchain as little as possible. BNS only uses it to store a
tries to use the blockchain as little as possible. BNS only uses it to store a
database log for name operations (which are interpreted with an off-chain BNS
node like Stacks Blockchain). BNS name state and BNS subdomains reside entirely
off-chain in the Atlas network. This has allowed BNS to migrate from blockchain
node like Stacks Blockchain). BNS name state and BNS subdomains reside entirely
off-chain in the Atlas network. This has allowed BNS to migrate from blockchain
to blockchain in order to survive individual blockchain failures, and this has
allowed BNS developers to upgrade its consensus rules without having to get the
blockchain's permission (see the [virtualchain
@ -84,32 +83,31 @@ paper](https://blockstack.org/virtualchain.pdf) for details).
## Summary feature comparison
The following feature table provides a quick summary how BNS differs from other naming systems
| Feature | BNS | [ENS](https://ens.domains/) | DNS | [Namecoin](https://namecoin.org/) |
|----------------------------|-----|-----|-----|----------|
| Globally unique names | X | X | X | X |
| Human-readable names | X | X | X | X |
| Strongly-owned names | X | X | | X |
| Names are enumerable | X | | | X |
| Registration times | 1-2 hours | ~1 week | ~1 day | 1-2 hours |
| Subdomain registration times | 1 hour (instant with [#750](https://github.com/blockstack/blockstack-core/issues/750)) | varies | instant | ~1 hour |
| Anyone can make a TLD/namespace | X | [1] | | [1] |
| TLD/Namespace owners get registration fees | X | | X | |
| TLD/Namespace can be seeded with initial names | X | | X | |
| Portable across blockchains | X | | N/A | |
| Off-chain names | X | | N/A | |
| Off-chain name state | X | X | N/A | |
| Name provenance | X | X | | X |
| [DID](http://identity.foundation) support | X | | | |
| Turing-complete namespace rules | | X | X | |
| Miners are rewarded for participating | [1] | | N/A | X |
[1] Requires support in higher-level applications. These systems are not aware
| Feature | BNS | [ENS](https://ens.domains/) | DNS | [Namecoin](https://namecoin.org/) |
| ---------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------- | ------- | --------------------------------- |
| Globally unique names | X | X | X | X |
| Human-readable names | X | X | X | X |
| Strongly-owned names | X | X | | X |
| Names are enumerable | X | | | X |
| Registration times | 1-2 hours | ~1 week | ~1 day | 1-2 hours |
| Subdomain registration times | 1 hour (instant with [#750](https://github.com/blockstack/blockstack-core/issues/750)) | varies | instant | ~1 hour |
| Anyone can make a TLD/namespace | X | [1] | | [1] |
| TLD/Namespace owners get registration fees | X | | X | |
| TLD/Namespace can be seeded with initial names | X | | X | |
| Portable across blockchains | X | | N/A | |
| Off-chain names | X | | N/A | |
| Off-chain name state | X | X | N/A | |
| Name provenance | X | X | | X |
| [DID](http://identity.foundation) support | X | | | |
| Turing-complete namespace rules | | X | X | |
| Miners are rewarded for participating | [1] | | N/A | X |
[1] Requires support in higher-level applications. These systems are not aware
of the existence of namespaces/TLDs at the protocol level.
[2] Stacks Blockchain destroys the underlying blockchain token to pay for
registration fees when there is no pay-to-namespace-creator address set in the
name's namespace. This has the effect of making the blockchain miners' holdings
name's namespace. This has the effect of making the blockchain miners' holdings
slightly more valuable.

23
src/pages/core/naming/creationhowto.md

@ -1,8 +1,7 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Creating a Namespace
Making a namespace is very expensive. Given the large amount of cryptocurrency at stake in name creation, developers wanting to create their own namespaces should read [Understand Namespaces]({{ site.baseurl }}/core/naming/namespaces.html) first. You should also read this document thoroughly before creating a namespace.
@ -13,35 +12,35 @@ There are four steps to creating a namespace.
### Step 1. Send a `NAMESPACE_PREORDER` transaction
This step registers the *salted hash* of the namespace with BNS nodes, and burns the requisite amount of cryptocurrency. Additionally, this step proves to the BNS nodes that user has honored the BNS consensus rules by including a recent *consensus hash* in the transaction (see the section on [BNS forks](#bns-forks) for details).
This step registers the _salted hash_ of the namespace with BNS nodes, and burns the requisite amount of cryptocurrency. Additionally, this step proves to the BNS nodes that user has honored the BNS consensus rules by including a recent _consensus hash_ in the transaction (see the section on [BNS forks](#bns-forks) for details).
### Step 2. Send a `NAMESPACE_REVEAL` transaction
This second step reveals the salt and the namespace ID (pairing it with its
`NAMESPACE_PREORDER`). It reveals how long names last in this namespace before
they expire or must be renewed, and it sets a *price function* for the namespace
they expire or must be renewed, and it sets a _price function_ for the namespace
that determines how cheap or expensive names its will be.
The price function takes a name in this namespace as input, and outputs the amount of cryptocurrency the name will cost. The function does this by examining how long the name is, and whether or not it has any vowels or non-alphabet characters. The namespace creator has the option to collect name registration fees for the first year of the namespace's existence by setting a *namespace creator address*.
The price function takes a name in this namespace as input, and outputs the amount of cryptocurrency the name will cost. The function does this by examining how long the name is, and whether or not it has any vowels or non-alphabet characters. The namespace creator has the option to collect name registration fees for the first year of the namespace's existence by setting a _namespace creator address_.
### Step 3. Seed the namespace with `NAME_IMPORT` transactions
Once a namespace is revealed, the user has the option to populate it with a set of
names. Each imported name is given both an owner and some off-chain state.
names. Each imported name is given both an owner and some off-chain state.
This step is optional; Namespace creators are not required to import names.
### Step 4. Send a `NAMESPACE_READY` transaction
The final step of the process *launches* the namespace and makes the namespace available to the
public. Once a namespace is launched, anyone can register a name in it if they
The final step of the process _launches_ the namespace and makes the namespace available to the
public. Once a namespace is launched, anyone can register a name in it if they
pay the appropriate amount of cryptocurrency. Again, the appropriate amount is according to the price function
revealed in step 2.
## Consensus rules and competition for namespaces
Namespaces are created on a first-come first-serve basis. The BNS consensus rules require a `NAMESPACE_REVEAL` to be paired with a previous `NAMESPACE_PREORDER` sent within the past 24 hours. If two people try to create the same namespace, the one that successfully confirms both the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` wins. The fee burned in the `NAMESPACE_PREORDER` is spent either way.
Namespaces are created on a first-come first-serve basis. The BNS consensus rules require a `NAMESPACE_REVEAL` to be paired with a previous `NAMESPACE_PREORDER` sent within the past 24 hours. If two people try to create the same namespace, the one that successfully confirms both the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` wins. The fee burned in the `NAMESPACE_PREORDER` is spent either way.
Once a user issues the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL`, they have 1 year before they must send the `NAMESPACE_READY` transaction. If they do not do this, then the namespace they created disappears (along with all the names they imported).
Once a user issues the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL`, they have 1 year before they must send the `NAMESPACE_READY` transaction. If they do not do this, then the namespace they created disappears (along with all the names they imported).
Pairing the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` steps is designed to prevent frontrunning. Frontrunning is a practice where name registrar uses insider information to register domains for the purpose of re-selling them or earning revenue from them. By registering the domains, the registrar locks out other potential registrars. Thus, through this pairing, a malicious actor cannot watch the blockchain network and race a victim to claim a namespace.
@ -94,5 +93,3 @@ If you would like to navigate a namespace history, you can. To do this, do the f
3. Provide the id in a query to a blockchain explorer such as [Blockchain.com](https://www.blockchain.com/) or similar.
For example, a search on Blockchain returns this [page of information](https://www.blockchain.com/btc/tx/5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28).

44
src/pages/core/naming/did.md

@ -1,5 +1,5 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Decentralized Identifiers (DIDs)
@ -8,15 +8,16 @@ BNS nodes are compliant with the emerging
[Decentralized Identity Foundation](http://identity.foundation) protocol
specification for decentralized identifiers (DIDs).
Each name in BNS has an associated DID. The DID format for BNS is:
Each name in BNS has an associated DID. The DID format for BNS is:
```
did:stack:v0:{address}-{index}
```
Where:
* `{address}` is an on-chain public key hash (e.g. a Bitcoin address).
* `{index}` refers to the `nth` name this address created.
- `{address}` is an on-chain public key hash (e.g. a Bitcoin address).
- `{index}` refers to the `nth` name this address created.
For example, the DID for `personal.id` is
`did:stack:v0:1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV-0`, because the name
@ -35,15 +36,15 @@ in order to be compatible with other systems that use DIDs for public key resolu
In order for a DID to be resolvable, all of the following must be true for a
name:
* The name must exist
* The name's zone file hash must be the hash of a well-formed DNS zone file
* The DNS zone file must be present in the BNS [Atlas Network]({{ site.baseurl }}/core/atlas/overview.html)
* The DNS zone file must contain a `URI` resource record that points to a signed
- The name must exist
- The name's zone file hash must be the hash of a well-formed DNS zone file
- The DNS zone file must be present in the BNS [Atlas Network]({{ site.baseurl }}/core/atlas/overview.html)
- The DNS zone file must contain a `URI` resource record that points to a signed
JSON Web Token
* The public key that signed the JSON Web Token (and is included with it) must
- The public key that signed the JSON Web Token (and is included with it) must
hash to the address that owns the name
Not all names will have DIDs that resolve to public keys. However, names created by the [Blockstack
Not all names will have DIDs that resolve to public keys. However, names created by the [Blockstack
Browser](https://github.com/blockstack/blockstack-browser) will have DIDs that
do.
@ -57,29 +58,28 @@ Developers can programmatically resolve DIDs via the Python API:
A RESTful API is under development.
# DID Encoding for Subdomains
Every name and subdomain in BNS has a DID. The encoding is slightly different
Every name and subdomain in BNS has a DID. The encoding is slightly different
for subdomains, so the software can determine which code-path to take.
* For on-chain BNS names, the `{address}` is the same as the Bitcoin address
that owns the name. Currently, both version byte 0 and version byte 5
addresses are supported (i.e. addresses starting with `1` or `3`, meaning `p2pkh` and
`p2sh` addresses).
- For on-chain BNS names, the `{address}` is the same as the Bitcoin address
that owns the name. Currently, both version byte 0 and version byte 5
addresses are supported (i.e. addresses starting with `1` or `3`, meaning `p2pkh` and
`p2sh` addresses).
* For off-chain BNS subdomains, the `{address}` has version byte 63 for
- For off-chain BNS subdomains, the `{address}` has version byte 63 for
subdomains owned by a single private key, and version byte 50 for subdomains
owned by a m-of-n set of private keys. That is, subdomain DID addresses start
with `S` or `M`, respectively.
owned by a m-of-n set of private keys. That is, subdomain DID addresses start
with `S` or `M`, respectively.
The `{index}` field for a subdomain's DID is distinct from the `{index}` field
for a BNS name's DID, even if the same created both names and subdomains.
For example, the name `abcdefgh123456.id` has the DID `did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-0`,
because it was the first name created by `16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg`.
However, `16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg` *also* created `jude.statism.id`
as its first subdomain name. The DID for `jude.statism.id` is
`did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0`. Note that the address
However, `16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg` _also_ created `jude.statism.id`
as its first subdomain name. The DID for `jude.statism.id` is
`did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0`. Note that the address
`SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i` encodes the same public key hash as the address
`16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg` (the only difference between these two
strings is that the first is base58check-encoded with version byte 0, and the

86
src/pages/core/naming/forks.md

@ -1,61 +1,61 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# BNS Forks
BNS effectively uses a public blockchain to store a database log. A BNS peer
BNS effectively uses a public blockchain to store a database log. A BNS peer
bootstraps itself by downloading and replaying the database log from the
blockchain, and in doing so, will calculate the same name database state as
every other (honest) BNS peer that has the same view of the blockchain.
Crucially, BNS is built on top of a public blockchain that is *unaware* of BNS's existence.
This means that the blockchain peers do not validate BNS transactions. Instead,
the BNS peer needs to do so, and must know how to *reject* both invalid transactions
Crucially, BNS is built on top of a public blockchain that is _unaware_ of BNS's existence.
This means that the blockchain peers do not validate BNS transactions. Instead,
the BNS peer needs to do so, and must know how to _reject_ both invalid transactions
as well as well-formed transactions from dishonest peers (i.e. peers that do not
follow the same consensus rules).
BNS nodes do not directly communicate with one another---by design, the set of
BNS peers is not enumerable. The only shared communication medium between BNS
BNS peers is not enumerable. The only shared communication medium between BNS
peers is the blockchain.
To identify and reject invalid and malicious transactions without the blockchain's help,
the log of name operations embedded in the blockchain is constructed as a
[fork\*-consistent](http://www.scs.stanford.edu/~jinyuan/bft2f.pdf) database
log. Fork\*-consistency is a [consistency
log. Fork\*-consistency is a [consistency
model](https://en.wikipedia.org/wiki/Consistency_model) whereby the state
replicas in all of the nodes exhibit the following properties:
* Each correct peer maintains a history of well-formed, valid state operations. In this
- Each correct peer maintains a history of well-formed, valid state operations. In this
case, each correct BNS node maintains a copy of the history blockchain transactions
that encoded well-formed, valid name operations.
that encoded well-formed, valid name operations.
* Each honest peer's history contains the sequence of all operations that it
sent. That is, a user's BNS peer's transaction log will contain the sequence of all valid
transactions that the user's client wrote to the blockchain.
- Each honest peer's history contains the sequence of all operations that it
sent. That is, a user's BNS peer's transaction log will contain the sequence of all valid
transactions that the user's client wrote to the blockchain.
* If two peers accept operations *op* and *op'* from the same correct client,
then both of their logs will have the both operations in the same order. If
*op'* was accepted before *op*, then both peers' logs are identical up to *op'*.
In BNS, this means that if two peers both accept a given transaction, then it
means that they have accepted the same sequence of prior transactions.
- If two peers accept operations _op_ and _op'_ from the same correct client,
then both of their logs will have the both operations in the same order. If
_op'_ was accepted before _op_, then both peers' logs are identical up to _op'_.
In BNS, this means that if two peers both accept a given transaction, then it
means that they have accepted the same sequence of prior transactions.
This means that unlike with blockchains,
there can be *multiple long-lived conflicting forks* of the BNS database log.
However, due to fork\*-consistency, a correct BNS peer will only process *one*
of these forks, and will *ignore* transactions from peers in other forks. In other words,
there can be _multiple long-lived conflicting forks_ of the BNS database log.
However, due to fork\*-consistency, a correct BNS peer will only process _one_
of these forks, and will _ignore_ transactions from peers in other forks. In other words,
fork\*-consistency partitions the set of BNS peers into different **fork-sets**,
where all peers in a fork-set process each other's transactions, but the
completely ignore peers in other fork-sets.
BNS nodes identify which fork set they belong to using a **consensus hash**. The
BNS nodes identify which fork set they belong to using a **consensus hash**. The
consensus hash is a cryptographic digest of a node's operation
history. Each BNS peer calculates a new consensus hash each time it processes a
history. Each BNS peer calculates a new consensus hash each time it processes a
new block, and stores the history of consensus hashes for each block it
processed.
Two honest BNS peers can quickly determine if they are in the same fork-set by querying
each other's consensus hashes for a given block. If they match, then they are
each other's consensus hashes for a given block. If they match, then they are
in the same fork-set (assming no hash collisions).
A BNS client executes a name operation on a specific fork-set by including a
@ -71,7 +71,7 @@ the [transaction wire format]({{ site.baseurl }}/core/wire-format.html) document
The blockchain linearizes the history of transactions, which means that
in general, there exists a fork-set for each distinct set of BNS
consensus rules. For example, the Stacks Blockchain [2016 hard fork](https://github.com/blockstack/blockstack-core/blob/master/release_notes/changelog-0.14.md)
consensus rules. For example, the Stacks Blockchain [2016 hard fork](https://github.com/blockstack/blockstack-core/blob/master/release_notes/changelog-0.14.md)
and [2017 hard fork](https://github.com/blockstack/blockstack-core/blob/master/release_notes/changelog-0.17.md) both introduced new consensus
rules, which means at the time of this writing there are three possible fork-sets:
the pre-2016 fork-set, the 2016-2017 fork-set, and the post-2017 fork-set.
@ -82,31 +82,31 @@ BNS clients are incentivized to communicate with peers in the fork-set that has
the most use, since this fork-set's name database will encode name/state
bindings that are the most widely-accepted and understood by users.
To identify this fork-set, a BNS client needs to learn one of
its recent consensus hashes. Once it has a recent consensus hash, it can
query an *untrusted* BNS node for a copy of
its recent consensus hashes. Once it has a recent consensus hash, it can
query an _untrusted_ BNS node for a copy of
its name database, and use the consensus hash to verify that the name database
was used to generate it.
How does a BNS node determine whether or not a consensus hash corresponds to the
most widely-used fork-set? There are two strategies:
most widely-used fork-set? There are two strategies:
* Determine whether or not a *characteristic transaction* was accepted by the
widely-used fork-set. If a client knows that a specific transaction belongs to
the widely-used fork-set and not others, then they can use the consensus hash to
efficiently determine whether or not a given node belongs to this fork-set.
- Determine whether or not a _characteristic transaction_ was accepted by the
widely-used fork-set. If a client knows that a specific transaction belongs to
the widely-used fork-set and not others, then they can use the consensus hash to
efficiently determine whether or not a given node belongs to this fork-set.
* Determine how much "economic activity" exists in a fork-set by inspecting
the blockchain for burned cryptocurrency tokens. Namespace and name
registrations are structured in a way that sends cryptocurrency tokens to either
a well-known burn address, or to an easily-queried pay-to-namespace-creator
address.
- Determine how much "economic activity" exists in a fork-set by inspecting
the blockchain for burned cryptocurrency tokens. Namespace and name
registrations are structured in a way that sends cryptocurrency tokens to either
a well-known burn address, or to an easily-queried pay-to-namespace-creator
address.
Both strategies rely on the fact that the consensus hash is calculated as a
[Merkle skip-list](https://github.com/blockstack/blockstack-core/issues/146)
over the BNS node's accepted transactions. A client can use a consensus hash to
determine whether or not a transaction *T* was accepted by a node with *O(log
n)* time and space complexity. We call the protocol for resolving a consensus hash to a specific transaction
**Simplified Name Verification** (SNV). See our [paper on the subject](https://blockstack.org/virtualchain_dccl16.pdf)
over the BNS node's accepted transactions. A client can use a consensus hash to
determine whether or not a transaction _T_ was accepted by a node with _O(log
n)_ time and space complexity. We call the protocol for resolving a consensus hash to a specific transaction
**Simplified Name Verification** (SNV). See our [paper on the subject](https://blockstack.org/virtualchain_dccl16.pdf)
for details of how SNV works under the hood.
If the client has a consensus hash and knows of a characteristic transaction in the widely-used fork-set,
@ -114,13 +114,13 @@ it can use SNV to determine whether or not a node belongs to the fork-set that a
If the client knows about multiple conflicting consensus hashes,
they can still use SNV to determine which one corresponds
to the most-used fork-set. To do so, the client would use a
to the most-used fork-set. To do so, the client would use a
[blockchain explorer](https://explorer.blockstack.org) to find the
list of transactions that burned cryptocurrency tokens. Each of these
list of transactions that burned cryptocurrency tokens. Each of these
transactions will be treated as potential characteristic transactions:
the client would first select the subset of transactions that are well-formed
BNS transactions, and then use SNV to determine which of them correspond to which
consensus hashes. The client chooses the consensus hash that corresponds
consensus hashes. The client chooses the consensus hash that corresponds
to the fork-set with the highest cumulative burn.
Work is currently underway to automate this process.

155
src/pages/core/naming/introduction.md

@ -1,5 +1,5 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Blockstack Naming Service (BNS)
@ -17,124 +17,125 @@ to off-chain state without relying on any central points of control.
It does so by embedding a log of its control-plane messages within a public blockchain, like Bitcoin.
Each BNS peer determines the state of each name by indexing these specially-crafted
transactions. In doing so, each peer independently calculates the same global
transactions. In doing so, each peer independently calculates the same global
name state.
Names in BNS have three properties:
* **Names are globally unique.** The protocol does not allow name collisions, and all
- **Names are globally unique.** The protocol does not allow name collisions, and all
well-behaved nodes resolve a given name to the same state.
* **Names are human-meaningful.** Each name is chosen by its creator.
* **Names are strongly-owned.** Only the name's owner can change the state it
resolves to. Specifically, a name is owned by one or more ECDSA private keys.
- **Names are human-meaningful.** Each name is chosen by its creator.
- **Names are strongly-owned.** Only the name's owner can change the state it
resolves to. Specifically, a name is owned by one or more ECDSA private keys.
Internally, a BNS node implements a replicated name database. Each BNS node keeps itself
Internally, a BNS node implements a replicated name database. Each BNS node keeps itself
synchronized to all of the other ones in the world, so queries on one BNS node
will be the same on other nodes. BNS nodes allow a name's owner to bind
will be the same on other nodes. BNS nodes allow a name's owner to bind
up to 40Kb of off-chain state to their name, which will be replicated to all
BNS nodes via the [Atlas network]({{ site.baseurl }}/core/atlas/overview.html).
BNS nodes extract the name database log from an underlying blockchain (Blockstack
Core currently uses Bitcoin, and had used Namecoin in the past).
BNS uses the blockchain to establish a shared "ground truth" for the system: as long as
BNS uses the blockchain to establish a shared "ground truth" for the system: as long as
two nodes have the same view of the blockchain, then they will build up the same
database.
The biggest consequence for developers is that in BNS, reading name state is
fast and cheap but writing name state is slow and expensive. This is because
fast and cheap but writing name state is slow and expensive. This is because
registering and modifying names requires one or more transactions to be sent to
the underlying blockchain, and BNS nodes will not process them until they are
sufficiently confirmed. Users and developers need to acquire and spend
sufficiently confirmed. Users and developers need to acquire and spend
the requisite cryptocurrency (i.e. Bitcoin) to send BNS transactions.
## Motivation behind naming services
We rely on naming systems in everyday life, and they play a critical
role in many different applications. For example, when you look up a
role in many different applications. For example, when you look up a
friend on social media, you are using the platform's naming service to resolve
their name to their profile. When you look up a website, you are using the
their name to their profile. When you look up a website, you are using the
Domain Name Service to
resolve the hostname to its host's IP address. When you check out a Git branch, you
resolve the hostname to its host's IP address. When you check out a Git branch, you
are using your Git client to resolve the branch name to a commit hash.
When you look up someone's PGP key on a keyserver, you are resolving
their key ID to their public key.
What kinds of things do we want to be true about names? In BNS, names are
What kinds of things do we want to be true about names? In BNS, names are
globally unique, names are human-meaningful, and names are strongly-owned.
However, if you look at these examples, you'll see that each of them only
guarantees *two* of these properties. This limits how useful they can be.
* In DNS and social media, names are globally unique and human-readable, but not
strongly-owned. The system operator has the
final say as to what each names resolves to.
* **Problem**: Clients must trust the system to make the right
choice in what a given name resolves to. This includes trusting that
no one but the system administrators can make these changes.
* In Git, branch names are human-meaningful
and strongly-owned, but not globally unique. Two different Git nodes may resolve the same
branch name to different unrelated repository states.
* **Problem**: Since names can refer to conflicting state, developers
have to figure out some other mechanism to resolve ambiguities. In Git's
case, the user has to manually intervene.
* In PGP, names are key IDs. They are
are globally unique and cryptographically owned, but not human-readable. PGP
key IDs are derived from the keys they reference.
* **Problem**: These names are difficult for most users to
remember since they do not carry semantic information relating to their use in the system.
BNS names have all three properties, and none of these problems. This makes it a
powerful tool for building all kinds of network applications. With BNS, we
guarantees _two_ of these properties. This limits how useful they can be.
- In DNS and social media, names are globally unique and human-readable, but not
strongly-owned. The system operator has the
final say as to what each names resolves to.
- **Problem**: Clients must trust the system to make the right
choice in what a given name resolves to. This includes trusting that
no one but the system administrators can make these changes.
- In Git, branch names are human-meaningful
and strongly-owned, but not globally unique. Two different Git nodes may resolve the same
branch name to different unrelated repository states.
- **Problem**: Since names can refer to conflicting state, developers
have to figure out some other mechanism to resolve ambiguities. In Git's
case, the user has to manually intervene.
- In PGP, names are key IDs. They are
are globally unique and cryptographically owned, but not human-readable. PGP
key IDs are derived from the keys they reference.
- **Problem**: These names are difficult for most users to
remember since they do not carry semantic information relating to their use in the system.
BNS names have all three properties, and none of these problems. This makes it a
powerful tool for building all kinds of network applications. With BNS, we
can do the following and more:
* Build domain name services where hostnames can't be hijacked.
* Build social media platforms where user names can't be stolen by phishers.
* Build version control systems where repository branches do not conflict.
* Build public-key infrastructure where it's easy for users to discover and
- Build domain name services where hostnames can't be hijacked.
- Build social media platforms where user names can't be stolen by phishers.
- Build version control systems where repository branches do not conflict.
- Build public-key infrastructure where it's easy for users to discover and
remember each other's keys.
# Organization of BNS
BNS names are organized into a global name hierarchy. There are three different
BNS names are organized into a global name hierarchy. There are three different
layers in this hierarchy related to naming:
* **Namespaces**. These are the top-level names in the hierarchy. An analogy
to BNS namespaces are DNS top-level domains. Existing BNS namespaces include
`.id`, `.podcast`, and `.helloworld`. All other names belong to exactly one
namespace. Anyone can create a namespace, but in order for the namespace
to be persisted, it must be *launched* so that anyone can register names in it.
Namespaces are not owned by their creators.
* **BNS names**. These are names whose records are stored directly on the
blockchain. The ownership and state of these names are controlled by sending
blockchain transactions. Example names include `verified.podcast` and
`muneeb.id`. Anyone can create a BNS name, as long as the namespace that
contains it exists already. The state for BNS names is usually stored in the [Atlas
network]({{ site.baseurl }}/core/atlas/overview.html).
* **BNS subdomains**. These are names whose records are stored off-chain,
but are collectively anchored to the blockchain. The ownership and state for
these names lives within the [Atlas network]({{ site.baseurl }}/core/atlas/overview.html). While BNS
subdomains are owned by separate private keys, a BNS name owner must
broadcast their subdomain state. Example subdomains include `jude.personal.id`
and `podsaveamerica.verified.podcast`. Unlike BNS namespaces and names, the
state of BNS subdomains is *not* part of the blockchain consensus rules.
- **Namespaces**. These are the top-level names in the hierarchy. An analogy
to BNS namespaces are DNS top-level domains. Existing BNS namespaces include
`.id`, `.podcast`, and `.helloworld`. All other names belong to exactly one
namespace. Anyone can create a namespace, but in order for the namespace
to be persisted, it must be _launched_ so that anyone can register names in it.
Namespaces are not owned by their creators.
- **BNS names**. These are names whose records are stored directly on the
blockchain. The ownership and state of these names are controlled by sending
blockchain transactions. Example names include `verified.podcast` and
`muneeb.id`. Anyone can create a BNS name, as long as the namespace that
contains it exists already. The state for BNS names is usually stored in the [Atlas
network]({{ site.baseurl }}/core/atlas/overview.html).
- **BNS subdomains**. These are names whose records are stored off-chain,
but are collectively anchored to the blockchain. The ownership and state for
these names lives within the [Atlas network]({{ site.baseurl }}/core/atlas/overview.html). While BNS
subdomains are owned by separate private keys, a BNS name owner must
broadcast their subdomain state. Example subdomains include `jude.personal.id`
and `podsaveamerica.verified.podcast`. Unlike BNS namespaces and names, the
state of BNS subdomains is _not_ part of the blockchain consensus rules.
A feature comparison matrix summarizing the similarities and differences
between these name objects is presented below:
| Feature | **Namespaces** | **BNS names** | **BNS Subdomains** |
|---------|----------------|---------------|--------------------|
| Globally unique | X | X | X |
| Human-meaningful | X | X | X |
| Owned by a private key | | X | X |
| Anyone can create | X | X | [1] |
| Owner can update | | X | [1] |
| State hosted on-chain | X | X | |
| State hosted off-chain | | X | X |
| Behavior controlled by consensus rules | X | X | |
| May have an expiration date | | X | |
| Feature | **Namespaces** | **BNS names** | **BNS Subdomains** |
| -------------------------------------- | -------------- | ------------- | ------------------ |
| Globally unique | X | X | X |
| Human-meaningful | X | X | X |
| Owned by a private key | | X | X |
| Anyone can create | X | X | [1] |
| Owner can update | | X | [1] |
| State hosted on-chain | X | X | |
| State hosted off-chain | | X | X |
| Behavior controlled by consensus rules | X | X | |
| May have an expiration date | | X | |
[1] Requires the cooperation of a BNS name owner to broadcast its transactions

55
src/pages/core/naming/manage.md

@ -1,6 +1,7 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Manage BNS Names
This section teaches you how to manage your namespace, it contains the
@ -10,19 +11,19 @@ following sections:
Once you register a BNS name, you have the power to change its zone file hash,
change its public key hash, destroy it (i.e. render it unresolvable),
or renew it. The BNS consensus rules ensure that *only* you, as the owner of
or renew it. The BNS consensus rules ensure that _only_ you, as the owner of
the name's private key, have the ability to carry out these operations.
Each of these operations are executed by sending a specially-formatted
blockchain transaction to the blockchain, which BNS nodes read and process.
The operations are listed below:
| Transaction Type | Description |
|------------------|-------------|
| `NAME_UPDATE` | This changes the name's zone file hash. Any 20-byte string is allowed. |
| `NAME_TRANSFER` | This changes the name's public key hash. In addition, the current owner has the option to atomically clear the name's zone file hash (so the new owner won't "receive" the zone file). |
| `NAME_REVOKE` | This renders a name unresolvable. You should do this if your private key is compromised. |
| `NAME_RENEWAL` | This pushes back the name's expiration date (if it has one), and optionally both sets a new zone file hash and a new public key hash. |
| Transaction Type | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NAME_UPDATE` | This changes the name's zone file hash. Any 20-byte string is allowed. |
| `NAME_TRANSFER` | This changes the name's public key hash. In addition, the current owner has the option to atomically clear the name's zone file hash (so the new owner won't "receive" the zone file). |
| `NAME_REVOKE` | This renders a name unresolvable. You should do this if your private key is compromised. |
| `NAME_RENEWAL` | This pushes back the name's expiration date (if it has one), and optionally both sets a new zone file hash and a new public key hash. |
The reference BNS clients---
[blockstack.js](https://github.com/blockstack/blockstack.js) and the [Blockstack
@ -31,23 +32,23 @@ and sending all of these transactions for you.
## NAME_UPDATE ([live example](https://www.blocktrail.com/BTC/tx/e2029990fa75e9fc642f149dad196ac6b64b9c4a6db254f23a580b7508fc34d7))
A `NAME_UPDATE` transaction changes the name's zone file hash. You would send
A `NAME_UPDATE` transaction changes the name's zone file hash. You would send
one of these transactions if you wanted to change the name's zone file contents.
For example, you would do this if you want to deploy your own [Gaia
hub](https://github.com/blockstack/gaia) and want other people to read from it.
A `NAME_UPDATE` transaction is generated from the name, a recent [consensus
hash](#bns-forks), and the new zone file hash. The reference clients gather
this information automatically. See the [transaction format]({{ site.baseurl }}/core/wire-format.html)
hash](#bns-forks), and the new zone file hash. The reference clients gather
this information automatically. See the [transaction format]({{ site.baseurl }}/core/wire-format.html)
document for details on how to construct this transaction.
## NAME_TRANSFER ([live example](https://www.blocktrail.com/BTC/tx/7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24))
A `NAME_TRANSFER` transaction changes the name's public key hash. You would
A `NAME_TRANSFER` transaction changes the name's public key hash. You would
send one of these transactions if you wanted to:
* Change your private key
* Send the name to someone else
- Change your private key
- Send the name to someone else
When transferring a name, you have the option to also clear the name's zone
file hash (i.e. set it to `null`).
@ -55,42 +56,42 @@ This is useful for when you send the name to someone else, so the
recipient's name does not resolve to your zone file.
The `NAME_TRANSFER` transaction is generated from the name, a recent [consensus
hash](#bns-forks), and the new public key hash. The reference clients gather
this information automatically. See the [transaction format]({{ site.baseurl }}/core/wire-format.html)
hash](#bns-forks), and the new public key hash. The reference clients gather
this information automatically. See the [transaction format]({{ site.baseurl }}/core/wire-format.html)
document for details on how to construct this transaction.
## NAME_REVOKE ([live example](https://www.blocktrail.com/BTC/tx/eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f))
A `NAME_REVOKE` transaction makes a name unresolvable. The BNS consensus rules
A `NAME_REVOKE` transaction makes a name unresolvable. The BNS consensus rules
stipulate that once a name is revoked, no one can change its public key hash or
its zone file hash. The name's zone file hash is set to `null` to prevent it
its zone file hash. The name's zone file hash is set to `null` to prevent it
from resolving.
You should only do this if your private key is compromised, or if you want to
render your name unusable for whatever reason. It is rarely used in practice.
render your name unusable for whatever reason. It is rarely used in practice.
The `NAME_REVOKE` operation is generated using only the name. See the
The `NAME_REVOKE` operation is generated using only the name. See the
[transaction format]({{ site.baseurl }}/core/wire-format.html) document for details on how to construct
it.
## NAME_RENEWAL ([live example](https://www.blocktrail.com/BTC/tx/e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65))
Depending in the namespace rules, a name can expire. For example, names in the
`.id` namespace expire after 2 years. You need to send a `NAME_RENEWAL` every
Depending in the namespace rules, a name can expire. For example, names in the
`.id` namespace expire after 2 years. You need to send a `NAME_RENEWAL` every
so often to keep your name.
A `NAME_RENEWAL` costs both transaction fees and registration fees. You will
A `NAME_RENEWAL` costs both transaction fees and registration fees. You will
pay the registration cost of your name to the namespace's designated burn address when you
renew it. You can find this fee using the `/v1/prices/names/{name}` endpoint.
renew it. You can find this fee using the `/v1/prices/names/{name}` endpoint.
When a name expires, it enters a month-long "grace period" (5000 blocks). It
When a name expires, it enters a month-long "grace period" (5000 blocks). It
will stop resolving in the grace period, and all of the above operations will
cease to be honored by the BNS consensus rules. You may, however, send a
cease to be honored by the BNS consensus rules. You may, however, send a
`NAME_RENEWAL` during this grace period to preserve your name.
If your name is in a namespace where names do not expire, then you never need to
use this transaction.
When you send a `NAME_RENEWAL`, you have the option of also setting a new public
key hash and a new zone file hash. See the [transaction format]({{ site.baseurl }}/core/wire-format.html)
key hash and a new zone file hash. See the [transaction format]({{ site.baseurl }}/core/wire-format.html)
document for details on how to construct this transaction.

89
src/pages/core/naming/namespaces.md

@ -1,5 +1,5 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Understand Namespaces
@ -7,24 +7,25 @@ description: "Blockstack naming service (BNS)"
Namespaces are the top-level naming objects in BNS.
They control a few properties about the names within them:
* How expensive they are to register
* How long they last before they have to be renewed
* Who (if anyone) receives the name registration fees
* Who is allowed to seed the namespace with its initial names.
- How expensive they are to register
- How long they last before they have to be renewed
- Who (if anyone) receives the name registration fees
- Who is allowed to seed the namespace with its initial names.
At the time of this writing, by far the largest BNS namespace is the `.id`
namespace. Names in the `.id` namespace are meant for resolving user
identities. Short names in `.id` are more expensive than long names, and have
to be renewed by their owners every two years. Name registration fees are not
namespace. Names in the `.id` namespace are meant for resolving user
identities. Short names in `.id` are more expensive than long names, and have
to be renewed by their owners every two years. Name registration fees are not
paid to anyone in particular---they are instead sent to a "black hole" where
they are rendered unspendable (the intention is to discourage ID squatters).
Unlike DNS, *anyone* can create a namespace and set its properties. Namespaces
Unlike DNS, _anyone_ can create a namespace and set its properties. Namespaces
are created on a first-come first-serve basis, and once created, they last
forever.
However, creating a namespace is not free. The namespace creator must *burn*
cryptocurrency to do so. The shorter the namespace, the more cryptocurrency
However, creating a namespace is not free. The namespace creator must _burn_
cryptocurrency to do so. The shorter the namespace, the more cryptocurrency
must be burned (i.e. short namespaces are more valuable than long namespaces).
For example, it cost Blockstack PBC 40 BTC to create the `.id` namespace in 2015
(in transaction
@ -35,44 +36,44 @@ characters `a-z`, `0-9`, `-`, and `_`.
## Namespace Organization
BNS names are organized into a global name hierarchy. There are three different
BNS names are organized into a global name hierarchy. There are three different
layers in this hierarchy related to naming:
* **Namespaces**. These are the top-level names in the hierarchy. An analogy
to BNS namespaces are DNS top-level domains. Existing BNS namespaces include
`.id`, `.podcast`, and `.helloworld`. All other names belong to exactly one
namespace. Anyone can create a namespace, but in order for the namespace
to be persisted, it must be *launched* so that anyone can register names in it.
Namespaces are not owned by their creators.
* **BNS names**. These are names whose records are stored directly on the
blockchain. The ownership and state of these names are controlled by sending
blockchain transactions. Example names include `verified.podcast` and
`muneeb.id`. Anyone can create a BNS name, as long as the namespace that
contains it exists already. The state for BNS names is usually stored in the [Atlas
network]({{ site.baseurl }}/core/atlas/overview.html).
* **BNS subdomains**. These are names whose records are stored off-chain,
but are collectively anchored to the blockchain. The ownership and state for
these names lives within the [Atlas network]({{ site.baseurl }}/core/atlas/overview.html). While BNS
subdomains are owned by separate private keys, a BNS name owner must
broadcast their subdomain state. Example subdomains include `jude.personal.id`
and `podsaveamerica.verified.podcast`. Unlike BNS namespaces and names, the
state of BNS subdomains is *not* part of the blockchain consensus rules.
- **Namespaces**. These are the top-level names in the hierarchy. An analogy
to BNS namespaces are DNS top-level domains. Existing BNS namespaces include
`.id`, `.podcast`, and `.helloworld`. All other names belong to exactly one
namespace. Anyone can create a namespace, but in order for the namespace
to be persisted, it must be _launched_ so that anyone can register names in it.
Namespaces are not owned by their creators.
- **BNS names**. These are names whose records are stored directly on the
blockchain. The ownership and state of these names are controlled by sending
blockchain transactions. Example names include `verified.podcast` and
`muneeb.id`. Anyone can create a BNS name, as long as the namespace that
contains it exists already. The state for BNS names is usually stored in the [Atlas
network]({{ site.baseurl }}/core/atlas/overview.html).
- **BNS subdomains**. These are names whose records are stored off-chain,
but are collectively anchored to the blockchain. The ownership and state for
these names lives within the [Atlas network]({{ site.baseurl }}/core/atlas/overview.html). While BNS
subdomains are owned by separate private keys, a BNS name owner must
broadcast their subdomain state. Example subdomains include `jude.personal.id`
and `podsaveamerica.verified.podcast`. Unlike BNS namespaces and names, the
state of BNS subdomains is _not_ part of the blockchain consensus rules.
A feature comparison matrix summarizing the similarities and differences
between these name objects is presented below:
| Feature | **Namespaces** | **BNS names** | **BNS Subdomains** |
|---------|----------------|---------------|--------------------|
| Globally unique | X | X | X |
| Human-meaningful | X | X | X |
| Owned by a private key | | X | X |
| Anyone can create | X | X | [1] |
| Owner can update | | X | [1] |
| State hosted on-chain | X | X | |
| State hosted off-chain | | X | X |
| Behavior controlled by consensus rules | X | X | |
| May have an expiration date | | X | |
| Feature | **Namespaces** | **BNS names** | **BNS Subdomains** |
| -------------------------------------- | -------------- | ------------- | ------------------ |
| Globally unique | X | X | X |
| Human-meaningful | X | X | X |
| Owned by a private key | | X | X |
| Anyone can create | X | X | [1] |
| Owner can update | | X | [1] |
| State hosted on-chain | X | X | |
| State hosted off-chain | | X | X |
| Behavior controlled by consensus rules | X | X | |
| May have an expiration date | | X | |
[1] Requires the cooperation of a BNS name owner to broadcast its transactions

84
src/pages/core/naming/pickname.md

@ -1,5 +1,5 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Choose a name
@ -10,22 +10,22 @@ following sections:
## Intended uses for a namespace
The intention is that each application can create its own BNS
namespace for its own purposes. Applications can use namespaces for things like:
namespace for its own purposes. Applications can use namespaces for things like:
* Giving users a SSO system, where each user registers their public key under a
username. Blockstack applications do this with names in the `.id` namespace,
for example.
- Giving users a SSO system, where each user registers their public key under a
username. Blockstack applications do this with names in the `.id` namespace,
for example.
* Providing a subscription service, where each name is a 3rd party that provides
a service for users to subscribe to. For example, names in
`.podcast` point to podcasts that users of the [DotPodcast](https://dotpodcast.co) app can subscribe to.
* Implementing software licenses, where each name corresponds to an access key.
- Providing a subscription service, where each name is a 3rd party that provides
a service for users to subscribe to. For example, names in
`.podcast` point to podcasts that users of the [DotPodcast](https://dotpodcast.co) app can subscribe to.
- Implementing software licenses, where each name corresponds to an access key.
Unlike conventional access keys, access keys implemented as names
can be sold and traded independently. The licensing fee (paid as a name
registration) would be set by the developer and sent to a developer-controlled
blockchain address.
can be sold and traded independently. The licensing fee (paid as a name
registration) would be set by the developer and sent to a developer-controlled
blockchain address.
Names within a namespace can serve any purpose the developer wants. The ability
Names within a namespace can serve any purpose the developer wants. The ability
to collect registration fees for 1 year after creating the namespace not only
gives developers the incentive to get users to participate in the app, but also
gives them a way to measure economic activity.
@ -95,60 +95,60 @@ $ curl -sL https://core.blockstack.org/v1/blockchains/bitcoin/consensus
}
```
A recent consensus hash is required to create a `NAMESPACE_PREORDER` transaction. The reference
BNS clients do this automatically. See the [transaction format]({{ site.baseurl }}/core/wire-format.html)
A recent consensus hash is required to create a `NAMESPACE_PREORDER` transaction. The reference
BNS clients do this automatically. See the [transaction format]({{ site.baseurl }}/core/wire-format.html)
document for details on how the consensus hash is used to construct the
transaction.
## Create a namespace
There are four steps to creating a namespace:
There are four steps to creating a namespace:
1. **Send a `NAMESPACE_PREORDER` transaction** ([live example](https://www.blocktrail.com/BTC/tx/5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28)).
This is the first step. This registers the *salted hash* of the namespace with BNS nodes, and burns the
requisite amount of cryptocurrency. In addition, it proves to the
BNS nodes that user has honored the BNS consensus rules by including
a recent *consensus hash* in the transaction
(see the section on [BNS forks](#bns-forks) for details).
This is the first step. This registers the _salted hash_ of the namespace with BNS nodes, and burns the
requisite amount of cryptocurrency. In addition, it proves to the
BNS nodes that user has honored the BNS consensus rules by including
a recent _consensus hash_ in the transaction
(see the section on [BNS forks](#bns-forks) for details).
2. **Send a `NAMESPACE_REVEAL` transaction** ([live example](https://www.blocktrail.com/BTC/tx/ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32)).
This is the second step. This reveals the salt and the namespace ID (pairing it with its
`NAMESPACE_PREORDER`), it reveals how long names last in this namespace before
they expire or must be renewed, and it sets a *price function* for the namespace
that determines how cheap or expensive names its will be. The price function takes
a name in this namespace as input, and outputs the amount of cryptocurrency the
name will cost (i.e. by examining how long the name is, and whether or not it
has any vowels or non-alphabet characters). The namespace creator
has the option to collect name registration fees for the first year of the
namespace's existence by setting a *namespace creator address*.
This is the second step. This reveals the salt and the namespace ID (pairing it with its
`NAMESPACE_PREORDER`), it reveals how long names last in this namespace before
they expire or must be renewed, and it sets a _price function_ for the namespace
that determines how cheap or expensive names its will be. The price function takes
a name in this namespace as input, and outputs the amount of cryptocurrency the
name will cost (i.e. by examining how long the name is, and whether or not it
has any vowels or non-alphabet characters). The namespace creator
has the option to collect name registration fees for the first year of the
namespace's existence by setting a _namespace creator address_.
3. **Seed the namespace with `NAME_IMPORT` transactions** ([live example](https://www.blocktrail.com/BTC/tx/c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312)).
Once the namespace has been revealed, the user has the option to populate it with a set of
names. Each imported name is given both an owner and some off-chain state.
This step is optional---namespace creators are not required to import names.
Once the namespace has been revealed, the user has the option to populate it with a set of
names. Each imported name is given both an owner and some off-chain state.
This step is optional---namespace creators are not required to import names.
4. **Send a `NAMESPACE_READY` transaction** ([live example](https://www.blocktrail.com/BTC/tx/2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032)).
This is the final step of the process. It *launches* the namespace, which makes it available to the
public. Once a namespace is ready, anyone can register a name in it if they
pay the appropriate amount of cryptocurrency (according to the price funtion
revealed in step 2).
This is the final step of the process. It _launches_ the namespace, which makes it available to the
public. Once a namespace is ready, anyone can register a name in it if they
pay the appropriate amount of cryptocurrency (according to the price funtion
revealed in step 2).
The reason for the `NAMESPACE_PREORDER/NAMESPACE_REVEAL` pairing is to prevent
frontrunning. The BNS consensus rules require a `NAMESPACE_REVEAL` to be
frontrunning. The BNS consensus rules require a `NAMESPACE_REVEAL` to be
paired with a previous `NAMESPACE_PREORDER` sent within the past 24 hours.
If it did not do this, then a malicious actor could watch the blockchain network
and race a victim to claim a namespace.
Namespaces are created on a first-come first-serve basis. If two people try to
Namespaces are created on a first-come first-serve basis. If two people try to
create the same namespace, the one that successfully confirms both the
`NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` wins. The fee burned in the
`NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` wins. The fee burned in the
`NAMESPACE_PREORDER` is spent either way.
Once the user issues the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL`, they have
1 year before they must send the `NAMESPACE_READY` transaction. If they do not
1 year before they must send the `NAMESPACE_READY` transaction. If they do not
do this, then the namespace they created disappears (along with all the names
they imported).
Developers wanting to create their own namespaces should read the [namespace creation section](/core/naming/namespaces.html) document. It is highly recommended that
Developers wanting to create their own namespaces should read the [namespace creation section](/core/naming/namespaces.html) document. It is highly recommended that
developers request individual support before creating their own space, given the large amount of
cryptocurrency at stake.

62
src/pages/core/naming/register.md

@ -1,5 +1,5 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Register a name
@ -9,58 +9,58 @@ you can use to understandt the cost of namespace registration.
## Understand registration
Registering a BNS name costs cryptocurrency. This cost comes from two sources:
Registering a BNS name costs cryptocurrency. This cost comes from two sources:
* **Transaction fees:** These are the fees imposed by the cost of storing the
transaction data to the blockchain itself. They are independent of BNS, since
all of the blockchain's users are competing to have their transactions included
in the next block. The blockchain's miners receive the transaction fee.
- **Transaction fees:** These are the fees imposed by the cost of storing the
transaction data to the blockchain itself. They are independent of BNS, since
all of the blockchain's users are competing to have their transactions included
in the next block. The blockchain's miners receive the transaction fee.
* **Registration fees:** Each BNS namespace imposes an *additional* fee on how
much a name costs. The registration fee is sent to the namespace creator
during the first year that a namespace exists, and is sent to a burn address
afterwards. The registration fee is different for each name and is
determined by the namespace itself, but can be queried in advance by the user.
- **Registration fees:** Each BNS namespace imposes an _additional_ fee on how
much a name costs. The registration fee is sent to the namespace creator
during the first year that a namespace exists, and is sent to a burn address
afterwards. The registration fee is different for each name and is
determined by the namespace itself, but can be queried in advance by the user.
Registering a name takes two transactions. They are:
Registering a name takes two transactions. They are:
* **`NAME_PREORDER` transaction**: This is the first transaction to be sent.
It tells all BNS nodes the *salted hash* of the BNS name, and it pays the
registration fee to the namespace owner's designated address (or the burn
address). In addition, it proves to the BNS nodes that the client knows about
the current state of the system by including a recent *consensus hash*
in the transaction (see the section on [BNS forks](#bns-forks) for details).
- **`NAME_PREORDER` transaction**: This is the first transaction to be sent.
It tells all BNS nodes the _salted hash_ of the BNS name, and it pays the
registration fee to the namespace owner's designated address (or the burn
address). In addition, it proves to the BNS nodes that the client knows about
the current state of the system by including a recent _consensus hash_
in the transaction (see the section on [BNS forks](#bns-forks) for details).
* **`NAME_REGISTRATION` transaction**: This is the second transaction to be
sent. It reveals the salt and the name to all BNS nodes, and assigns the name
an initial public key hash and zone file hash
- **`NAME_REGISTRATION` transaction**: This is the second transaction to be
sent. It reveals the salt and the name to all BNS nodes, and assigns the name
an initial public key hash and zone file hash
The reason this process takes two transactions is to prevent front-running.
The BNS consensus rules stipulate that a name can only be registered if its
matching preorder transaction was sent in the last 24 hours. Because a name
matching preorder transaction was sent in the last 24 hours. Because a name
must be preordered before it is registered, someone watching the blockchain's
peer network cannot race a victim to claim the name they were trying to
register (i.e. the attacker would have needed to send a `NAME_PREORDER`
transaction first, and would have had to have sent it no more than 24 hours
ago).
Registering a name on top of the Bitcoin blockchain takes 1-2 hours. This is
Registering a name on top of the Bitcoin blockchain takes 1-2 hours. This is
because you need to wait for the `NAME_PREORDER` transaction to be sufficiently
confirmed before sending the `NAME_REGISTRATION` transaction. The BNS nodes
confirmed before sending the `NAME_REGISTRATION` transaction. The BNS nodes
only register the name once both transactions have at least 6 confirmations
(which itself usually takes about an hour).
Names are registered on a first-come first-serve basis.
If two different people try to register the same name at the same time, the
person who completes the two-step process *earliest* will receive the name. The
person who completes the two-step process _earliest_ will receive the name. The
other person's `NAME_REGISTRATION` transaction will be ignored, since it will
not be considered valid at this point. The registration fee paid by the
`NAME_PREORDER` will be lost. However, this situation is rare in practice---
not be considered valid at this point. The registration fee paid by the
`NAME_PREORDER` will be lost. However, this situation is rare in practice---
as of early 2018, we only know of one confirmed instance in the system's 3+ years
of operation.
Fully-qualified names can be between 3 and 37 characters long, and consist of
the characters `a-z`, `0-9`, `+`, `-`, `_`, and `.`. This is to prevent
the characters `a-z`, `0-9`, `+`, `-`, `_`, and `.`. This is to prevent
[homograph attacks](https://en.wikipedia.org/wiki/IDN_homograph_attack).
`NAME_REGISTRATION` transactions that do not conform to this requirement will be
ignored.
@ -75,7 +75,7 @@ $ curl -sL https://core.blockstack.org/v1/prices/names/helloworld.id | jq -r ".n
}
```
Note the use of `jq -r` to select the `"name_price"` field. This API
Note the use of `jq -r` to select the `"name_price"` field. This API
endpoint may return other ancilliary data regarding transaction fee estimation,
but this is the only field guaranteed by this specification to be present.
@ -88,8 +88,8 @@ $ curl -sL https://core.blockstack.org/v1/blockchains/bitcoin/consensus
}
```
The consensus hash must be included in the `NAME_PREORDER` transaction. The BNS
clients do this automatically. See the [transaction format
The consensus hash must be included in the `NAME_PREORDER` transaction. The BNS
clients do this automatically. See the [transaction format
document]({{ site.baseurl }}/core/wire-format.html) for details as to how to include this in the
transaction.

50
src/pages/core/naming/resolving.md

@ -1,5 +1,5 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
## Resolve a name
@ -15,24 +15,24 @@ which contains routing information for discovering the user's Blockstack data
(such as their profile and app data, which are hosted in the [Gaia storage
system](https://github.com/blockstack/gaia)).
The blockchain is not used to store this information directly. Instead, the
blockchain stores the *public key hash* and the *zone file hash*. When
The blockchain is not used to store this information directly. Instead, the
blockchain stores the _public key hash_ and the _zone file hash_. When
indexing the blockchain, each BNS node builds a database with
three columns: all the on-chain BNS names that have been registered, each
three columns: all the on-chain BNS names that have been registered, each
name's public key hash, and each name's zone file's hash.
In addition, each BNS node maintains the *transaction history* of each name.
In addition, each BNS node maintains the _transaction history_ of each name.
A developer can resolve a name to any configuration it was in at any prior
point in time.
Below is an example name table pulled from a live BNS node:
| Name | Public key hash | Zone File Hash |
|------|-----------------|--------------|
| `ryan.id` | `15BcxePn59Y6mYD2fRLCLCaaHScefqW2No` | `a455954b3e38685e487efa41480beeb315f4ec65` |
| `muneeb.id` | `1J3PUxY5uDShUnHRrMyU6yKtoHEUPhKULs` | `37aecf837c6ae9bdc9dbd98a268f263dacd00361` |
| `jude.id` | `16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg` | `b6e99200125e70d634b17fe61ce55b09881bfafd` |
| `verified.podcast` | `1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH` | `6701ce856620d4f2f57cd23b166089759ef6eabd` |
| `cicero.res_publica.id` | `1EtE77Aa5AA8etzF2irk56vvkS4v7rZ7PE` | `7e4ac75f9d79ba9d5d284fac19617497433b832d` |
| Name | Public key hash | Zone File Hash |
| --------------------------------- | ------------------------------------ | ------------------------------------------ |
| `ryan.id` | `15BcxePn59Y6mYD2fRLCLCaaHScefqW2No` | `a455954b3e38685e487efa41480beeb315f4ec65` |
| `muneeb.id` | `1J3PUxY5uDShUnHRrMyU6yKtoHEUPhKULs` | `37aecf837c6ae9bdc9dbd98a268f263dacd00361` |
| `jude.id` | `16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg` | `b6e99200125e70d634b17fe61ce55b09881bfafd` |
| `verified.podcast` | `1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH` | `6701ce856620d4f2f57cd23b166089759ef6eabd` |
| `cicero.res_publica.id` | `1EtE77Aa5AA8etzF2irk56vvkS4v7rZ7PE` | `7e4ac75f9d79ba9d5d284fac19617497433b832d` |
| `podsaveamerica.verified.podcast` | `1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH` | `0d6f090db8945aa0e60759f9c866b17645893a95` |
In practice, the zone file hash is the `RIPEMD160` hash of the `SHA256` hash of
@ -42,12 +42,12 @@ of the double-`SHA256` hash of the ECDSA public key (i.e. a Bitcoin address).
The BNS consensus rules ensure that
a BNS name can only be registered if it is not already taken, and that only the
user who owns the name's private key can change its public key hash or zone file
hash. This means that a name's public key and zone file can be stored anywhere,
hash. This means that a name's public key and zone file can be stored anywhere,
since they can be authenticated using the hashes discovered by indexing the
blockchain under the BNS consensus rules.
BNS nodes implement a decentralized storage system for zone files called the
[Atlas network]({{ site.baseurl }}/core/atlas/overview.html). In this system, BNS nodes eagerly replicate
[Atlas network]({{ site.baseurl }}/core/atlas/overview.html). In this system, BNS nodes eagerly replicate
all the zone files they know about to one another, so that eventually every BNS
node has a full replica of all zone files.
@ -55,7 +55,7 @@ The public keys for names are stored off-chain in [Gaia](https://github.com/bloc
The user controls where their public keys are hosted using the zone file
contents (if they are hosted online anywhere at all).
Developers can query this table via the BNS API. The API offers routes
Developers can query this table via the BNS API. The API offers routes
to do the following:
## Look up a name's public key and zone file ([reference](https://core.blockstack.org/#name-querying-get-name-info))
@ -99,7 +99,7 @@ $ curl https://core.blockstack.org/v1/names?page=0
]
```
Each page returns 100 names. While no specific ordering is mandated by the
Each page returns 100 names. While no specific ordering is mandated by the
protocol, the reference implementation orders names by their order of creation
in the blockchain.
@ -211,22 +211,22 @@ $ curl https://core.blockstack.org/v1/names/patrickstanley.id/history
}
```
All of the above information is extracted from the blockchain. Each top-level
All of the above information is extracted from the blockchain. Each top-level
field encodes the states the name transitioned to at the given block height (e.g.
445838, 445851, 445873, adn 445884). At each block height, the name's zone file
445838, 445851, 445873, adn 445884). At each block height, the name's zone file
hashes are returned in the order they were discovered in the blockchain.
Each name state contains a lot of ancillary data that is used internally by
other API calls and client libraries. The relevant fields for this document's
other API calls and client libraries. The relevant fields for this document's
scope are:
* `address`: This is the base58check-encoded public key hash.
* `name`: This is the name queried.
* `value_hash`: This is the zone file hash.
* `opcode`: This is the type of transaction that was processed.
* `txid`: This is the transaction ID in the underlying blockchain.
- `address`: This is the base58check-encoded public key hash.
- `name`: This is the name queried.
- `value_hash`: This is the zone file hash.
- `opcode`: This is the type of transaction that was processed.
- `txid`: This is the transaction ID in the underlying blockchain.
The name's *entire* history is returned. This includes the history of the name
The name's _entire_ history is returned. This includes the history of the name
under its previous owner, if the name expired and was reregistered.
## Look up the list of names owned by a given public key hash ([reference](https://core.blockstack.org/#name-querying-get-names-owned-by-address))

15
src/pages/core/naming/search.md

@ -1,5 +1,5 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# How to build a Profile Search Index
@ -12,8 +12,8 @@ be easily expanded to include other namespaces.
Currently there are two types of indexes to handle search queries:
* Substring search on usernames, full names, twitter_handle (powered by MongoDB)
* Raw Lucene index which handles searching extended data e.g., bio.
- Substring search on usernames, full names, twitter_handle (powered by MongoDB)
- Raw Lucene index which handles searching extended data e.g., bio.
Search will currently return upto a max of 20 results (can be less depending on the query)
with data that follows structure of [blockstack IDs](https://github.com/blockstack/blockstack):
@ -29,7 +29,8 @@ This document describes how to setup the search subsystem to respond at that end
# Installation
- **Step 1:** First, make sure you have [virtualenv installed](http://docs.python-guide.org/en/latest/dev/virtualenvs/).
Then, setup the API and search subsystem:
Then, setup the API and search subsystem:
```
$ sudo apt-get install -y mongodb memcached python-dev libmemcached-dev zlib1g-dev nginx
$ sudo pip install uwsgi
@ -41,8 +42,8 @@ $ sudo mkdir /var/blockstack-search && sudo chown $USER:$USER /var/blockstack-se
```
- **Step 2:** Make sure you have a Stacks Node running locally (see [instructions](https://github.com/blockstack/blockstack-core/blob/master/README.md#quick-start)). We highly
recommend using a local node because the search subsystem issues thousands of calls to
a Stacks Node for re-indexing and remote nodes can slow down performance.
recommend using a local node because the search subsystem issues thousands of calls to
a Stacks Node for re-indexing and remote nodes can slow down performance.
- **Step 3:** Fetch the data for the .id namespace and respective profiles. Note, you may want to redirect stderr to a file, as there is a lot of debug output.
@ -150,7 +151,7 @@ pip install -r requirements.txt
Elastic Search library is not in github and resides at unix/lib/elastic
the current version we're using is *0.90.2*. Download from:
the current version we're using is _0.90.2_. Download from:
> wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.90.2.zip

78
src/pages/core/naming/subdomains.md

@ -1,6 +1,7 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# BNS Subdomains
This section explains BNS subdomains and provides instructions for methods
@ -9,35 +10,35 @@ you can use to work with them. The following topics are included:
# Overview of subdomains
BNS names are strongly-owned because the owner of its private key can generate
valid transactions that update its zone file hash and owner. However, this comes at the
valid transactions that update its zone file hash and owner. However, this comes at the
cost of requiring a name owner to pay for the underlying transaction in the
blockchain. Moreover, this approach limits the rate of BNS name registrations
blockchain. Moreover, this approach limits the rate of BNS name registrations
and operations to the underlying blockchain's transaction bandwidth.
BNS overcomes this with subdomains. A **BNS subdomain** is a type of BNS name whose state
BNS overcomes this with subdomains. A **BNS subdomain** is a type of BNS name whose state
and owner are stored outside of the blockchain, but whose existence and
operation history are anchored to the
blockchain. In the example table in the [Resolving BNS
blockchain. In the example table in the [Resolving BNS
Names](#resolving-bns-names) section, the names `cicero.res_publica.id` and
`podsaveamerica.verified.podcast` are subdomains.
Like their on-chain counterparts, subdomains are globally
unique, strongly-owned, and human-readable. BNS gives them their own name state
unique, strongly-owned, and human-readable. BNS gives them their own name state
and public keys.
Unlike on-chain names, subdomains can be created and managed
cheaply, because they are broadcast to the
BNS network in batches. A single blockchain transaction can send up to 120
BNS network in batches. A single blockchain transaction can send up to 120
subdomain operations.
This is achieved by storing subdomain records in the [Atlas Network]({{ site.baseurl }}/core/atlas/overview.html).
An on-chain name owner broadcasts subdomain operations by encoding them as
`TXT` records within a DNS zone file. To broadcast the zone file,
`TXT` records within a DNS zone file. To broadcast the zone file,
the name owner sets the new zone file hash with a `NAME_UPDATE` transaction and
replicates the zone file via Atlas. This, in turn, replicates all subdomain
replicates the zone file via Atlas. This, in turn, replicates all subdomain
operations it contains, and anchors the set of subdomain operations to
an on-chain transaction. The BNS node's consensus rules ensure that only
valid subdomain operations from *valid* `NAME_UPDATE` transactions will ever be
an on-chain transaction. The BNS node's consensus rules ensure that only
valid subdomain operations from _valid_ `NAME_UPDATE` transactions will ever be
stored.
For example, the name `verified.podcast` once wrote the zone file hash `247121450ca0e9af45e85a82e61cd525cd7ba023`,
@ -80,9 +81,9 @@ file for `verified.podcast`.
## Subdomain Lifecycle
Note that `1yeardaily.verified.podcast` has a different public key
hash (address) than `verified.podcast`. A BNS node will only process a
hash (address) than `verified.podcast`. A BNS node will only process a
subsequent subdomain operation on `1yeardaily.verified.podcast` if it includes a
signature from this address's private key. `verified.podcast` cannot generate
signature from this address's private key. `verified.podcast` cannot generate
updates; only the owner of `1yeardaily.verified.podcast can do so`.
The lifecycle of a subdomain and its operations is shown in Figure 2.
@ -122,17 +123,17 @@ However, any on-chain name ("jude.id" in this case) can broadcast a subdomain
update for "cicero.res_publica.id".
```
Subdomain operations are ordered by sequence number, starting at 0. Each new
Subdomain operations are ordered by sequence number, starting at 0. Each new
subdomain operation must include:
* The next sequence number
* The public key that hashes to the previous subdomain transaction's address
* A signature from the corresponding private key over the entire subdomain
- The next sequence number
- The public key that hashes to the previous subdomain transaction's address
- A signature from the corresponding private key over the entire subdomain
operation.
If two correctly-signed but conflicting subdomain operations are discovered
(i.e. they have the same sequence number), the one that occurs earlier in the
blockchain's history is accepted. Invalid subdomain operations are ignored.
blockchain's history is accepted. Invalid subdomain operations are ignored.
Combined, this ensures that a BNS node with all of the zone files with a given
subdomain's operations will be able to determine the valid sequence of
@ -192,23 +193,24 @@ $ curl https://core.blockstack.org/v1/addresses/bitcoin/1PwztPFd1s2STMv4Ntq6UPBd
## Subdomain Creation and Management
Unlike an on-chain name, a subdomain owner needs an on-chain name owner's help
to broadcast their subdomain operations. In particular:
* A subdomain-creation transaction can only be processed by the owner of the on-chain
name that shares its suffix. For example, only the owner of `res_publica.id`
can broadcast subdomain-creation transactions for subdomain names ending in
`.res_publica.id`.
* A subdomain-transfer transaction can only be broadcast by the owner of the
on-chain name that created it. For example, the owner of
`cicero.res_publica.id` needs the owner of `res_publica.id` to broadcast a
subdomain-transfer transaction to change `cicero.res_publica.id`'s public key.
* In order to send a subdomain-creation or subdomain-transfer, all
to broadcast their subdomain operations. In particular:
- A subdomain-creation transaction can only be processed by the owner of the on-chain
name that shares its suffix. For example, only the owner of `res_publica.id`
can broadcast subdomain-creation transactions for subdomain names ending in
`.res_publica.id`.
- A subdomain-transfer transaction can only be broadcast by the owner of the
on-chain name that created it. For example, the owner of
`cicero.res_publica.id` needs the owner of `res_publica.id` to broadcast a
subdomain-transfer transaction to change `cicero.res_publica.id`'s public key.
- In order to send a subdomain-creation or subdomain-transfer, all
of an on-chain name owner's zone files must be present in the Atlas network.
This lets the BNS node prove the *absence* of any conflicting subdomain-creation and
subdomain-transfer operations when processing new zone files.
* A subdomain update transaction can be broadcast by *any* on-chain name owner,
but the subdomain owner needs to find one who will cooperate. For example,
the owner of `verified.podcast` can broadcast a subdomain-update transaction
created by the owner of `cicero.res_publica.id`.
This lets the BNS node prove the _absence_ of any conflicting subdomain-creation and
subdomain-transfer operations when processing new zone files.
- A subdomain update transaction can be broadcast by _any_ on-chain name owner,
but the subdomain owner needs to find one who will cooperate. For example,
the owner of `verified.podcast` can broadcast a subdomain-update transaction
created by the owner of `cicero.res_publica.id`.
That said, to create a subdomain, the subdomain owner generates a
subdomain-creation operation for their desired name
@ -217,26 +219,26 @@ The on-chain name owner then uses Atlas to
broadcast it to all other BNS nodes.
Once created, a subdomain owner can use any on-chain name owner to broadcast a
subdomain-update operation. To do so, they generate and sign the requisite
subdomain-update operation. To do so, they generate and sign the requisite
subdomain operation and give it to an on-chain name owner, who then packages it
with other subdomain operations into a DNS zone file
and sends them all out on the Atlas network.
If the subdomain owner wants to change the address of their subdomain, they need
to sign a subdomain-transfer operation and give it to the on-chain name owner
who created the subdomain. They then package it into a zone file and broadcast
who created the subdomain. They then package it into a zone file and broadcast
it.
## Subdomain Registrars
Because subdomain names are cheap, developers may be inclined to run
subdomain registrars on behalf of their applications. For example,
subdomain registrars on behalf of their applications. For example,
the name `personal.id` is used to register Blockstack application users without
requiring them to spend any Bitcoin.
We supply a reference
implementation of a [BNS Subdomain Registrar](https://github.com/blockstack/subdomain-registrar)
to help developers broadcast subdomain operations. Users would still own their
to help developers broadcast subdomain operations. Users would still own their
subdomain names; the registrar simply gives developers a convenient way for them
to register and manage them in the context of a particular application.
Please see the [tutorial on running a subdomain registrar]({{ site.baseurl }}/core/naming/tutorial_subdomains.html) for

35
src/pages/core/naming/tutorial_subdomains.md

@ -1,5 +1,5 @@
---
description: "Blockstack naming service (BNS)"
description: 'Blockstack naming service (BNS)'
---
# Subdomain Design and Implementation
@ -22,30 +22,29 @@ These names will be indicated with an `.`, e.g., `foo.bar.id`
We can do this today with a special indexer & resolver endpoint and
without any changes to the core protocol.
We can do this by having a zone file record for each subdomain *i*
We can do this by having a zone file record for each subdomain _i_
containing the following information:
1. An owner address *addr*
2. A sequence number *N*
1. An owner address _addr_
2. A sequence number _N_
3. A zonefile
4. A signature *S* of the above
4. A signature _S_ of the above
The signature *S_i* must be verifiable with the address in the
*(N-1)*th entry for subdomain *i*.
The signature _S_i_ must be verifiable with the address in the
*(N-1)*th entry for subdomain _i_.
## Zonefile Format
For now, the resolver will use an *TXT* record per subdomain to define
For now, the resolver will use an _TXT_ record per subdomain to define
this information. The entry name will be `$(subdomain)`.
We'll use the format of [RFC 1464](https://tools.ietf.org/html/rfc1464)
for the TXT entry. We'll have the following strings with identifiers:
1. **parts** : this specifies the number of pieces that the
zonefile has been chopped into. TXT strings can only be 255 bytes,
so we chop up the zonefile.
2. **zf{n}**: part *n* of the zonefile, base64 encoded
zonefile has been chopped into. TXT strings can only be 255 bytes,
so we chop up the zonefile.
2. **zf{n}**: part _n_ of the zonefile, base64 encoded
3. **owner**: the owner address delegated to operate the subdomain
4. **seqn**: the sequence number
5. **sig**: signature of the above data.
@ -133,13 +132,13 @@ On success, this returns `202` and the message
When the registrar wakes up to prepare a transaction, it packs the queued
registrations together and issues an `UPDATE`.
### Check subdomain registration status
A user can check on the registration status of their name via querying the
registrar.
This is an API call:
```
GET /status/{subdomain}
```
@ -179,17 +178,17 @@ When a lookup like `foo.bar.id` hits the resolver, the resolver will need to:
3. Verify that all `foo` operations are correct
4. Return the latest record for foo
5. Do a profile lookup for `foo.bar.id` by fetching the URLs in the entry.
*Note*, this spec does not define a priority order for fetching those URLs.
_Note_, this spec does not define a priority order for fetching those URLs.
### Supported Core / Resolver Endpoints
Generally, domain endpoints are not aware of subdomains (only endpoints
aware of subdomains is `/v1/users/<foo.bar.tld>`,
`/v1/names/<foo.bar.tld>`, and `/v1/addresses/bitcoin/<foo.bar.tld>`)
The endpoints which *are* subdomain aware are marked as such in
The endpoints which _are_ subdomain aware are marked as such in
[api-specs.md].
This means that search is *not* yet supported.
This means that search is _not_ yet supported.
The lookups work just like normal -- it returns the user's
profile object:
@ -240,7 +239,7 @@ $ curl -H "Authorization: bearer XXXX" -H "Origin: http://localhost:3000" http:/
### Subdomain Caching
A resolver *caches* a subdomain's state by keeping a database of all
A resolver _caches_ a subdomain's state by keeping a database of all
the current subdomain records. This database is automatically updated
when a new zonefile for a particularly domain is seen by the resolver
(this is performed lazily).
@ -282,6 +281,7 @@ curl http://localhost:6270/v1/names/baz.foo.id | python -m json.tool
```
Will return:
```
{
"address": "1Nup2UcbVuVoDZeZCtR4vjSkrvTi8toTqc",
@ -299,6 +299,7 @@ Will return:
Follow the [instructions here](https://github.com/blockstack/blockstack-core/blob/master/integration_tests/README.md) to download the regtesting Docker image.
Since the subdomain registrar service runs on port 3000, we need to do two things to expose this endpoint to interact with it from the browser:
- Open port 3000 with `-p 3000:3000`
Here's the full command you'd run to start the interactive testing scenario:

36
src/pages/core/smart/clarityRef.md

@ -1,5 +1,5 @@
---
description: "Clarity: Language Reference"
description: 'Clarity: Language Reference'
---
# Clarity Language Reference
@ -13,21 +13,21 @@ and database schemas require specified types, and use of types is checked
during contract launch. The type system does _not_ have a universal
super type. The type system contains the following types:
* `(tuple (key-name-0 key-type-0) (key-name-1 key-type-1) ...)` -
- `(tuple (key-name-0 key-type-0) (key-name-1 key-type-1) ...)` -
a typed tuple with named fields.
* `(list max-len entry-type)` - a list of maximum length `max-len`, with
- `(list max-len entry-type)` - a list of maximum length `max-len`, with
entries of type `entry-type`
* `(response ok-type err-type)` - object used by public functions to commit
- `(response ok-type err-type)` - object used by public functions to commit
their changes or abort. May be returned or used by other functions as
well, however, only public functions have the commit/abort behavior.
* `(optional some-type)` - an option type for objects that can either be
- `(optional some-type)` - an option type for objects that can either be
`(some value)` or `none`
* `(buff max-len)` := byte buffer or maximum length `max-len`.
* `principal` := object representing a principal (whether a contract principal
- `(buff max-len)` := byte buffer or maximum length `max-len`.
- `principal` := object representing a principal (whether a contract principal
or standard principal).
* `bool` := boolean value (`true` or `false`)
* `int` := signed 128-bit integer
* `uint` := unsigned 128-bit integer
- `bool` := boolean value (`true` or `false`)
- `int` := signed 128-bit integer
- `uint` := unsigned 128-bit integer
## Public Functions
@ -61,10 +61,10 @@ called smart contract function.
We distinguish 2 different types of `contract-call?`:
* Static dispatch: the callee is a known, invariant contract available
on-chain when the caller contract is deployed. In this case, the
callee's principal is provided as the first argument, followed by the
name of the method and its arguments:
- Static dispatch: the callee is a known, invariant contract available
on-chain when the caller contract is deployed. In this case, the
callee's principal is provided as the first argument, followed by the
name of the method and its arguments:
```scheme
(contract-call?
@ -73,8 +73,8 @@ name of the method and its arguments:
name-to-register)
```
* Dynamic dispatch: the callee is passed as an argument, and typed
as a trait reference (`<A>`).
- Dynamic dispatch: the callee is passed as an argument, and typed
as a trait reference (`<A>`).
```scheme
(define-public (swap (token-a <can-transfer-tokens>)
@ -127,8 +127,8 @@ The following limitations are imposed on contract calls:
execute when the caller is also the callee will abort the
transaction.
## Keyword reference
<!-- TODO: make work with react -->
<!-- {% capture keyword_list %} -->
<!-- {% for entry in site.data.clarityRef.keywords %} -->
@ -153,7 +153,6 @@ The following limitations are imposed on contract calls:
<!-- <hr class="uk-divider-icon"> -->
<!-- {% endfor %} -->
<!-- ## Function reference -->
<!-- {% capture function_list %} -->
@ -182,4 +181,3 @@ The following limitations are imposed on contract calls:
<!-- ``` -->
<!-- <hr class="uk-divider-icon"> -->
<!-- {% endfor %} -->

4
src/pages/core/smart/cli-wallet-quickstart.md

@ -1,5 +1,5 @@
---
description: "Blockstack CLI Wallet Quickstart"
description: 'Blockstack CLI Wallet Quickstart'
---
# Send/Receive Stacks on Testnet
@ -84,7 +84,7 @@ In order to send tokens, we will need the 5 parameters below.
**Private Key** - This is the private key corresponding to your account that was generated when you created the wallet earlier using the CLI.
Once we have the parameters, we can use the `send_tokens` command:
Once we have the parameters, we can use the `send_tokens` command:
```
$ blockstack send_tokens ST2KMMVJAB00W5Z6XWTFPH6B13JE9RJ2DCSHYX0S7 1000 200 0 381314da39a45f43f45ffd33b5d8767d1a38db0da71fea50ed9508e048765cf301 -t

2
src/pages/core/smart/install-source.md

@ -1,5 +1,5 @@
---
description: "Blockstack smart contracting language"
description: 'Blockstack smart contracting language'
---
# Install Clarity from Source

26
src/pages/core/smart/overview.md

@ -1,5 +1,5 @@
---
description: "Blockstack Clarity: Introduction"
description: 'Blockstack Clarity: Introduction'
---
# Introduction to Clarity
@ -18,18 +18,18 @@ Apps can take advantage of smart contracts to manage a global state that is visi
Not every decentralized application requires smart contracts, but Clarity unlocks interesting capabilities for decentralized applications. Examples of use cases include, but are not limited to:
* Access control (e.g. pay to access)
* Non-fungible (e.g. collectibles) and fungible tokens (e.g. stablecoins)
* Business model templates (e.g. subscriptions)
* App-specific blockchains
* Decentralized Autonomous Organizations
- Access control (e.g. pay to access)
- Non-fungible (e.g. collectibles) and fungible tokens (e.g. stablecoins)
- Business model templates (e.g. subscriptions)
- App-specific blockchains
- Decentralized Autonomous Organizations
## Language design
Clarity differs from most other smart contract languages in two essential ways:
* The language is interpreted and broadcasted on the blockchain as is (not compiled)
* The language is decidable (not Turing complete)
- The language is interpreted and broadcasted on the blockchain as is (not compiled)
- The language is decidable (not Turing complete)
Using an interpreted language ensures that the executed code is human-readable and auditable. A decidable language like Clarity makes it possible to determine precisely which code is going to be executed, for any function.
@ -37,11 +37,11 @@ A Clarity smart contract is composed of two parts &mdash; a data space and a set
Note some of the key Clarity language rules and limitations.
* The only primitive types are booleans, integers, buffers, and principals
* Recursion is illegal and there are no anonymous functions.
* Looping may only be performed via `map`, `filter`, or `fold`
* There is support for lists, however, the only variable length lists in the language appear as function inputs; There is no support for list operations like append or join.
* Variables are immutable.
- The only primitive types are booleans, integers, buffers, and principals
- Recursion is illegal and there are no anonymous functions.
- Looping may only be performed via `map`, `filter`, or `fold`
- There is support for lists, however, the only variable length lists in the language appear as function inputs; There is no support for list operations like append or join.
- Variables are immutable.
## Learning Clarity

12
src/pages/core/smart/principals.md

@ -1,5 +1,5 @@
---
description: "Clarity: Understanding Principals"
description: 'Clarity: Understanding Principals'
---
# Understanding Principals
@ -112,10 +112,10 @@ faucet" could be implemented as so:
In this example, the public function `claim-from-faucet`:
* Checks if the sender has claimed from the faucet before.
* Assigns the tx sender to a `requester` variable.
* Adds an entry to the tracking map.
* Uses `as-contract` to send 1 microstack
- Checks if the sender has claimed from the faucet before.
- Assigns the tx sender to a `requester` variable.
- Adds an entry to the tracking map.
- Uses `as-contract` to send 1 microstack
Unlike other principals, there is no private key associated with a
smart contract. As it lacks a private key, a Clarity smart contract
@ -230,7 +230,6 @@ another contract.
(err u4)))))
```
### Extending functionality: Multi-flyer contract
The authorization scheme for `fly-ship` allows pilots to fly rocket-ships from
@ -253,7 +252,6 @@ for multiple rocket-ships in a single transaction:
(ok (map call-fly ships)))
```
### Authorization for Contract-Owned Assets
The check in `authorize-pilot` protects users from malicious contracts,

24
src/pages/core/smart/rpc-api.md

@ -1,5 +1,5 @@
---
description: "Stacks Node RPC API Reference"
description: 'Stacks Node RPC API Reference'
---
# RPC API Reference
@ -22,10 +22,10 @@ Returns JSON data in the form:
```json
{
"balance": "0x100..",
"nonce": 1,
"balance_proof": "0x01fa...",
"nonce_proof": "0x01ab...",
"balance": "0x100..",
"nonce": 1,
"balance_proof": "0x01fa...",
"nonce_proof": "0x01ab..."
}
```
@ -42,7 +42,7 @@ JSON object _without_ the `balance_proof` or `nonce_proof` fields.
### POST /v2/map_entry/[Stacks Address]/[Contract Name]/[Map Name]
Attempt to fetch data from a contract data map. The contract is identified with [Stacks Address] and
[Contract Name] in the URL path. The map is identified with [Map Name].
[Contract Name] in the URL path. The map is identified with [Map Name].
The _key_ to lookup in the map is supplied via the POST body. This should be supplied as the hex string
serialization of the key (which should be a Clarity value). Note, this is a _JSON_ string atom.
@ -51,8 +51,8 @@ Returns JSON data in the form:
```json
{
"data": "0x01ce...",
"proof": "0x01ab...",
"data": "0x01ce...",
"proof": "0x01ab..."
}
```
@ -225,9 +225,9 @@ published in, and the MARF proof for the data.
```json
{
"source": "(define-private ...",
"publish_height": 1,
"proof": "0x00213..."
"source": "(define-private ...",
"publish_height": 1,
"proof": "0x00213..."
}
```
@ -245,7 +245,7 @@ the simulated `tx-sender` are supplied via the POST body in the following JSON f
```json
{
"sender": "SP31DA6FTSJX2WGTZ69SFY11BH51NZMB0ZW97B5P0.get-info",
"arguments": [ "0x0011...", "0x00231..." ]
"arguments": ["0x0011...", "0x00231..."]
}
```

3
src/pages/core/smart/testnet-node.md

@ -3,6 +3,7 @@
The Stacks 2.0 testnet is currently in development. As part of the testnet, you can run a node and connect it to a public network. This guide will walk you through downloading and running your own node in the testnet network.
### Prerequisites
Note: If you use Linux, you may need to manually install [`libssl-dev`](https://wiki.openssl.org/index.php/Libssl_API) and other packages. In your command line, run the following to get all packages:
```bash
@ -17,7 +18,7 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
If Rust is already installed, you might see this prompt. Select 'Proceed with Installation' to make sure you have the latest version installed.
![rustup prompt](/core/images/rust-install.png)
![rustup prompt](/core/images/rust-install.png)
In case you just installed Rust, you will be prompted to run the following command to make the `cargo` command available:

104
src/pages/core/smart/tutorial-counter.md

@ -1,17 +1,17 @@
---
description: "Clarity: Counter Tutorial"
description: 'Clarity: Counter Tutorial'
---
# Counter
| Experience | | **Intermediate** |
| Experience | | **Intermediate** |
| Duration | | **30 minutes** |
In this tutorial, you learn how to implement a smart contract that stores and manipulates an integer value on the Stacks 2.0 blockchain. By the end of this tutorial, you will ...
* Have experienced test-driven development with Clarity
* Understand more Clarity language design principles
* Have a working Clarity counter smart contract
- Have experienced test-driven development with Clarity
- Understand more Clarity language design principles
- Have a working Clarity counter smart contract
## Overview
@ -75,71 +75,76 @@ Let's get familiar with the tests to understand what the new smart contract shou
1. Take a quick look at the test file associated with the counter smart contract:
```shell
cat test/counter.ts
```
```shell
cat test/counter.ts
```
You should be familiar with the test set up from the Hello World tutorial. Notice how the instance of the smart contract is created on line 8:
You should be familiar with the test set up from the Hello World tutorial. Notice how the instance of the smart contract is created on line 8:
```js
counterClient = new Client("SP3GWX3NE58KXHESRYE4DYQ1S31PQJTCRXB3PE9SB.counter", "counter", provider);
```
```js
counterClient = new Client(
'SP3GWX3NE58KXHESRYE4DYQ1S31PQJTCRXB3PE9SB.counter',
'counter',
provider
);
```
That tells us that the new smart contract is named `counter` and that it should be found in the following file: `contracts/counter.clar`. Note that the `contracts` folder is assumed as the base folder and that every Clarity file has the suffix `.clar`.
That tells us that the new smart contract is named `counter` and that it should be found in the following file: `contracts/counter.clar`. Note that the `contracts` folder is assumed as the base folder and that every Clarity file has the suffix `.clar`.
The file was already created during the project setup.
The file was already created during the project setup.
2. With the editor of your choice, open `contracts/counter.clar` and add the following lines of code:
```cl
(define-data-var counter int 0)
```cl
(define-data-var counter int 0)
(define-public (get-counter)
(ok (var-get counter)))
```
(define-public (get-counter)
(ok (var-get counter)))
```
The first line initializes a new integer variable `counter` with the value set to `0` using the [`define-data-var`](https://docs.blockstack.org/core/smart/clarityref#define-data-var) statement. It is important to note that all definition statements in Clarity need to be at the top of the file.
The first line initializes a new integer variable `counter` with the value set to `0` using the [`define-data-var`](https://docs.blockstack.org/core/smart/clarityref#define-data-var) statement. It is important to note that all definition statements in Clarity need to be at the top of the file.
The `counter` variable is stored in the data space associated with this particular smart contract. The variable is persisted and acts as the global shared state.
The `counter` variable is stored in the data space associated with this particular smart contract. The variable is persisted and acts as the global shared state.
To provide access to the `counter` variable from outside of the current smart contract, we need to declare a public function to get it. The last lines of the code add a public `get-counter` function. The [`var-get`](https://docs.blockstack.org/core/smart/clarityref#var-get) statement looks for a variable in the contract's data space and returns it.
To provide access to the `counter` variable from outside of the current smart contract, we need to declare a public function to get it. The last lines of the code add a public `get-counter` function. The [`var-get`](https://docs.blockstack.org/core/smart/clarityref#var-get) statement looks for a variable in the contract's data space and returns it.
With that, you are ready to rerun the tests!
With that, you are ready to rerun the tests!
3. Run the tests and review the results:
```shell
npm test
```
```shell
npm test
```
You should now only see 2 failing tests! `should start at zero` is passing, and you successfully build your first part of the contract. Congrats!
You should now only see 2 failing tests! `should start at zero` is passing, and you successfully build your first part of the contract. Congrats!
However, we don't stop here. Let's implement increment and decrement functions.
However, we don't stop here. Let's implement increment and decrement functions.
4. Add the following lines to the bottom of the `counter.clar` file and take a few seconds to review them:
```cl
(define-public (increment)
(begin
(var-set counter (+ (var-get counter) 1))
(ok (var-get counter))))
```
```cl
(define-public (increment)
(begin
(var-set counter (+ (var-get counter) 1))
(ok (var-get counter))))
```
First, the [`begin`](https://docs.blockstack.org/core/smart/clarityref#begin) statement evaluates the multi-line expressions and returns the value of the last expression. In this case, it is used to set a new value and return the new value.
First, the [`begin`](https://docs.blockstack.org/core/smart/clarityref#begin) statement evaluates the multi-line expressions and returns the value of the last expression. In this case, it is used to set a new value and return the new value.
Next, a [`var-set`](https://docs.blockstack.org/core/smart/clarityref#var-set) is used to set a new value for the `counter` variable. The new value is constructed using the [`+`](https://docs.blockstack.org/core/smart/clarityref#-add) (add) statement. This statement takes a number of integers and returns the result. Along with add, Clarity provides statements to subtract, multiply, and divide integers. Find more details in the [Clarity language reference](https://docs.blockstack.org/core/smart/clarityref).
Next, a [`var-set`](https://docs.blockstack.org/core/smart/clarityref#var-set) is used to set a new value for the `counter` variable. The new value is constructed using the [`+`](https://docs.blockstack.org/core/smart/clarityref#-add) (add) statement. This statement takes a number of integers and returns the result. Along with add, Clarity provides statements to subtract, multiply, and divide integers. Find more details in the [Clarity language reference](https://docs.blockstack.org/core/smart/clarityref).
5. Finally, take a few minutes and implement a new public function `decrement` to subtract `1` from the `counter` variable. You should have all knowledge needed to succeed at this!
Done? Great! Run the tests and make sure all of them are passing. You are looking for 4 passed tests:
Done? Great! Run the tests and make sure all of them are passing. You are looking for 4 passed tests:
```shell
counter contract test suite
✓ should have a valid syntax (39ms)
deploying an instance of the contract
✓ should start at zero
✓ should increment (133ms)
✓ should decrement (177ms)
```shell
counter contract test suite
✓ should have a valid syntax (39ms)
deploying an instance of the contract
✓ should start at zero
✓ should increment (133ms)
✓ should decrement (177ms)
```
4 passing (586ms)
@ -166,15 +171,14 @@ Here is how the final smart contract file should look like. Note that you can fi
(ok (var-get counter))))
```
If you're ready to deploy and execute the contract, try [the Explorer Sandbox](tutorial.html#access-the-explorer-sandbox) or following [the instructions to run the contract in the command-line](tutorial.html#get-familiar-with-cli-optional).
---
## If you're ready to deploy and execute the contract, try [the Explorer Sandbox](tutorial.html#access-the-explorer-sandbox) or following [the instructions to run the contract in the command-line](tutorial.html#get-familiar-with-cli-optional).
With the completion of this tutorial, you ...
* Experienced test-driven development with Clarity
* Understood more Clarity language design principles
* Developed a working Clarity counter smart contract
- Experienced test-driven development with Clarity
- Understood more Clarity language design principles
- Developed a working Clarity counter smart contract
## Where to go next
* <a href="clarityRef.html">Clarity language reference</a>
- <a href="clarityRef.html">Clarity language reference</a>

22
src/pages/core/smart/tutorial-test.md

@ -6,13 +6,13 @@ description: Learn to Test Clarity Contract Code with JavaScript and Mocha
## Overview
| Experience | | **Advanced** |
| Experience | | **Advanced** |
| Duration | | **15 minutes** |
Clarity, Blockstack's smart contracting language, is based on [LISP](https://en.wikipedia.org/wiki/Lisp_(programming_language)). Clarity is an interpreted language, and [decidable](https://en.wikipedia.org/wiki/Recursive_language). In this tutorial, you will learn how to test Clarity and how use [Mocha](https://mochajs.org/) to test Clarity contracts while you develop them.
Clarity, Blockstack's smart contracting language, is based on [LISP](<https://en.wikipedia.org/wiki/Lisp_(programming_language)>). Clarity is an interpreted language, and [decidable](https://en.wikipedia.org/wiki/Recursive_language). In this tutorial, you will learn how to test Clarity and how use [Mocha](https://mochajs.org/) to test Clarity contracts while you develop them.
* Have a working Clarity starter project
* Understand how to test Clarity code using `.ts` files and Mocha.
- Have a working Clarity starter project
- Understand how to test Clarity code using `.ts` files and Mocha.
## Prerequisites
@ -83,7 +83,7 @@ Take a few seconds to review the contents of the file. You should ignore the tes
Note that we're importing modules from the `@blockstack/clarity` package:
```js
import { Client, Provider, ProviderRegistry, Result } from "@blockstack/clarity";
import { Client, Provider, ProviderRegistry, Result } from '@blockstack/clarity';
```
### Initializing a client
@ -127,7 +127,7 @@ await helloWorldClient.deployContract();
Finally, you will find snippets that call the public `say-hi` function of the contract:
```js
const query = helloWorldClient.createQuery({ function: { name: "say-hi", args: [] } });
const query = helloWorldClient.createQuery({ function: { name: 'say-hi', args: [] } });
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrapString(receipt);
```
@ -140,13 +140,13 @@ Now, review the last test `should echo number` on your own and try to understand
With the completion of this tutorial, you ...
* Created a working Clarity starter project
* Understood how to test Clarity contracts
- Created a working Clarity starter project
- Understood how to test Clarity contracts
Congratulations!
## Where to go next
* <a href="principals.html">Guide: Understanding principals</a>
* <a href="tutorial-counter.html">Next tutorial: Writing a counter smart contract</a>
* <a href="clarityRef.html">Clarity language reference</a>
- <a href="principals.html">Guide: Understanding principals</a>
- <a href="tutorial-counter.html">Next tutorial: Writing a counter smart contract</a>
- <a href="clarityRef.html">Clarity language reference</a>

40
src/pages/core/smart/tutorial.md

@ -6,7 +6,7 @@ description: Get Started Writing Smart Contracts with Clarity
## Overview
| Experience | | **Beginner** |
| Experience | | **Beginner** |
| Duration | | **18 minutes** |
In the world of smart contracts, everything is a blockchain transaction. You use tokens in your wallet to deploy a smart contract in a transaction, and each call to that contract after it's published is a transaction, too. That means that at each step, tokens are being exchanged as transaction fees. This tutorial introduces you to this mode of programming, which transforms blockchains into powerful state machines capable of executing complex logic.
@ -15,11 +15,10 @@ Clarity, Blockstack's smart contracting language, is based on LISP and uses its
By the end of this tutorial, you will:
* Have a working Clarity starter project and local dev environment
* Understand basic Clarity language design principles
* Deploy a contract to the Stacks 2.0 blockchain and call its public methods
* Understand how to use the Explorer Sandbox functionality
- Have a working Clarity starter project and local dev environment
- Understand basic Clarity language design principles
- Deploy a contract to the Stacks 2.0 blockchain and call its public methods
- Understand how to use the Explorer Sandbox functionality
## Prerequisites
@ -79,11 +78,12 @@ On the first line, a new public function `say-hi` is declared. Public functions
The function doesn't take any parameters and simply returns "hello world" using the [`ok`](clarityRef.html#ok) response constructor.
The second function, `echo-number`, is a [read-only function](clarityRef.html#define-read-only). Read-only functions are also public, but as the name implies, they can not perform any datamap modifications. `echo-number` takes an input parameter of the type `int`. Along with integer, Clarity supports the following [types](clarityRef.html#clarity-type-system):
* `uint`: 16-byte unsigned integer
* `principal`: spending entity, roughly equivalent to a Stacks address
* `boolean`: `true` or `false`
* `buffer`: fixed-length byte buffers
* `tuple`: named fields in keys and values
- `uint`: 16-byte unsigned integer
- `principal`: spending entity, roughly equivalent to a Stacks address
- `boolean`: `true` or `false`
- `buffer`: fixed-length byte buffers
- `tuple`: named fields in keys and values
`echo-number` uses an [`ok`](clarityRef.html#ok) response to return the value passed to the function.
@ -116,7 +116,7 @@ Go back to the Sandbox screen, switch to the [**Contract deploy**](https://testn
1. Enter a name for the contract under **Contract name** that uses lower-case letters, dashes, and numbers only.
2. Replace code in the text area under **Contract source code** with the contents of `contracts/hello-world.clar`.
3. Ignore the **Choose from sample** drop-down for now. After completing this tutorial you can come back to the Explorer Sandbox and use this drop-down to try other sample contracts.
3. Click **Deploy contract**.
4. Click **Deploy contract**.
![deploy](images/contract-deploy.png)
@ -126,8 +126,8 @@ A confirmation will pop up, indicating that a new contract deploy transaction wa
Go back to the Sandbox screen, switch to the [**Contract call**](https://testnet-explorer.blockstack.org/sandbox?tab=contract-call) tab, and enter the following details:
* **Contract address**: Your generated STX address. Hover over the identity component on the right side of the screen to copy your full address and paste it in here.
* **Contract name**: Whatever you entered as your contract name in the previous step. If you forgot, you can review your recent transactions by following the link on the upper-right, and look up your contract creation transaction.
- **Contract address**: Your generated STX address. Hover over the identity component on the right side of the screen to copy your full address and paste it in here.
- **Contract name**: Whatever you entered as your contract name in the previous step. If you forgot, you can review your recent transactions by following the link on the upper-right, and look up your contract creation transaction.
![Screenshot of the Sandbox's contract call screen](images/sandbox-call.png)
@ -143,10 +143,10 @@ Locate the `(echo-number)` method, provide any integer for the `val` argument an
With the completion of this tutorial, you now:
* Have a working Clarity starter project and local dev environment
* Understand basic Clarity language design principles
* Have deployed a contract to the Stacks 2.0 blockchain and called its public methods
* Understand how to use the Explorer Sandbox functionality
- Have a working Clarity starter project and local dev environment
- Understand basic Clarity language design principles
- Have deployed a contract to the Stacks 2.0 blockchain and called its public methods
- Understand how to use the Explorer Sandbox functionality
## Get familiar with CLI (optional)
@ -200,5 +200,5 @@ To learn more about the Blockstack CLI commands, you can run `blockstack-cli hel
## Where to go next
* <a href="tutorial-counter.html">Next tutorial: Writing a counter smart contract</a>
* <a href="tutorial-test.html">Tutorial: Testing contracts with JavaScript and Mocha</a>
- <a href="tutorial-counter.html">Next tutorial: Writing a counter smart contract</a>
- <a href="tutorial-test.html">Tutorial: Testing contracts with JavaScript and Mocha</a>

280
src/pages/core/wire-format.md

@ -5,42 +5,43 @@ It describes the transaction formats for the Bitcoin blockchain.
## Transaction format
Each Bitcoin transaction for Blockstack contains signatures from two sets of keys: the name owner, and the payer. The owner `scriptSig` and `scriptPubKey` fields are generated from the key(s) that own the given name. The payer `scriptSig` and `scriptPubKey` fields are used to *subsidize* the operation. The owner keys do not pay for any operations; the owner keys only control the minimum amount of BTC required to make the transaction standard. The payer keys only pay for the transaction's fees, and (when required) they pay the name fee.
Each Bitcoin transaction for Blockstack contains signatures from two sets of keys: the name owner, and the payer. The owner `scriptSig` and `scriptPubKey` fields are generated from the key(s) that own the given name. The payer `scriptSig` and `scriptPubKey` fields are used to _subsidize_ the operation. The owner keys do not pay for any operations; the owner keys only control the minimum amount of BTC required to make the transaction standard. The payer keys only pay for the transaction's fees, and (when required) they pay the name fee.
This construction is meant to allow the payer to be wholly separate from the owner. The principal that owns the name can fund their own transactions, or they can create a signed transaction that carries out the desired operation and request some other principal (e.g. a parent organization) to actually pay for and broadcast the transaction.
This construction is meant to allow the payer to be wholly separate from the owner. The principal that owns the name can fund their own transactions, or they can create a signed transaction that carries out the desired operation and request some other principal (e.g. a parent organization) to actually pay for and broadcast the transaction.
The general transaction layout is as follows:
| **Inputs** | **Outputs** |
| ------------------------ | ----------------------- |
| Owner scriptSig (1) | `OP_RETURN <payload>` (2) |
| Payment scriptSig | Owner scriptPubKey (3) |
| **Inputs** | **Outputs** |
| ------------------------ | ------------------------- |
| Owner scriptSig (1) | `OP_RETURN <payload>` (2) |
| Payment scriptSig | Owner scriptPubKey (3) |
| Payment scriptSig... (4) |
| ... (4) | ... (5) |
| ... (4) | ... (5) |
(1) The owner `scriptSig` is *always* the first input.
(2) The `OP_RETURN` script that describes the name operation is *always* the first output.
(3) The owner `scriptPubKey` is *always* the second output.
(1) The owner `scriptSig` is _always_ the first input.
(2) The `OP_RETURN` script that describes the name operation is _always_ the first output.
(3) The owner `scriptPubKey` is _always_ the second output.
(4) The payer can use as many payment inputs as (s)he likes.
(5) At most one output will be the "change" `scriptPubKey` for the payer.
Different operations require different outputs.
## Payload Format
Each Blockstack transaction in Bitcoin describes the name operation within an `OP_RETURN` output. It encodes name ownership, name fees, and payments as `scriptPubKey` outputs. The specific operations are described below.
Each Blockstack transaction in Bitcoin describes the name operation within an `OP_RETURN` output. It encodes name ownership, name fees, and payments as `scriptPubKey` outputs. The specific operations are described below.
Each `OP_RETURN` payload *always* starts with the two-byte string `id` (called the "magic" bytes in this document), followed by a one-byte `op` that describes the operation.
Each `OP_RETURN` payload _always_ starts with the two-byte string `id` (called the "magic" bytes in this document), followed by a one-byte `op` that describes the operation.
### NAME_PREORDER
Op: `?`
Description: This transaction commits to the *hash* of a name. It is the first
Description: This transaction commits to the _hash_ of a name. It is the first
transaction of two transactions that must be sent to register a name in BNS.
Example: [6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889](https://www.blocktrail.com/BTC/tx/6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889)
`OP_RETURN` wire format:
```
0 2 3 23 39
|-----|--|--------------------------------------------------|--------------|
@ -48,23 +49,26 @@ Example: [6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889](http
```
Inputs:
* Payment `scriptSig`'s
- Payment `scriptSig`'s
Outputs:
* `OP_RETURN` payload
* Payment `scriptPubkey` script for change
* `p2pkh` `scriptPubkey` to the burn address (0x00000000000000000000000000000000000000)
- `OP_RETURN` payload
- Payment `scriptPubkey` script for change
- `p2pkh` `scriptPubkey` to the burn address (0x00000000000000000000000000000000000000)
Notes:
* `register_addr` is a base58check-encoded `ripemd160(sha256(pubkey))` (i.e. an address). This address **must not** have been used before in the underlying blockchain.
* `script_pubkey` is either a `p2pkh` or `p2sh` compiled Bitcoin script for the payer's address.
- `register_addr` is a base58check-encoded `ripemd160(sha256(pubkey))` (i.e. an address). This address **must not** have been used before in the underlying blockchain.
- `script_pubkey` is either a `p2pkh` or `p2sh` compiled Bitcoin script for the payer's address.
### NAME_REGISTRATION
Op: `:`
Description: This transaction reveals the name whose hash was announced by a
previous `NAME_PREORDER`. It is the second of two transactions that must be
Description: This transaction reveals the name whose hash was announced by a
previous `NAME_PREORDER`. It is the second of two transactions that must be
sent to register a name in BNS.
Example: [55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925](https://www.blocktrail.com/BTC/tx/55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925)
@ -72,6 +76,7 @@ Example: [55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925](http
`OP_RETURN` wire format (2 variations allowed):
Variation 1:
```
0 2 3 39
|----|--|-----------------------------|
@ -79,6 +84,7 @@ Variation 1:
```
Variation 2:
```
0 2 3 39 59
|----|--|----------------------------------|-------------------|
@ -86,26 +92,28 @@ Variation 2:
```
Inputs:
* Payer `scriptSig`'s
- Payer `scriptSig`'s
Outputs:
* `OP_RETURN` payload
* `scriptPubkey` for the owner's address
* `scriptPubkey` for the payer's change
- `OP_RETURN` payload
- `scriptPubkey` for the owner's address
- `scriptPubkey` for the payer's change
Notes:
* Variation 1 simply registers the name. Variation 2 will register the name and
set a name value simultaneously. This is used in practice to set a zone file
hash for a name without the extra `NAME_UPDATE` transaction.
* Both variations are supported. Variation 1 was designed for the time when
- Variation 1 simply registers the name. Variation 2 will register the name and
set a name value simultaneously. This is used in practice to set a zone file
hash for a name without the extra `NAME_UPDATE` transaction.
- Both variations are supported. Variation 1 was designed for the time when
Bitcoin only supported 40-byte `OP_RETURN` outputs.
### NAME_RENEWAL
Op: `:`
Description: This transaction renews a name in BNS. The name must still be
Description: This transaction renews a name in BNS. The name must still be
registered and not expired, and owned by the transaction sender.
Example: [e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65](https://www.blocktrail.com/BTC/tx/e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65)
@ -113,6 +121,7 @@ Example: [e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65](http
`OP_RETURN` wire format (2 variations allowed):
Variation 1:
```
0 2 3 39
|----|--|-----------------------------|
@ -120,6 +129,7 @@ Variation 1:
```
Variation 2:
```
0 2 3 39 59
|----|--|----------------------------------|-------------------|
@ -128,24 +138,24 @@ Variation 2:
Inputs:
* Payer `scriptSig`'s
- Payer `scriptSig`'s
Outputs:
* `OP_RETURN` payload
* `scriptPubkey` for the owner's addess. This can be a different address than
- `OP_RETURN` payload
- `scriptPubkey` for the owner's addess. This can be a different address than
the current name owner (in which case, the name is renewed and transferred).
* `scriptPubkey` for the payer's change
* `scriptPubkey` for the burn address (to pay the name cost)
- `scriptPubkey` for the payer's change
- `scriptPubkey` for the burn address (to pay the name cost)
Notes:
* This transaction is identical to a `NAME_REGISTRATION`, except for the presence of the fourth output that pays for the name cost (to the burn address).
* Variation 1 simply renews the name. Variation 2 will both renew the name and
- This transaction is identical to a `NAME_REGISTRATION`, except for the presence of the fourth output that pays for the name cost (to the burn address).
- Variation 1 simply renews the name. Variation 2 will both renew the name and
set a new name value (in practice, the hash of a new zone file).
* Both variations are supported. Variation 1 was designed for the time when
- Both variations are supported. Variation 1 was designed for the time when
Bitcoin only supported 40-byte `OP_RETURN` outputs.
* This operation can be used to transfer a name to a new address by setting the
- This operation can be used to transfer a name to a new address by setting the
second output (the first `scriptPubkey`) to be the `scriptPubkey` of the new
owner key.
@ -153,13 +163,14 @@ Notes:
Op: `+`
Description: This transaction sets the name state for a name to the given
`value`. In practice, this is used to announce new DNS zone file hashes to the [Atlas
Description: This transaction sets the name state for a name to the given
`value`. In practice, this is used to announce new DNS zone file hashes to the [Atlas
network]({{ site.baseurl }}/core/atlas/overview.html).
Example: [e2029990fa75e9fc642f149dad196ac6b64b9c4a6db254f23a580b7508fc34d7](https://www.blocktrail.com/BTC/tx/e2029990fa75e9fc642f149dad196ac6b64b9c4a6db254f23a580b7508fc34d7)
`OP_RETURN` wire format:
```
0 2 3 19 39
|-----|--|-----------------------------------|-----------------------|
@ -174,24 +185,27 @@ Example: `hash128("jude.id" + "8d8762c37d82360b84cf4d87f32f7754") == "d1062edb9e
The 20 byte zone file hash is computed from zone file data by using `ripemd160(sha56(zone file data))`
Inputs:
* owner `scriptSig`
* payment `scriptSig`'s
- owner `scriptSig`
- payment `scriptSig`'s
Outputs:
* `OP_RETURN` payload
* owner's `scriptPubkey`
* payment `scriptPubkey` change
- `OP_RETURN` payload
- owner's `scriptPubkey`
- payment `scriptPubkey` change
### NAME_TRANSFER
Op: `>`
Description: This transaction changes the public key hash that owns the name in
Description: This transaction changes the public key hash that owns the name in
BNS.
Example: [7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24](https://www.blocktrail.com/BTC/tx/7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24)
`OP_RETURN` wire format:
```
0 2 3 4 20 36
|-----|--|----|-------------------|---------------|
@ -201,31 +215,32 @@ Example: [7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24](http
Inputs:
* Owner `scriptSig`
* Payment `scriptSig`'s
- Owner `scriptSig`
- Payment `scriptSig`'s
Outputs:
* `OP_RETURN` payload
* new name owner's `scriptPubkey`
* old name owner's `scriptPubkey`
* payment `scriptPubkey` change
- `OP_RETURN` payload
- new name owner's `scriptPubkey`
- old name owner's `scriptPubkey`
- payment `scriptPubkey` change
Notes:
* The `keep data?` byte controls whether or not the name's 20-byte value is preserved. This value is either `>` to preserve it, or `~` to delete it.
- The `keep data?` byte controls whether or not the name's 20-byte value is preserved. This value is either `>` to preserve it, or `~` to delete it.
### NAME_REVOKE
Op: `~`
Description: This transaction destroys a registered name. Its name state value
Description: This transaction destroys a registered name. Its name state value
in BNS will be cleared, and no further transactions will be able to affect the
name until it expires (if its namespace allows it to expire at all).
Example: [eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f](https://www.blocktrail.com/BTC/tx/eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f)
`OP_RETURN` wire format:
```
0 2 3 39
|----|--|-----------------------------|
@ -234,28 +249,28 @@ Example: [eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f](http
Inputs:
* owner `scriptSig`
* payment `scriptSig`'s
- owner `scriptSig`
- payment `scriptSig`'s
Outputs:
* `OP_RETURN` payload
* owner `scriptPubkey`
* payment `scriptPubkey` change
- `OP_RETURN` payload
- owner `scriptPubkey`
- payment `scriptPubkey` change
### ANNOUNCE
Op: `#`
Description: This transaction does not affect any names in BNS, but it allows a
user to send a message to other BNS nodes. In order for the message to be
Description: This transaction does not affect any names in BNS, but it allows a
user to send a message to other BNS nodes. In order for the message to be
received, the following must be true:
* The sender must have a BNS name
* The BNS nodes must list the sender's BNS name as being a "trusted message
- The sender must have a BNS name
- The BNS nodes must list the sender's BNS name as being a "trusted message
sender"
* The message must have already been propagated through the [Atlas
network]({{ site.baseurl }}/core/atlas/overview.html). This transaction references it by content hash.
- The message must have already been propagated through the [Atlas
network]({{ site.baseurl }}/core/atlas/overview.html). This transaction references it by content hash.
`OP_RETURN` wire format:
@ -267,27 +282,28 @@ received, the following must be true:
Inputs:
* The payer `scriptSig`'s
- The payer `scriptSig`'s
Outputs:
* `OP_RETURN` payload
* change `scriptPubKey`
- `OP_RETURN` payload
- change `scriptPubKey`
Notes:
* The payer key should be an owner key for an existing name, since Blockstack users can subscribe to announcements from specific name-owners.
- The payer key should be an owner key for an existing name, since Blockstack users can subscribe to announcements from specific name-owners.
### NAMESPACE_PREORDER
Op: `*`
Description: This transaction announces the *hash* of a new namespace. It is the
Description: This transaction announces the _hash_ of a new namespace. It is the
first of three transactions that must be sent to create a namespace.
Example: [5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28](https://www.blocktrail.com/BTC/tx/5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28)
`OP_RETURN` wire format:
```
0 2 3 23 39
|-----|---|-----------------------------------------|----------------|
@ -296,28 +312,29 @@ Example: [5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28](http
Inputs:
* Namespace payer `scriptSig`
- Namespace payer `scriptSig`
Outputs:
* `OP_RETURN` payload
* Namespace payer `scriptPubkey` change address
* `p2pkh` script to the burn address `1111111111111111111114oLvT2`, whose public key hash is 0x00000000000000000000000000000000
- `OP_RETURN` payload
- Namespace payer `scriptPubkey` change address
- `p2pkh` script to the burn address `1111111111111111111114oLvT2`, whose public key hash is 0x00000000000000000000000000000000
Notes:
* The `reveal_addr` field is the address of the namespace revealer public key. The revealer private key will be used to generate `NAME_IMPORT` transactions.
- The `reveal_addr` field is the address of the namespace revealer public key. The revealer private key will be used to generate `NAME_IMPORT` transactions.
### NAMESPACE_REVEAL
Op: `&`
Description: This transaction reveals the namespace ID and namespace rules
Description: This transaction reveals the namespace ID and namespace rules
for a previously-anounced namespace hash (sent by a previous `NAMESPACE_PREORDER`).
Example: [ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32](https://www.blocktrail.com/BTC/tx/ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32)
`OP_RETURN` wire format:
```
0 2 3 7 8 9 10 11 12 13 14 15 16 17 18 20 39
|-----|---|--------|-----|-----|----|----|----|----|----|-----|-----|-----|--------|----------|-------------------------|
@ -328,57 +345,58 @@ Example: [ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32](http
Inputs:
* Namespace payer `scriptSig`s
- Namespace payer `scriptSig`s
Outputs:
* `OP_RETURN` payload
* namespace revealer `scriptPubkey`
* namespace payer change `scriptPubkey`
- `OP_RETURN` payload
- namespace revealer `scriptPubkey`
- namespace payer change `scriptPubkey`
Notes:
* This transaction must be sent within 1 day of the `NAMESPACE_PREORDER`
* The second output (with the namespace revealer) **must** be a `p2pkh` script
* The address of the second output **must** be the `reveal_addr` in the `NAMESPACE_PREORDER`
- This transaction must be sent within 1 day of the `NAMESPACE_PREORDER`
- The second output (with the namespace revealer) **must** be a `p2pkh` script
- The address of the second output **must** be the `reveal_addr` in the `NAMESPACE_PREORDER`
Pricing:
The rules for a namespace are as follows:
* a name can fall into one of 16 buckets, measured by length. Bucket 16 incorporates all names at least 16 characters long.
* the pricing structure applies a multiplicative penalty for having numeric characters, or punctuation characters.
* the price of a name in a bucket is ((coeff) * (base) ^ (bucket exponent)) / ((numeric discount multiplier) * (punctuation discount multiplier))
- a name can fall into one of 16 buckets, measured by length. Bucket 16 incorporates all names at least 16 characters long.
- the pricing structure applies a multiplicative penalty for having numeric characters, or punctuation characters.
- the price of a name in a bucket is ((coeff) _ (base) ^ (bucket exponent)) / ((numeric discount multiplier) _ (punctuation discount multiplier))
Example:
* base = 10
* coeff = 2
* nonalpha discount: 10
* no-vowel discount: 10
* buckets 1, 2: 9
* buckets 3, 4, 5, 6: 8
* buckets 7, 8, 9, 10, 11, 12, 13, 14: 7
* buckets 15, 16+:
With the above example configuration, the following are true:
- base = 10
- coeff = 2
- nonalpha discount: 10
- no-vowel discount: 10
- buckets 1, 2: 9
- buckets 3, 4, 5, 6: 8
- buckets 7, 8, 9, 10, 11, 12, 13, 14: 7
- buckets 15, 16+:
* The price of "john" would be 2 * 10^8, since "john" falls into bucket 4 and has no punctuation or numerics.
* The price of "john1" would be 2 * 10^6, since "john1" falls into bucket 5 but has a number (and thus receives a 10x discount)
* The price of "john_1" would be 2 * 10^6, since "john_1" falls into bucket 6 but has a number and punctuation (and thus receives a 10x discount)
* The price of "j0hn_1" would be 2 * 10^5, since "j0hn_1" falls into bucket 6 but has a number and punctuation and lacks vowels (and thus receives a 100x discount)
With the above example configuration, the following are true:
- The price of "john" would be 2 \* 10^8, since "john" falls into bucket 4 and has no punctuation or numerics.
- The price of "john1" would be 2 \* 10^6, since "john1" falls into bucket 5 but has a number (and thus receives a 10x discount)
- The price of "john_1" would be 2 \* 10^6, since "john_1" falls into bucket 6 but has a number and punctuation (and thus receives a 10x discount)
- The price of "j0hn_1" would be 2 \* 10^5, since "j0hn_1" falls into bucket 6 but has a number and punctuation and lacks vowels (and thus receives a 100x discount)
### NAME_IMPORT
Op: `;`
Description: This transaction registers a name and some name state into a
namespace that has been revealed, but not been launched. Only the namespace
creator can import names. See the [namespace creation section]({{ site.baseurl }}/core/naming/namespaces.html) for details.
Description: This transaction registers a name and some name state into a
namespace that has been revealed, but not been launched. Only the namespace
creator can import names. See the [namespace creation section]({{ site.baseurl }}/core/naming/namespaces.html) for details.
Example: [c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312](https://www.blocktrail.com/BTC/tx/c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312)
`OP_RETURN` wire format:
```
0 2 3 39
|----|--|-----------------------------|
@ -387,33 +405,34 @@ Example: [c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312](http
Inputs:
* The namespace reveal `scriptSig` (with the namespace revealer's public key), or one of its first 300 extended public keys
* Any payment inputs
- The namespace reveal `scriptSig` (with the namespace revealer's public key), or one of its first 300 extended public keys
- Any payment inputs
Outputs:
* `OP_RETURN` payload
* recipient `scriptPubKey`
* zone file hash (using the 20-byte hash in a standard `p2pkh` script)
* payment change `scriptPubKey`
- `OP_RETURN` payload
- recipient `scriptPubKey`
- zone file hash (using the 20-byte hash in a standard `p2pkh` script)
- payment change `scriptPubKey`
Notes:
* These transactions can only be sent between the `NAMESPACE_REVEAL` and `NAMESPACE_READY`.
* The first `NAME_IMPORT` transaction **must** have a `scriptSig` input that matches the `NAMESPACE_REVEAL`'s second output (i.e. the reveal output).
* Any subsequent `NAME_IMPORT` transactions **may** have a `scriptSig` input whose public key is one of the first 300 extended public keys from the `NAMESPACE_REVEAL`'s `scriptSig` public key.
- These transactions can only be sent between the `NAMESPACE_REVEAL` and `NAMESPACE_READY`.
- The first `NAME_IMPORT` transaction **must** have a `scriptSig` input that matches the `NAMESPACE_REVEAL`'s second output (i.e. the reveal output).
- Any subsequent `NAME_IMPORT` transactions **may** have a `scriptSig` input whose public key is one of the first 300 extended public keys from the `NAMESPACE_REVEAL`'s `scriptSig` public key.
### NAMESPACE_READY
Op: `!`
Description: This transaction launches a namesapce. Only the namespace creator
can send this transaction. Once sent, anyone can register names in the
Description: This transaction launches a namesapce. Only the namespace creator
can send this transaction. Once sent, anyone can register names in the
namespace.
Example: [2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032](https://www.blocktrail.com/BTC/tx/2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032)
`OP_RETURN` wire format:
```
0 2 3 4 23
@ -422,24 +441,28 @@ Example: [2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032](http
```
Inputs:
* Namespace revealer's `scriptSig`s
- Namespace revealer's `scriptSig`s
Outputs:
* `OP_RETURN` payload
* Change output to the namespace revealer's `p2pkh` script
- `OP_RETURN` payload
- Change output to the namespace revealer's `p2pkh` script
Notes:
* This transaction must be sent within 1 year of the corresponding `NAMESPACE_REVEAL` to be accepted.
- This transaction must be sent within 1 year of the corresponding `NAMESPACE_REVEAL` to be accepted.
### TOKEN_TRANSFER
Op: `$`
Description: This transaction transfers tokens from one account to another. Only `STACKS` tokens can be transferred at this time. The transaction encodes the number of *micro-Stacks* to send.
Description: This transaction transfers tokens from one account to another. Only `STACKS` tokens can be transferred at this time. The transaction encodes the number of _micro-Stacks_ to send.
Example: [093983ca71a6a9dd041c0bdb8b3012824d726ee26fe51da8335a06e8a08c2798](https://www.blocktrail.com/BTC/tx/093983ca71a6a9dd041c0bdb8b3012824d726ee26fe51da8335a06e8a08c2798)
`OP_RETURN` wire format:
```
0 2 3 19 38 46 80
|-----|--|--------------|----------|-----------|-------------------------|
@ -447,21 +470,24 @@ Example: [093983ca71a6a9dd041c0bdb8b3012824d726ee26fe51da8335a06e8a08c2798](http
```
Inputs:
* Sender's scriptSig's
- Sender's scriptSig's
Outputs:
* `OP_RETURN` payload
* Recipient scriptPubKey (encodes the address of the receiving account)
* Change address for the sender
- `OP_RETURN` payload
- Recipient scriptPubKey (encodes the address of the receiving account)
- Change address for the sender
Notes:
* The `amount` field is an 8-byte litte-endian number that encodes the number of micro-Stacks.
* The `token_type` field must be `STACKS`. All other unused bytes in this field must be `\x00`.
* The `scratch area` field is optional -- it can be up to 34 bytes, and include any data you want.
- The `amount` field is an 8-byte litte-endian number that encodes the number of micro-Stacks.
- The `token_type` field must be `STACKS`. All other unused bytes in this field must be `\x00`.
- The `scratch area` field is optional -- it can be up to 34 bytes, and include any data you want.
## Method Glossary
Some hashing primitives are used to construct the wire-format representation of each name operation. They are enumerated here:
Some hashing primitives are used to construct the wire-format representation of each name operation. They are enumerated here:
```
B40_REGEX = '^[a-z0-9\-_.+]*$'

3
src/pages/develop/cliDocs.md

@ -1,7 +1,6 @@
---
---
# Blockstack CLI Reference
{% include commandline.md %}

92
src/pages/develop/collection-type.md

@ -1,8 +1,8 @@
---
---
# How to create a Collection type
Collections support data portability between applications. Blockstack supplies a `Contact` collection for use by Blockstack applications. Developers can create additional collection types, use them in their own applications, and publish them so other developers can make use of them too.
In this section, you learn the coding guidelines for creating and publishing a new `Collection` type. The following topics are included:
@ -26,17 +26,17 @@ This section demonstrates how to create a new collection type using Typescript.
1. Create a new `.ts` file and open it for editing.
2. Import the `Collection` class.
```js
import { Collection, Attrs, Serializable } from 'blockstack-collections'
```
```js
import { Collection, Attrs, Serializable } from 'blockstack-collections';
```
3. Extend the abstract `Collection` class from the `blockstack-collections` package.
```js
export class Contact extends Collection implements Serializable {
...
}
```
```js
export class Contact extends Collection implements Serializable {
...
}
```
4. Give your `Collection` a unique identifier.
@ -46,57 +46,57 @@ This section demonstrates how to create a new collection type using Typescript.
static get collectionName(): string {
return 'contact'
}
```
```
{% include warning.html content="While you must specify a unique identifier, the Blockstack platform does not currently enforce uniqueness. If your <code>Collection</code> type shares the same identifier as another type, it will lead to data corruption for the user. In the future, the Blockstack platform will enforce unique collection names. " %}
{% include warning.html content="While you must specify a unique identifier, the Blockstack platform does not currently enforce uniqueness. If your <code>Collection</code> type shares the same identifier as another type, it will lead to data corruption for the user. In the future, the Blockstack platform will enforce unique collection names. " %}
5. Define a static `schema` constant.
This is your type's schema.
```js
static schema = {
identifier: String,
firstName: String,
lastName: String,
blockstackID: String,
email: String,
website: String,
address: String,
telephone: String,
organization: String
}
```
```js
static schema = {
identifier: String,
firstName: String,
lastName: String,
blockstackID: String,
email: String,
website: String,
address: String,
telephone: String,
organization: String
}
```
6. Determine if you need to set the `singleFile` storage flag.
By default, the `singleFile` flag is false. This setting causes every record in a collection to store in Gaia as a separate file. The default works well for larger types that describe data such as documents or photos. If your `Collection` type only has a few fields and is not expected to have a large number of records, set the `singleFile` data format flag to `true`.
By default, the `singleFile` flag is false. This setting causes every record in a collection to store in Gaia as a separate file. The default works well for larger types that describe data such as documents or photos. If your `Collection` type only has a few fields and is not expected to have a large number of records, set the `singleFile` data format flag to `true`.
```js
static singleFile = true
```
```js
static singleFile = true
```
7. Define the `fromObject` and `fromData` serializaiton methods.
These methods serialize and deserialize your `Collection` type. You can use any serialization method you want. Data encryption is handled automatically by the parent `Collection` class, so you *should not* perform any additional encryption.
These methods serialize and deserialize your `Collection` type. You can use any serialization method you want. Data encryption is handled automatically by the parent `Collection` class, so you _should not_ perform any additional encryption.
In the following example code, data is converted to JSON string for storage.
```js
static fromObject(object: object) {
// Create from plain Javascript object
return new Contact(object)
}
static fromData(data: string) {
// Deserialize JSON data
return new Contact(JSON.parse(data))
}
serialize() {
// Serialize to JSON string
return JSON.stringify(this.attrs)
}
```
```js
static fromObject(object: object) {
// Create from plain Javascript object
return new Contact(object)
}
static fromData(data: string) {
// Deserialize JSON data
return new Contact(JSON.parse(data))
}
serialize() {
// Serialize to JSON string
return JSON.stringify(this.attrs)
}
```
8. Test and iterate development of your type in your application.
9. Publish your type for others to use.
@ -144,7 +144,7 @@ To perform additional processing of a collection, you can override the `get`, `s
## Publish your new type for others to use
While you *can* use your collection exclusively in your application, the Collections feature is intended to enable data portability between DApps. So, you should publish your new type so other developers can make use of it.
While you _can_ use your collection exclusively in your application, the Collections feature is intended to enable data portability between DApps. So, you should publish your new type so other developers can make use of it.
To publish your Collection type, do the following:

130
src/pages/develop/collections.md

@ -1,8 +1,8 @@
---
---
# Work with Collections (Preview)
Collections is the feature designed to make data portable among Blockstack applications. Sharing is accomplished by storing a user's data in a standardized format at a known, Gaia storage location. Collections associate user data with a user's decentralized ID. When users move among apps, the same data is available to each application the user authorizes.
On this page, you learn what collections are and how to use them. You'll learn about the `Contact` collection in particular. The following topics are covered:
@ -11,7 +11,7 @@ On this page, you learn what collections are and how to use them. You'll learn a
## Understand how collections work
One of Blockstack's goals is to give users true data ownership by enabling *data portability*. Data portability allows users to login with their digital ID on any app and have access to the same data. For example, if a user adds a photo of a Hawaiian vacation in one app, that photo enters the user's data pool. Then, when the user opens a second app, that same photo is available to the second app because the user data, including the photo, is shared via the user's decentralized ID.
One of Blockstack's goals is to give users true data ownership by enabling _data portability_. Data portability allows users to login with their digital ID on any app and have access to the same data. For example, if a user adds a photo of a Hawaiian vacation in one app, that photo enters the user's data pool. Then, when the user opens a second app, that same photo is available to the second app because the user data, including the photo, is shared via the user's decentralized ID.
How do collections work? Blockstack builds a library containing commonly used data schemes. Developers use these classes and objects instead of creating their own, unique data schemes. Using a class from the collections library guarantees class data is stored in Gaia in that format; And, when retrieved, guarantees the same format is returned. This pre-release provides the `Contact` collection. A contact schema produces this structure:
@ -65,28 +65,28 @@ If you have `npm` installed, do the following to run the Contact Manager demo ap
7. Install the dependencies using `npm`.
```bash
npm install
```
```bash
npm install
```
8. Start the application running.
```bash
npm run start
```
```bash
npm run start
```
The system starts the application and launches it in your browser at 127.0.0.1:3000
The system starts the application and launches it in your browser at 127.0.0.1:3000
9. Choose **Sign In with Blockstack**.
The internet browser will display this pop-up
The internet browser will display this pop-up
![](images/contacts-manager.png)
![](images/contacts-manager.png)
10. Use the local browser by choosing **Open Blockstack.app**.
10. Use the local browser by choosing **Open Blockstack.app**.
11. If you are not signed into an ID in the Blockstack Browser, choose **Create new ID** from the pop up.
If you are already signed in, choose an ID to sign in to the Contacts Manager app with.
If you are already signed in, choose an ID to sign in to the Contacts Manager app with.
The system should return you to the Contact Manager demo application.
@ -108,7 +108,6 @@ If you have `npm` installed, do the following to run the Contact Manager demo ap
![](images/test-contact.png)
## How to add the Contact collections to your DApp
In this section, you learn how to add `Contact` collection functionality to an existing application. Before beginning, make sure your application is using Blockstack auth and is storing data with Gaia. To start using the `Contact` collection in your Blockstack app, do the following:
@ -116,35 +115,35 @@ In this section, you learn how to add `Contact` collection functionality to an e
1. Change to the root directory of your app project.
2. Install the preview branch of the `blockstack.js`.
```
npm install blockstack@20.0.0-alpha.5
```
```
npm install blockstack@20.0.0-alpha.5
```
3. Add the ``blockstack-collections` package to your app.
```
npm install blockstack-collections@0.1.8
```
```
npm install blockstack-collections@0.1.8
```
4. Edit your code to import the `Contact` collection type.
```
import { Contact } from `blockstack-collections`
```
```
import { Contact } from `blockstack-collections`
```
5. Customize your sign in request to include the contacts collection scope `Contact.scope`.
This scope grants your app permission to read and write to the user’s `Contact` collection.
This scope grants your app permission to read and write to the user’s `Contact` collection.
```javascript
import { UserSession, AppConfig, makeAuthRequest } from 'blockstack'
import { Contact } from '`blockstack-collections'
```javascript
import { UserSession, AppConfig, makeAuthRequest } from 'blockstack';
import { Contact } from '`blockstack-collections';
const scopes = ['store_write', 'publish_data', Contact.scope]
const appConfig = new AppConfig(scopes)
const userSession = new UserSession({appConfig: appConfig})
userSession.redirectToSignIn()
```
const scopes = ['store_write', 'publish_data', Contact.scope];
const appConfig = new AppConfig(scopes);
const userSession = new UserSession({ appConfig: appConfig });
userSession.redirectToSignIn();
```
## Collection storage operations
@ -153,53 +152,50 @@ Collection storage was designed around an ORM-like interface. This approach ensu
### Example: Create and save a Contact object
```javascript
const newContact = {
lastName: 'Stackerson',
firstName: 'Blocky',
blockstackID: 'Blockstacker.id',
email: 'blockstacker@blockstack.org',
website: 'blockstack.org',
telephone: '123123123'
}
var contact = new Contact(newContact)
contact.save().then((contactID) => {
// contact saved successfully
})
const newContact = {
lastName: 'Stackerson',
firstName: 'Blocky',
blockstackID: 'Blockstacker.id',
email: 'blockstacker@blockstack.org',
website: 'blockstack.org',
telephone: '123123123',
};
var contact = new Contact(newContact);
contact.save().then(contactID => {
// contact saved successfully
});
```
### Example: Read a Contact object
```javascript
let contactID = 'Blocky Stackerson'
Contact.get(contactID).then((contact) => {
// Do something with the contact object
console.log('Hello ${contact.firstName}')
})
let contactID = 'Blocky Stackerson';
Contact.get(contactID).then(contact => {
// Do something with the contact object
console.log('Hello ${contact.firstName}');
});
```
### Example: List Contact objects
```javascript
let contacts = []
Contact.list((contactID) => {
// This callback is invoked for each contact identifier
// To get the actual object you'll need to use Contact.get
// Or you can add the IDs to an array for display
contacts.push(contactID)
// Return true to continue iterating, return false to stop
return true
})
let contacts = [];
Contact.list(contactID => {
// This callback is invoked for each contact identifier
// To get the actual object you'll need to use Contact.get
// Or you can add the IDs to an array for display
contacts.push(contactID);
// Return true to continue iterating, return false to stop
return true;
});
```
### Example: Delete a Contact
```javascript
var contact = new Contact(newContact)
contact.delete().then(() => {
// contact deleted successfully
})
var contact = new Contact(newContact);
contact.delete().then(() => {
// contact deleted successfully
});
```

40
src/pages/develop/connect/get-started.md

@ -1,4 +1,5 @@
# Guide to Blockstack Connect
## Installation
With yarn:
@ -34,14 +35,13 @@ export interface AuthOptions {
}
```
parameter | type | default | optional | description
---|---|---|---|---
redirectTo | string | | false | The path in your app where users go after sign in.
appDetails | object | | false | an object which includes `appName: string` and `appIcon: string`. This will speed up the process of loading your app's information during onboarding.
finished | function | | false | A callback that can be invoked after authentication. This prevents having to do a whole page refresh in a new tab. One argument is passed to this callback, which is an object with `userSession` included. If included, then the `redirectTo` path is ignored, and the user will be logged in automatically.
sendToSignIn | boolean | false | true | Whether the user should go straight to the 'sign in' flow (false) or be presented with the 'sign up' flow (true) instead.
userSession | UserSession | | false | pass a `UserSession` instance to use for authentication. If it's not passed, `@blockstack/connect` will create one for you.
| parameter | type | default | optional | description |
| ------------ | ----------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| redirectTo | string | | false | The path in your app where users go after sign in. |
| appDetails | object | | false | an object which includes `appName: string` and `appIcon: string`. This will speed up the process of loading your app's information during onboarding. |
| finished | function | | false | A callback that can be invoked after authentication. This prevents having to do a whole page refresh in a new tab. One argument is passed to this callback, which is an object with `userSession` included. If included, then the `redirectTo` path is ignored, and the user will be logged in automatically. |
| sendToSignIn | boolean | false | true | Whether the user should go straight to the 'sign in' flow (false) or be presented with the 'sign up' flow (true) instead. |
| userSession | UserSession | | false | pass a `UserSession` instance to use for authentication. If it's not passed, `@blockstack/connect` will create one for you. |
### In React Apps
@ -63,11 +63,7 @@ const authOptions = {
},
};
const App = () => (
<Connect authOptions={authOptions}>
// the rest of your app's components
</Connect>
)
const App = () => <Connect authOptions={authOptions}>// the rest of your app's components</Connect>;
```
Later, when you want to begin the onboarding process, use the `useConnect` hook to get `connect`'s `doOpenAuth` method.
@ -78,12 +74,8 @@ import { useConnect } from '@blockstack/connect';
const SignInButton = () => {
const { doOpenAuth } = useConnect();
return (
<Button onClick={doOpenAuth}>
Sign In
</Button>
)
}
return <Button onClick={doOpenAuth}>Sign In</Button>;
};
```
#### Sign In
@ -94,11 +86,12 @@ To send the user straight to sign in, call `doOpenAuth(true)`.
If you aren't using React, or just want a simpler API, then you can use the `showBlockstackConnect` method.
```javascript
import { showBlockstackConnect } from '@blockstack/connect';
const authOptions = { /** See docs above for options */ };
const authOptions = {
/** See docs above for options */
};
showBlockstackConnect(authOptions);
```
@ -124,9 +117,10 @@ First, include the script in your HTML:
Then, you can use API methods under the `blockstackConnect` global variable:
```javascript
const authOptions = { /** See docs above for options */ };
const authOptions = {
/** See docs above for options */
};
blockstackConnect.showBlockstackConnect(authOptions);
```

26
src/pages/develop/deploy-tips.md

@ -1,18 +1,18 @@
---
description: Blockstack dApp documentation
---
# Deployment
Blockstack applications are web applications that authenticate users with Blockstack Auth and store data with Gaia. Both of these technologies can be accessed on the client side. As such, Blockstack apps tend to be simple in design and operation, since in many cases, they don’t have to host anything besides the application’s assets.
## Where to deploy your application
Blockstack applications are web applications that authenticate users with Blockstack Auth and store data with Gaia. Both of these technologies can be accessed on the client side. As such, Blockstack apps tend to be simple in design and operation, since in many cases, they don’t have to host anything besides the application’s assets.
## Where to deploy your application
Before users can interact with your application, you must deploy it on a server that is accessible over the internet. Deploying requires that you:
* Configure or customize the files in the `public` directory.
* Build your application site for deployment.
* Copy your generated application files to your production server.
- Configure or customize the files in the `public` directory.
- Build your application site for deployment.
- Copy your generated application files to your production server.
If you first populated your application with the Blockstack application generator, your application contains the starting blocks for configuring, building, and deploying your app. For example, the React template builds out a scaffolding with the following building blocks.
@ -57,13 +57,13 @@ When your application authenticates users with Blockstack, your DApp at one URL
You can think of CORS interactions as an apartment building with Security. For example, if you need to borrow a ladder, you could ask a neighbor in your building who has one. Security would likely not have a problem with this request (i.e., same-origin, your building). If you needed a particular tool, however, and you ordered it delivered from an online hardware store (i.e., cross-origin, another site), Security may request identification before allowing the delivery man into the apartment building. (Credit: [Codecademy](https://www.codecademy.com/articles/what-is-cors))
The way you configure CORs depends on which company you use to host your web application. The application generator adds a `cors` directory to your application scaffolding. This directory contains files for Netlify (`_headers` and `_redirects`) as well as one for Firebase (`firebase.json`). The configurations in the `cors` directory make your application's `manifest.json` file accessible to other applications (for example, to the Blockstack Browser). If you are deploying to a service other than Netlify or Firebase, you must configure CORS on that service to include the following headers when serving `manifest.json`:
The way you configure CORs depends on which company you use to host your web application. The application generator adds a `cors` directory to your application scaffolding. This directory contains files for Netlify (`_headers` and `_redirects`) as well as one for Firebase (`firebase.json`). The configurations in the `cors` directory make your application's `manifest.json` file accessible to other applications (for example, to the Blockstack Browser). If you are deploying to a service other than Netlify or Firebase, you must configure CORS on that service to include the following headers when serving `manifest.json`:
```html
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Access-Control-Allow-Methods: "POST, GET, OPTIONS, DELETE, PUT"```
```
````html
Access-Control-Allow-Origin: * Access-Control-Allow-Headers: "X-Requested-With, Content-Type,
Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding" Access-Control-Allow-Methods:
"POST, GET, OPTIONS, DELETE, PUT"```
````
Consult the documentation for your hosting service to learn how to configure CORS on that service.

60
src/pages/develop/overview_auth.md

@ -1,9 +1,8 @@
---
---
# Authentication protocol
Blockstack Auth provides single sign on and authentication without third parties or remote servers. On this page, you'll get an overview of authentication from a developer perspective. The following topics are covered:
## Authentication flow
@ -19,7 +18,7 @@ Apps may request any of the following scopes:
| Scope | Definition |
| -------------- | ------------------------------------------------------------------------------------ |
| `store_write` | Read and write data to the user's Gaia hub in an app-specific storage bucket. |
| `publish_data` | Publish data so that other users of the app can discover and interact with the user. | |
| `publish_data` | Publish data so that other users of the app can discover and interact with the user. | |
The permissions scope should be specified through the <a href="https://blockstack.github.io/blockstack.js/classes/appconfig.html" target="\_blank">AppConfig</a> object. If no `scopes` array is provided to the `redirectToSignIn` or `makeAuthRequest`
functions, the default is to request `['store_write']`.
@ -59,9 +58,9 @@ How you implement CORS depends in part on which platform/service you use to serv
Blockstack Auth makes extensive use of public key cryptography. Blockstack uses ECDSA with the `secp256k1` curve. The following sections describe the three public-private key pairs used in the authentication process:
* how they're generated
* where they're used
* to whom the private key is disclosed
- how they're generated
- where they're used
- to whom the private key is disclosed
### Transit private key
@ -109,12 +108,11 @@ and
[Ruby](https://github.com/blockstack/ruby-jwt-blockstack/tree/ruby-jwt-blockstack)
JWT libraries with support for this signing algorithm.
{% include note.html content="The Blockstack JWT implementation is different from other implementations because of the underlying cryptography we employ. There are libraries in <a href='https://github.com/blockstack/jsontokens-js'>Javascript</a> and <a href='https://github.com/blockstack/ruby-jwt-blockstack'>Ruby</a> available on the Blockstack Github to allow you to work with these tokens." %}
### Example: authRequest payload schema
``` JavaScript
```JavaScript
const requestPayload = {
jti, // UUID
iat, // JWT creation time in seconds
@ -131,7 +129,6 @@ const requestPayload = {
}
```
### Example: authResponse payload schema
```JavaScript
@ -163,28 +160,23 @@ To decode the token and see what information it holds:
2. Navigate to [jwt.io](https://jwt.io/).
3. Paste the full token there.
The output should look similar to below:
```json
{
"jti": "f65f02db-9f42-4523-bfa9-8034d8edf459",
"iat": 1555641911,
"exp": 1555645511,
"iss": "did:btc-addr:1ANL7TNdT7TTcjVnrvauP7Mq3tjcb8TsUX",
"public_keys": [
"02f08d5541bf611ded745cc15db08f4447bfa55a55a2dd555648a1de9759aea5f9"
],
"domain_name": "http://localhost:8080",
"manifest_uri": "http://localhost:8080/manifest.json",
"redirect_uri": "http://localhost:8080",
"version": "1.3.1",
"do_not_include_profile": true,
"supports_hub_url": true,
"scopes": [
"store_write",
"publish_data"
]
}
```
The `iss` property is a decentralized identifier or `did`. This identifies the user and the user name to the application. The specific `did` is a `btc-addr`.
The output should look similar to below:
```json
{
"jti": "f65f02db-9f42-4523-bfa9-8034d8edf459",
"iat": 1555641911,
"exp": 1555645511,
"iss": "did:btc-addr:1ANL7TNdT7TTcjVnrvauP7Mq3tjcb8TsUX",
"public_keys": ["02f08d5541bf611ded745cc15db08f4447bfa55a55a2dd555648a1de9759aea5f9"],
"domain_name": "http://localhost:8080",
"manifest_uri": "http://localhost:8080/manifest.json",
"redirect_uri": "http://localhost:8080",
"version": "1.3.1",
"do_not_include_profile": true,
"supports_hub_url": true,
"scopes": ["store_write", "publish_data"]
}
```
The `iss` property is a decentralized identifier or `did`. This identifies the user and the user name to the application. The specific `did` is a `btc-addr`.

35
src/pages/develop/profiles.md

@ -1,7 +1,6 @@
---
---
# Guide to Blockstack Profiles
You can use the blockstack.js library to create and register an Blockstack username on the Stacks blockchain. This section describes the `Profile` object and contains the following topics:
@ -36,45 +35,45 @@ Follow these steps to create and register a profile for a Blockstack username (`
```es6
const profileOfNaval = {
"@context": "http://schema.org/",
"@type": "Person",
"name": "Naval Ravikant",
"description": "Co-founder of AngelList"
}
'@context': 'http://schema.org/',
'@type': 'Person',
name: 'Naval Ravikant',
description: 'Co-founder of AngelList',
};
```
## Sign a profile as a single token
```es6
import { makeECPrivateKey, wrapProfileToken, Person } from 'blockstack'
import { makeECPrivateKey, wrapProfileToken, Person } from 'blockstack';
const privateKey = makeECPrivateKey()
const privateKey = makeECPrivateKey();
const person = new Person(profileOfNaval)
const token = person.toToken(privateKey)
const tokenFile = [wrapProfileToken(token)]
const person = new Person(profileOfNaval);
const token = person.toToken(privateKey);
const tokenFile = [wrapProfileToken(token)];
```
## Verify an individual token
```js
import { verifyProfileToken } from 'blockstack'
import { verifyProfileToken } from 'blockstack';
try {
const decodedToken = verifyProfileToken(tokenFile[0].token, publicKey)
} catch(e) {
console.log(e)
const decodedToken = verifyProfileToken(tokenFile[0].token, publicKey);
} catch (e) {
console.log(e);
}
```
## Recover a profile from a token file
```js
const recoveredProfile = Person.fromToken(tokenFile, publicKey)
const recoveredProfile = Person.fromToken(tokenFile, publicKey);
```
## Validate profile schema
```js
const validationResults = Person.validateSchema(recoveredProfile)
const validationResults = Person.validateSchema(recoveredProfile);
```

25
src/pages/develop/radiks-collaborate.md

@ -1,24 +1,24 @@
---
---
# Collaborate with groups
A key feature of Radiks is support for private collaboration between multiple users. Supporting collaboration with client-side encryption and user-owned storage can be complicated, but the patterns to implement it are generally the same among most applications. Radiks supplies interfaces for collaboration, making it easy to build private, collaborative apps.
A key feature of Radiks is support for private collaboration between multiple users. Supporting collaboration with client-side encryption and user-owned storage can be complicated, but the patterns to implement it are generally the same among most applications. Radiks supplies interfaces for collaboration, making it easy to build private, collaborative apps.
You use the <a href="https://github.com/blockstack/radiks/blob/master/src/models/user-group.ts" target="_blank"><code>UserGroup</code></a> class to build a collaborative group with Radiks. In this section, you learn about this class.
## Understand the UserGroup workflow
The key model behind a collaborative group is `UserGroup`. By default, it only has one attribute, `name`, which is encrypted. You can subclass `UserGroup` with different attributes as needed.
The key model behind a collaborative group is `UserGroup`. By default, it only has one attribute, `name`, which is encrypted. You can subclass `UserGroup` with different attributes as needed.
The general workflow for creating a collaborative group that can share and edit encrypted models is as follows:
1. The admin of the group creates a new `UserGroup`.
This group acts as the 'hub' and controls the logic around inviting and removing users.
2. The admin invites one or more other users to a group:
* The admin specifies the username of the user they want to invite
* Radiks looks up the user's public key
* Radiks creates an 'invitation' that is encrypted with the user's public key, and contains information about the `UserGroup`
- The admin specifies the username of the user they want to invite
- Radiks looks up the user's public key
- Radiks creates an 'invitation' that is encrypted with the user's public key, and contains information about the `UserGroup`
3. When the invited user 'activates' an invitation, they create a `GroupMembership`.
They use this membership instance to reference information (such as private keys and signing keys) related to the group.
@ -44,7 +44,6 @@ import { UserGroup } from 'radiks';
Calling `create` on a new `UserGroup` will create the group and activate an invitation for the group's creator.
```javascript
const group = new UserGroup({ name: 'My Group Name' });
await group.create();
@ -52,7 +51,6 @@ await group.create();
A group's creator is also the group's admin.
### Invite users to become members
Use the `makeGroupMembership` method on a `UserGroup` instance to invite a user. The only argument passed to this method is the user's `username`.
@ -70,21 +68,20 @@ console.log(invitation._id); // the ID used to later activate an invitation
You can also create a generic invitation that any user can activate, if they are provided with randomly generated secret key, which should be used to decrypt the invitation. The key is generated when the generic invitation is being created.
~~~javascript
```javascript
import { GenericGroupInvitation, UserGroup } from 'radiks';
const group = await UserGroup.findById(myGroupId);
// Creating generic invitation
const genericInvitation = await GenericGroupInvitation.makeGenericInvitation(group);
console.log(genericInvitation._id); // the ID used to later activate an invitation
console.log(genericInvitation.secretCode); // the secretCode used to later activate an invitation
~~~
```
### Accept an invitation
Use the `activate` method on a `GroupInvitation` instance to activate an invitation on behalf of a user:
```javascript
````javascript
import { GroupInvitation, GenericGroupInvitation } from 'radiks';
// For user-specific invitation
@ -103,7 +100,7 @@ Call `UserGroup.myGroups` to fetch all groups that the current user is a member
import { UserGroup } from 'radiks';
const groups = await UserGroup.myGroups();
```
````
## Find a UserGroup

15
src/pages/develop/radiks-intro.md

@ -1,21 +1,18 @@
---
---
# Radiks the data indexer
The Blockstack Radiks feature enables Blockstack decentralized applications (DApps) to index and store across data belonging to multiple users. Radiks works with Blockstack's Gaia Storage System. Using Radiks, you can build multi-player DApps that:
The Blockstack Radiks feature enables Blockstack decentralized applications (DApps) to index and store across data belonging to multiple users. Radiks works with Blockstack's Gaia Storage System. Using Radiks, you can build multi-player DApps that:
- index, store, and query application data
- query a user's publicly saved data
- display real-time updates that reflect in progress changes
- support collaboration among sets of users
## Why use Radiks?
Many applications serve data that users create to share publicly with others. Facebook, Twitter, and Instagram are examples of such applications. Decentralized applications that want to create comparable multi-user experiences must ensure that anything a user creates for public sharing is still under control of the creator in the user's Gaia storage.
Many applications serve data that users create to share publicly with others. Facebook, Twitter, and Instagram are examples of such applications. Decentralized applications that want to create comparable multi-user experiences must ensure that anything a user creates for public sharing is still under control of the creator in the user's Gaia storage.
For example, if Twitter wanted to be a decentralized application while still having many different users creating their own tweets, those tweets would be stored in each user's own Gaia storage. In such a situation, Twitter still needs a way to keep track of everyone's tweets, display those tweets in user timelines, and perform searches across the platform. Radiks exists to support these kinds of scenarios. It allows applications to query across multiple user data using complicated queries like text search, joins, and filters.
@ -33,9 +30,9 @@ Radiks can store both public and sensitive, non-public data since all data is en
## How Radiks authorizes writes
Radiks must ensure that the user is writing to their own data. To ensure this, Radiks creates and manages *signing keys*. These keys sign all writes that a user performs. Radiks server-validates all signatures before performing a write. This guarantees that a user is not able to overwrite another user's data.
Radiks must ensure that the user is writing to their own data. To ensure this, Radiks creates and manages _signing keys_. These keys sign all writes that a user performs. Radiks server-validates all signatures before performing a write. This guarantees that a user is not able to overwrite another user's data.
A Radiks server is also built to support writes in a collaborative but private situation. For example, consider a collaborative document editing application, where users can create organizations and invite users to that organization. All users in that organization should have read and write privileges to the organization data. Thus, these organizations will have a single shared key that is used to sign and encrypt data.
A Radiks server is also built to support writes in a collaborative but private situation. For example, consider a collaborative document editing application, where users can create organizations and invite users to that organization. All users in that organization should have read and write privileges to the organization data. Thus, these organizations will have a single shared key that is used to sign and encrypt data.
When an organization administrator needs to remove a user from the group, they are expected to revoke the previous key and create a new one. Radiks is aware of these relationships, and will only support writes that are signed with the currently active key related to an organization.
@ -65,5 +62,5 @@ Although Radiks applications rely on a centrally-hosted database, an application
</tr>
</table>
If you are not familiar with Gaia, see
If you are not familiar with Gaia, see
[read the Gaia documentation](({{site.baseurl}}/storage/overview.html).

79
src/pages/develop/radiks-models.md

@ -1,9 +1,9 @@
---
---
# Create and use models
Radiks allows you to model your client data. You can then query this data and display it for a user in multi-player applications. A social application where users want to see the comments of other users is an example of a multi-player application. This page explains how to create a model in your distributed application using Radiks.
Radiks allows you to model your client data. You can then query this data and display it for a user in multi-player applications. A social application where users want to see the comments of other users is an example of a multi-player application. This page explains how to create a model in your distributed application using Radiks.
## Overview of Model class extension
@ -13,9 +13,9 @@ Blockstack provides a `Model` class you should extend to easily create, save, an
import { Model, User } from 'radiks';
```
Then, create a class that extends this model, and provide a schema. Refer to <a href="https://github.com/blockstack/radiks/blob/master/src/model.ts" target="_blank">the <code>Model</code> class</a> in the `radiks` repo to get an overview of the class functionality.
Then, create a class that extends this model, and provide a schema. Refer to <a href="https://github.com/blockstack/radiks/blob/master/src/model.ts" target="_blank">the <code>Model</code> class</a> in the `radiks` repo to get an overview of the class functionality.
Your new class must define a static `className` property. This property is used when storing and querying information. If you fail to add a `className`, Radiks defaults to the actual model's class name (`foobar.ts`) and your application will behave unpredictably.
Your new class must define a static `className` property. This property is used when storing and querying information. If you fail to add a `className`, Radiks defaults to the actual model's class name (`foobar.ts`) and your application will behave unpredictably.
The example class code extends `Model` to create a class named `Todo`:
@ -24,11 +24,12 @@ import { Model, User } from 'radiks';
class Todo extends Model {
static className = 'Todo';
static schema = { // all fields are encrypted by default
static schema = {
// all fields are encrypted by default
title: String,
completed: Boolean,
}
};
};
}
// after authentication:
const todo = new Todo({ title: 'Use Radiks in an app' });
@ -38,8 +39,9 @@ todo.update({
});
await todo.save();
const incompleteTodos = await Todo.fetchOwnList({ // fetch todos that this user created
completed: false
const incompleteTodos = await Todo.fetchOwnList({
// fetch todos that this user created
completed: false,
});
console.log(incompleteTodos.length); // 0
```
@ -55,14 +57,15 @@ Every class must have a static `schema` property which defines the attributes of
```javascript
class Todo extends Model {
static className = 'Todo';
static schema = { // all fields are encrypted by default
static schema = {
// all fields are encrypted by default
title: String,
completed: Boolean,
}
};
};
}
```
The `key` in this object is the field name and the value, for example, `String`, `Boolean`, or `Number`. In this case, the `title` is a `String` field. Alternatively, you can pass options instead of a type.
The `key` in this object is the field name and the value, for example, `String`, `Boolean`, or `Number`. In this case, the `title` is a `String` field. Alternatively, you can pass options instead of a type.
To define options, pass an object, with a mandatory `type` field. The only supported option right now is `decrypted`. This defaults to `false`, meaning the field is encrypted before the data is stored publicly. If you specify `true`, then the field is not encrypted.
@ -86,13 +89,13 @@ class Person extends Model {
isHuman: Boolean,
likesDogs: {
type: Boolean,
decrypted: true // all users will know if this record likes dogs!
}
}
decrypted: true, // all users will know if this record likes dogs!
},
};
static defaults = {
likesDogs: true
}
likesDogs: true,
};
}
```
@ -123,12 +126,11 @@ The default `User` model defines a `username`, but you can add a `displayName` t
In this section, you learn how to use a model you have defined.
### About the _id attribute
### About the \_id attribute
All model instances have an `_id` attribute. An `_id` is used as a primary key when storing data and is used for fetching a model. Radiks also creates a `createdAt` and `updatedAt` property when creating and saving models.
If, when constructing a model's instance, you don't pass an `_id`, Radiks creates an `_id` for you automatically. This automatically created id uses the [`uuid/v4`](https://github.com/kelektiv/node-uuid) format. This automatic `_id` is returned by the constructor.
If, when constructing a model's instance, you don't pass an `_id`, Radiks creates an `_id` for you automatically. This automatically created id uses the [`uuid/v4`](https://github.com/kelektiv/node-uuid) format. This automatic `_id` is returned by the constructor.
### Construct a model instance
@ -138,19 +140,18 @@ To create an instance, pass some attributes to the constructor of that class:
const person = new Person({
name: 'Hank',
isHuman: false,
likesDogs: false // just an example, I love dogs!
})
likesDogs: false, // just an example, I love dogs!
});
```
### Fetch an instance
To fetch an existing instance of an instance, you need the instance's `id` property. Then, call the `findById()` method or the `fetch()` method, which returns a promise.
To fetch an existing instance of an instance, you need the instance's `id` property. Then, call the `findById()` method or the `fetch()` method, which returns a promise.
```javascript
const person = await Person.findById('404eab3a-6ddc-4ba6-afe8-1c3fff464d44');
```
After calling these methods, Radiks automatically decrypts all encrypted fields.
### Access attributes
@ -169,9 +170,9 @@ To quickly update multiple attributes of an instance, pass those attributes to t
```javascript
const newAttributes = {
likesDogs: false,
age: 30
}
person.update(newAttributes)
age: 30,
};
person.update(newAttributes);
```
Important, calling `update` does **not** save the instance.
@ -217,14 +218,14 @@ class Task extends Model {
order: {
type: Number,
decrypted: true,
}
}
},
};
}
const tasks = await Task.fetchList({
completed: false,
sort: '-order'
})
sort: '-order',
});
```
You can read the [`query-to-mongo`](https://github.com/pbatey/query-to-mongo) package documentation to learn how to do complex querying, sorting, limiting, and so forth.
@ -244,7 +245,7 @@ Use the `fetchOwnList` method to find instances that were created by the current
```javascript
const tasks = await Task.fetchOwnList({
completed: false
completed: false,
});
```
@ -276,8 +277,8 @@ Whenever you save a task, you should save a reference to the project it's in:
```javascript
const task = new Task({
name: 'Improve radiks documentation',
projectId: project._id
})
projectId: project._id,
});
await task.save();
```
@ -286,7 +287,7 @@ Then, later you'll want to fetch all tasks for a certain project:
```javascript
const tasks = await Task.fetchList({
projectId: project._id,
})
});
```
Radiks lets you define an `afterFetch` method. Use this method to automatically fetch child records when you fetch the parent instance.
@ -294,12 +295,12 @@ Radiks lets you define an `afterFetch` method. Use this method to automatically
```javascript
class Project extends Model {
static className = 'Project';
static schema = { name: String }
static schema = { name: String };
async afterFetch() {
this.tasks = await Task.fetchList({
projectId: this.id,
})
});
}
}

18
src/pages/develop/radiks-server-extras.md

@ -1,8 +1,8 @@
---
---
# Radiks server tips and tricks
In this section, you'll find some tips and tricks you can use to work with a Radiks server.
## Access the MongoDB collection
@ -17,7 +17,6 @@ const mongo = await getDB(MONGODB_URL);
[See the MongoDB Collection reference](https://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html) for documentation about how you can interact with this collection.
## Run a custom Radiks-server
If you're using an [express.js](https://expressjs.com/) server to run your application, it's probably easiest to use the Radiks-server middleware. This way, you won't have to run a separate application server and Radiks server.
@ -50,7 +49,6 @@ setup({
Currently, only the `mongoDBUrl` option is supported.
## Migrate from Firebase (or anywhere else)
Migrating data from Firebase to Radiks-server is simple and painless. You can create a script file to fetch all the Firebase data using their API. Then, you can use your `MONGOD_URI` config to use the `mongodb` npm package.
@ -122,8 +120,8 @@ migrate()
Before you can implement the websocket function, you must configure your `Radiks-Server` with [express-ws](https://github.com/HenningM/express-ws)
```javascript
const app = express()
expressWS(app)
const app = express();
expressWS(app);
```
Here's an example for how to use the API:
@ -131,7 +129,7 @@ Here's an example for how to use the API:
```javascript
import Task from './models/task';
const streamCallback = (task) => {
const streamCallback = task => {
// this callback will be called whenever a task is created or updated.
// `task` is an instance of `Task`, and all methods are defined on it.
// If the user has the necessary keys to decrypt encrypted fields on the model,
@ -140,15 +138,15 @@ const streamCallback = (task) => {
if (task.projectId === myAppsCurrentProjectPageId) {
// update your view here with this task
}
}
};
Task.addStreamListener(streamCallback)
Task.addStreamListener(streamCallback);
// later on, you might want to remove the stream listener (if the
// user changes pages, for example). When calling `removeStreamListener`,
// you MUST provide the exact same callback that you used with `addStreamListener`.
Task.removeStreamListener(streamCallback)
Task.removeStreamListener(streamCallback);
```
## Saving centralized user-related data

162
src/pages/develop/radiks-setup.md

@ -1,9 +1,9 @@
---
---
# Set-up Radiks for your DApp
Using Radiks with your application requires a Radiks server and a client application constructed to use the server. In this article, you learn how to install, setup, and run a pre-packaged Radiks server that connects to MongoDB. You also learn how to establish your DApp application as a client for that server.
Using Radiks with your application requires a Radiks server and a client application constructed to use the server. In this article, you learn how to install, setup, and run a pre-packaged Radiks server that connects to MongoDB. You also learn how to establish your DApp application as a client for that server.
## Task 1. Set up your Radiks server
@ -17,7 +17,7 @@ In the future, Radiks-server will support various different databases, but right
1. <a href="https://docs.mongodb.com/manual/administration/install-community/" target="_blank">Download and install MongoDB 3.6 or higher</a> on your workstation.
You can also install MongoDB using your favorite package manager; for example, Homebrew is recommended for macOS. If you are testing on a local workstation, you can use a `docker` image instead of installing locally.
You can also install MongoDB using your favorite package manager; for example, Homebrew is recommended for macOS. If you are testing on a local workstation, you can use a `docker` image instead of installing locally.
2. Start the MongoDB service and verify it is running.
@ -27,34 +27,35 @@ In the future, Radiks-server will support various different databases, but right
4. Create a username/password combination with `root` privileges on your new database.
### Install and start the Radiks server
The easiest way to run `radiks-server` is to use the pre-packaged `node.js` server.
1. Install the `radiks-server` on a workstation or server.
```bash
npm install -g radiks-server
```
Or, if you prefer `yarn`:
```bash
npm install -g radiks-server
```
```bash
yarn global add radiks-server
```
The default port for Mongodb is `27017`; your instance may be configured differently. By default, Radiks-server will use `'mongodb://localhost:27017/radiks-server'` as the `MongoDB_URI` value. This is suitable for local testing, but in production, you'll want to change the hostname and possibly the database name.
Or, if you prefer `yarn`:
3. Start the `radiks-server` in the command line to confirm your installation.
```bash
yarn global add radiks-server
```
The default port for Mongodb is `27017`; your instance may be configured differently. By default, Radiks-server will use `'mongodb://localhost:27017/radiks-server'` as the `MongoDB_URI` value. This is suitable for local testing, but in production, you'll want to change the hostname and possibly the database name.
2. Start the `radiks-server` in the command line to confirm your installation.
```
$ radiks-server
(node:37750) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
radiks-server is ready on http://localhost:1260
```
radiks-server is ready on http://localhost:1260
```
The `radiks-server` defaults to running on port `1260`. To change the default port, specify the `PORT` environment variable in your environment.
The `radiks-server` defaults to running on port `1260`. To change the default port, specify the `PORT` environment variable in your environment.
4. By default, the server is running at `http://localhost:1260`
3. By default, the server is running at `http://localhost:1260`
4. Stop the `radiks` server process after you confirm it runs, and your installation was a success.
@ -88,42 +89,42 @@ If you are using `blockstack.js` version 18 or earlier, you must use the Radiks
1. Start the mongo shell application.
```
$ mongo
MongoDB shell version v4.2.0
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("8d43cf80-490d-4cac-8bd6-40eec5c128de") }
MongoDB server version: 4.2.0
....
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
>
```
2. Create a new database for your application.
```
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> use test1
switched to db test1
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> db.createUser({user: "admin", pwd:"foobar1",roles: ["readWrite","dbAdmin"]});
Successfully added user: { "user" : "admin", "roles" : [ "readWrite", "dbAdmin" ] }
```
```
$ mongo
MongoDB shell version v4.2.0
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("8d43cf80-490d-4cac-8bd6-40eec5c128de") }
MongoDB server version: 4.2.0
....
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
>
```
2. Create a new database for your application.
```
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> use test1
switched to db test1
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> db.createUser({user: "admin", pwd:"foobar1",roles: ["readWrite","dbAdmin"]});
Successfully added user: { "user" : "admin", "roles" : [ "readWrite", "dbAdmin" ] }
```
3. Add a user with administrative rights to the database.
```
> db.createUser({user: "admin", pwd:"foobar1",roles: ["readWrite","dbAdmin"]});
Successfully added user: { "user" : "admin", "roles" : [ "readWrite", "dbAdmin" ] }
```
```
> db.createUser({user: "admin", pwd:"foobar1",roles: ["readWrite","dbAdmin"]});
Successfully added user: { "user" : "admin", "roles" : [ "readWrite", "dbAdmin" ] }
```
4. Create an `MONGODB_URI` environment variable on the same machine where you are running the `radiks-server`.
@ -133,7 +134,6 @@ If you are using `blockstack.js` version 18 or earlier, you must use the Radiks
export MONGODB_URI="mongodb://admin:foobar1@localhost:27017/test1"
```
## Task 3. Add startup code and build your application
To set up radiks.js, you only need to configure the URL that your Radiks-server instance is running on. If you're using the pre-built Radiks server, this will be `http://localhost:1260`. If you're in production or are using a custom Radiks server, you'll need to specify the exact URL where it's available.
@ -146,48 +146,47 @@ To configure your application as a `radiks` client, do the following:
1. Start your application so that a `UserSession` allows the app to both write and publish data:
```js
import { UserSession, AppConfig } from 'blockstack';
import { configure } from 'radiks';
```js
import { UserSession, AppConfig } from 'blockstack';
import { configure } from 'radiks';
const userSession = new UserSession({
appConfig: new AppConfig(['store_write', 'publish_data'])
})
const userSession = new UserSession({
appConfig: new AppConfig(['store_write', 'publish_data']),
});
configure({
apiServer: 'http://localhost:1260',
userSession
});
```
configure({
apiServer: 'http://localhost:1260',
userSession,
});
```
2. Add authentication to your application
2. Add authentication to your application
After your user logs in with Blockstack, you'll have some code to save the user's data in your applications `localStorage`. You'll want to use the same `UserSession` you configured with Radiks, which can be fetched from the `getConfig` method.
After your user logs in with Blockstack, you'll have some code to save the user's data in your applications `localStorage`. You'll want to use the same `UserSession` you configured with Radiks, which can be fetched from the `getConfig` method.
```js
import { User, getConfig } from 'radiks';
```js
import { User, getConfig } from 'radiks';
const handleSignIn = () => {
const { userSession } = getConfig();
if (userSession.isSignInPending()) {
await userSession.handlePendingSignIn();
await User.createWithCurrentUser();
}
}
```
const handleSignIn = () => {
const { userSession } = getConfig();
if (userSession.isSignInPending()) {
await userSession.handlePendingSignIn();
await User.createWithCurrentUser();
}
}
```
Calling `User.createWithCurrentUser` does the following:
Calling `User.createWithCurrentUser` does the following:
* Fetch user data that Blockstack.js stores in `localStorage`
* Save the user's public data (including their public key) in Radiks-server
* Find or create a signing key that is used to authorize writes on behalf of this user
* Cache the user's signing key (and any group-related signing keys) to make signatures and decryption happen quickly later on
- Fetch user data that Blockstack.js stores in `localStorage`
- Save the user's public data (including their public key) in Radiks-server
- Find or create a signing key that is used to authorize writes on behalf of this user
- Cache the user's signing key (and any group-related signing keys) to make signatures and decryption happen quickly later on
### Build and run your application
After you have added Radiks to your application, build and run the application. Test the application by logging in with your Blockstack ID. Create some data using the application. If you inspect the MongoDB database, you should see the encrypted data stored in the database.
You can specify the `mongoDBUrl` or the `maxLimit` option when initiating the Radiks server in your application.
```javascript
@ -201,7 +200,6 @@ setup({
The `mongoDBUrl` option is the MongoDB URL for the Radiks server
The `maxLimit` option is the maximum `limit` field used inside the mongo queries. The default is 1000.
## Where to go next
Creating models for your application's data is where radiks truly becomes helpful. To learn how to use models, see the [Create and use models](radiks-models.html) section.

7
src/pages/develop/storage.md

@ -1,7 +1,6 @@
---
---
# Guide to Blockstack Storage
The Blockstack Platform stores application data in the Gaia Storage System. Transactional metadata is stored on the Blockstack blockchain and user application data is stored in Gaia storage. Storing data off of the blockchain ensures that Blockstack applications can provide users with high performance and high availability for data reads and writes without introducing central trust parties.
@ -12,7 +11,6 @@ The Blockstack Platform stores application data in the Gaia Storage System. Tran
Gaia storage is a key-value store.
## Creating a file
You use the <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#putfile" target="_blank">UserSession.putFile</a>
@ -82,6 +80,7 @@ var userSession = new UserSession()
```
## Reading another user's unencrypted file
In order for files to be publicly readable, the app must request
the `publish_data` scope during authentication.
@ -103,7 +102,6 @@ userSession.putFile("/hello.txt", "hello world!", options)
You use the <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#deletefile" target="_blank">UserSession.deleteFile</a> from the application's data store.
```JavaScript
var userSession = new UserSession()
@ -115,4 +113,5 @@ var userSession = new UserSession()
```
## Related Information
To learn more about the guarantees provided by Gaia, see [Storage write and read]({{ site.baseurl }}/storage/write-to-read.html#)

10
src/pages/faqs/allFAQS.md

@ -1,9 +1,9 @@
---
description: "Blockstack Network documentation"
description: 'Blockstack Network documentation'
redirect_from: /org/voucherholder
---
# Blockstack FAQs
This is a comprehensive list of all the Blockstack FAQs.
@ -98,10 +98,10 @@ This is a comprehensive list of all the Blockstack FAQs.
## Important disclaimer
*The Securities and Exchange Commission (SEC) has qualified the offering statement that we have filed with the SEC under Regulation A for our offering of certain of our Stacks Tokens. The information in that offering statement is more complete than the information we are providing now, and could differ in important ways. You must read the documents filed with the SEC before investing. The offering is being made only by means of its offering statement. This document shall not constitute an offer to sell or the solicitation of an offer to buy, nor shall there be any sale of these securities in any state or jurisdiction in which such offer, solicitation or sale would be unlawful prior to registration or qualification under the securities laws of any such state or jurisdiction.*
_The Securities and Exchange Commission (SEC) has qualified the offering statement that we have filed with the SEC under Regulation A for our offering of certain of our Stacks Tokens. The information in that offering statement is more complete than the information we are providing now, and could differ in important ways. You must read the documents filed with the SEC before investing. The offering is being made only by means of its offering statement. This document shall not constitute an offer to sell or the solicitation of an offer to buy, nor shall there be any sale of these securities in any state or jurisdiction in which such offer, solicitation or sale would be unlawful prior to registration or qualification under the securities laws of any such state or jurisdiction._
*An indication of interest involves no obligation or commitment of any kind. Any person interested in investing in any offering of Stacks Tokens should review our disclosures and the publicly filed offering statement and the f<a href='https://stackstoken.com/circular'>final offering circular</a> that is part of that offering statement. Blockstack is not registered, licensed or supervised as a broker dealer or investment adviser by the SEC, the Financial Industry Regulatory Authority (FINRA) or any other financial regulatory authority or licensed to provide any financial advice or services.*
_An indication of interest involves no obligation or commitment of any kind. Any person interested in investing in any offering of Stacks Tokens should review our disclosures and the publicly filed offering statement and the f<a href='https://stackstoken.com/circular'>final offering circular</a> that is part of that offering statement. Blockstack is not registered, licensed or supervised as a broker dealer or investment adviser by the SEC, the Financial Industry Regulatory Authority (FINRA) or any other financial regulatory authority or licensed to provide any financial advice or services._
## Forward-looking statements
*This communication contains forward-looking statements that are based on our beliefs and assumptions and on information currently available to us. In some cases, you can identify forward-looking statements by the following words: “will,” “expect,” “would,” “intend,” “believe,” or other comparable terminology. Forward-looking statements in this document include, but are not limited to, statements about our plans for developing the platform and future utility for the Stacks Token, our Clarity smart contracting language, and potential mining operations. These statements involve risks, uncertainties, assumptions and other factors that may cause actual results or performance to be materially different. More information on the factors, risks and uncertainties that could cause or contribute to such differences is included in our filings with the SEC, including in the “Risk Factors” and “Management’s Discussion & Analysis” sections of our offering statement on Form 1-A. We cannot assure you that the forward-looking statements will prove to be accurate. These forward-looking statements speak only as of the date hereof. We disclaim any obligation to update these forward-looking statements.*
_This communication contains forward-looking statements that are based on our beliefs and assumptions and on information currently available to us. In some cases, you can identify forward-looking statements by the following words: “will,” “expect,” “would,” “intend,” “believe,” or other comparable terminology. Forward-looking statements in this document include, but are not limited to, statements about our plans for developing the platform and future utility for the Stacks Token, our Clarity smart contracting language, and potential mining operations. These statements involve risks, uncertainties, assumptions and other factors that may cause actual results or performance to be materially different. More information on the factors, risks and uncertainties that could cause or contribute to such differences is included in our filings with the SEC, including in the “Risk Factors” and “Management’s Discussion & Analysis” sections of our offering statement on Form 1-A. We cannot assure you that the forward-looking statements will prove to be accurate. These forward-looking statements speak only as of the date hereof. We disclaim any obligation to update these forward-looking statements._

547
src/pages/ios/tutorial.md

@ -1,9 +1,9 @@
---
description: How to use Blockstack on iOS Mobile
---
# iOS DApps
This tutorial teaches you how to create a decentralized application using
Blockstack's iOS SDK using the following content:
@ -18,7 +18,7 @@ experienced. For best results, beginners should follow the guide as written. It
is expected that the fast or furiously brilliant will skip ahead and improvise
on this material at will. God speed one and all.
If you want to download a complete application rather than working through a tutorial, see this *alternative* sample, the <a href="https://github.com/blockstack/photoblock-demo" target="_blank">photoblock-demo</a>.
If you want to download a complete application rather than working through a tutorial, see this _alternative_ sample, the <a href="https://github.com/blockstack/photoblock-demo" target="_blank">photoblock-demo</a>.
## Understand the sample application flow
@ -102,62 +102,62 @@ In this section, you build an initial React.js application called
1. Create a `hello-blockstack` directory.
```bash
mkdir hello-blockstack
```
```bash
mkdir hello-blockstack
```
2. Change into your new directory.
```bash
cd hello-blockstack
```
```bash
cd hello-blockstack
```
3. Create your initial `hello-world-tutorial` application.
```bash
$ npx generator-blockstack --react
npx: installed 338 in 13.792s
create package.json
create .gitignore
create webpack.config.js
create netlify.toml
create firebase.json
...
I'm all done. Running npm install for you to install the required dependencies. If this fails, try running the command yourself.
> fsevents@1.2.9 install /private/tmp/testymc/node_modules/fsevents
> node install
added 775 packages from 455 contributors and audited 9435 packages in 20.934s
found 0 vulnerabilities
```bash
$ npx generator-blockstack --react
npx: installed 338 in 13.792s
create package.json
create .gitignore
create webpack.config.js
create netlify.toml
create firebase.json
...
I'm all done. Running npm install for you to install the required dependencies. If this fails, try running the command yourself.
> fsevents@1.2.9 install /private/tmp/testymc/node_modules/fsevents
> node install
added 775 packages from 455 contributors and audited 9435 packages in 20.934s
found 0 vulnerabilities
```
```
Depending on your environment you may have some warnings with the installation. Optionally, you can fix these before continuing to the next section.
Depending on your environment you may have some warnings with the installation. Optionally, you can fix these before continuing to the next section.
4. Run the initial application.
```bash
npm run start
> hello-blockstack@0.0.0 start /Users/meepers/repos/hello-blockstack
> webpack-dev-server
Project is running at http://localhost:8080/
webpack output is served from /
404s will fallback to /index.html
Hash: 4d2312ba236a4b95dc3a
Version: webpack 2.7.0
Time: 2969ms
Asset Size Chunks Chunk Names
....
Child html-webpack-plugin for "index.html":
chunk {0} index.html 541 kB [entry] [rendered]
[0] ./~/lodash/lodash.js 540 kB {0} [built]
[1] ./~/html-webpack-plugin/lib/loader.js!./src/index.html 533 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
webpack: Compiled successfully.
```
```bash
npm run start
> hello-blockstack@0.0.0 start /Users/meepers/repos/hello-blockstack
> webpack-dev-server
Project is running at http://localhost:8080/
webpack output is served from /
404s will fallback to /index.html
Hash: 4d2312ba236a4b95dc3a
Version: webpack 2.7.0
Time: 2969ms
Asset Size Chunks Chunk Names
....
Child html-webpack-plugin for "index.html":
chunk {0} index.html 541 kB [entry] [rendered]
[0] ./~/lodash/lodash.js 540 kB {0} [built]
[1] ./~/html-webpack-plugin/lib/loader.js!./src/index.html 533 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
webpack: Compiled successfully.
```
At this point, the browser is running a Blockstack server on your local host.
@ -172,18 +172,16 @@ In this section, you build an initial React.js application called
The system displays a prompt allowing you to create a new Blockstack ID or restore an existing one.
![]({{ site.baseurl }}/browser/images/login-choice.png)
![]({{ site.baseurl }}/browser/images/login-choice.png)
7. Follow the prompts appropriate to your situation.
If you are restoring an existing ID, you may see a prompt about your user
being nameless, ignore it. At this point you have only a single application
on your test server. So, you should see this single application, with your
own `blockstack.id` display name, once you are signed in:
![]({{ site.baseurl }}/browser/images/hello-authd.png)
If you are restoring an existing ID, you may see a prompt about your user
being nameless, ignore it. At this point you have only a single application
on your test server. So, you should see this single application, with your
own `blockstack.id` display name, once you are signed in:
![]({{ site.baseurl }}/browser/images/hello-authd.png)
### Add a redirect end point to your application
@ -192,55 +190,55 @@ you want the web app to redirect the user to your iOS application. The work
you do here will allow it.
1. From the terminal command line, change directory to your web
application directory (`hello-blockstack`).
application directory (`hello-blockstack`).
1. If it doesn't ext, create the `public` directory.
```bash
$ mkdir public
```
```bash
$ mkdir public
```
2. Use the `touch` command to add a redirect endpoint to your application.
1. Use the `touch` command to add a redirect endpoint to your application.
This endpoint on the web version of your app will redirect iOS users back
to your mobile app.
```bash
$ touch public/redirect.html
```
3. Open `redirect.html` and add code to the endpoint.
```bash
$ touch public/redirect.html
```
```
<!DOCTYPE html>
<html>
<head>
<title>Hello, Blockstack!</title>
<script>
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
1. Open `redirect.html` and add code to the endpoint.
var authResponse = getParameterByName('authResponse')
window.location="myblockstackapp://?authResponse=" + authResponse
</script>
<body>
</body>
</html>
```
```
<!DOCTYPE html>
<html>
<head>
<title>Hello, Blockstack!</title>
<script>
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
var authResponse = getParameterByName('authResponse')
window.location="myblockstackapp://?authResponse=" + authResponse
</script>
<body>
</body>
</html>
```
Blockstack apps are identified by their domain names. The endpoint will
receive a get request with the query parameter `authResponse=XXXX` and
should redirect the browser to `myblockstackapp:XXXX`.
Blockstack apps are identified by their domain names. The endpoint will
receive a get request with the query parameter `authResponse=XXXX` and
should redirect the browser to `myblockstackapp:XXXX`.
`myblockstackapp:` is custom protocol handler. The handler should be unique
to your application. Your app's web-based authentication uses this handler
to redirect the user back to your iOS app. Later, you'll add a reference
to this handler in your iOS application.
`myblockstackapp:` is custom protocol handler. The handler should be unique
to your application. Your app's web-based authentication uses this handler
to redirect the user back to your iOS app. Later, you'll add a reference
to this handler in your iOS application.
4. Close and save the `redirect.html` file.
5. Ensure your Blockstack app compiles successfully.
1. Close and save the `redirect.html` file.
1. Ensure your Blockstack app compiles successfully.
The `npm` process should detect and compile your change.
@ -263,22 +261,22 @@ menu items and therefore these procedures may be differœent on your version.
5. On the **Choose options for your new project** dialog, set the following:
<table class="uk-table uk-table-small">
<tr>
<th>Product Name</th>
<td><code>hello-blockstack-ios</code></td>
</tr>
<tr>
<th>Organization Name</th>
<td><code><i>USERNAME</i></code></td>
</tr>
<tr>
<th>User Interface</th>
<td>Storyboard</td>
</tr>
</table>
![](images/choose-new-options.png)
<table class="uk-table uk-table-small">
<tr>
<th>Product Name</th>
<td><code>hello-blockstack-ios</code></td>
</tr>
<tr>
<th>Organization Name</th>
<td><code><i>USERNAME</i></code></td>
</tr>
<tr>
<th>User Interface</th>
<td>Storyboard</td>
</tr>
</table>
![](images/choose-new-options.png)
6. Press **Next**.
@ -288,7 +286,6 @@ menu items and therefore these procedures may be differœent on your version.
8. Close XCode.
### Add and edit a Podfile
To use CocoaPods you need to define the XCode target to link them to.
@ -299,16 +296,17 @@ lines after.
1. Open a terminal window on your workstation.
2. Change directory into your new project directory where your `hello-blockstack-ios.xcodeproj` file was created.
```swift
$ cd hello-blockstack-ios
```
```swift
$ cd hello-blockstack-ios
```
3. Create a Podfile.
```bash
$ pod init
```
```bash
$ pod init
```
The command creates a `Podfile` in the directory.
The command creates a `Podfile` in the directory.
4. Open the `Podfile` for editing.
5. Add a line stating the Blockstack dependency.
@ -318,20 +316,20 @@ lines after.
# platform :ios, '9.0'
target 'hello-blockstack-ios' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
s
!
# Pods for hello-blockstack-ios
pod 'Blockstack'
s
'
target 'hello-blockstack-iosTests' do
inherit! :search_paths
# Pods for testing
end
o
s
g
d
end
```
8. Save and close the `Podfile`.
6. Save and close the `Podfile`.
### Install Blockstack SDK and open the pod project
@ -339,26 +337,26 @@ lines after.
2. In terminal, make sure it is open to the root of your `hello-blockstack-ios` project.
3. Initialize the project with Cocoapods via the `pod install` command.
```bash
$ pod install
Analyzing dependencies
Downloading dependencies
Installing Blockstack (1.0.1)
Installing CryptoSwift (0.15.0)
Installing PromisesObjC (1.2.8)
Installing PromisesSwift (1.2.8)
Installing STRegex (2.1.0)
Generating Pods project
Integrating client project
[!] Please close any current XCode sessions and use `hello-blockstack-ios.xcworkspace` for this project from now on.
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 2 total pods installed.
[!] Automatically assigning platform `ios` with version `11.3` on target `hello-blockstack-ios` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
```
```bash
$ pod install
Analyzing dependencies
Downloading dependencies
Installing Blockstack (1.0.1)
Installing CryptoSwift (0.15.0)
Installing PromisesObjC (1.2.8)
Installing PromisesSwift (1.2.8)
Installing STRegex (2.1.0)
Generating Pods project
Integrating client project
[!] Please close any current XCode sessions and use `hello-blockstack-ios.xcworkspace` for this project from now on.
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 2 total pods installed.
[!] Automatically assigning platform `ios` with version `11.3` on target `hello-blockstack-ios` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
```
This command creates a number of files
This command creates a number of files
4. Review the files that the `pod` installation created:
@ -368,22 +366,23 @@ lines after.
Podfile.lock hello-blockstack-ios.xcodeproj
Pods hello-blockstack-ios.xcworkspace
```
5. Start XCode and choose **Open another project**.
6. Choose the `.xcworkspace` file created in your project folder.
![](images/open-xcworkspace.png)
![](images/open-xcworkspace.png)
When you open the workspace, the system will begin indexing the project. Then, after indexing, you **may** see a warning indicator at the top in the
project title. If you see the warning, continue to step 7. Otherwise, go to the next section.
When you open the workspace, the system will begin indexing the project. Then, after indexing, you **may** see a warning indicator at the top in the
project title. If you see the warning, continue to step 7. Otherwise, go to the next section.
7. Click the signal to reveal the warning.
8. Click **Next**.
![](images/indicator.png)
![](images/indicator.png)
9. Select all the targets and press **Next** and **Continue** when prompted.
Make sure you have no errors; warnings are acceptable to continue.
Make sure you have no errors; warnings are acceptable to continue.
### Choose a custom protocol handler
@ -391,20 +390,20 @@ You'll need to choose a custom protocol handler that is unique to your app. This
is so that your app's web-based authentication `redirect.html` endpoint can redirect
the user back to your iOS app. In this example, you use `myblockstackapp://`.
1. Open the `.xcworkspace` file in XCode if it isn't open already.
2. Select the top node of your project.
3. Select the **Info** tab in XCode.
4. Scroll to **URL Types** and press **+** (plus) sign.
5. Enter an **Identifier** and **URL Schemes** value.
1. Open the `.xcworkspace` file in XCode if it isn't open already.
2. Select the top node of your project.
3. Select the **Info** tab in XCode.
4. Scroll to **URL Types** and press **+** (plus) sign.
5. Enter an **Identifier** and **URL Schemes** value.
| **Identifier** | `MyBlockstackApp` |
| **URL Schemes** | `myblockstackapp` |
| **Identifier** | `MyBlockstackApp` |
| **URL Schemes** | `myblockstackapp` |
6. Set the **Role** to **Editor**.
6. Set the **Role** to **Editor**.
When you are done the **URL Types** appears as follows:
When you are done the **URL Types** appears as follows:
![](images/url-type.png)
![](images/url-type.png)
### Add a splash screen
@ -422,12 +421,12 @@ All iOS applications require a splash page.
5. Drag the downloaded file into the **3X** position in your new Images folder.
![](images/image-set-1.png)
![](images/image-set-1.png)
6. Select the `LaunchScreen.storyboard`.
7. Choose **Open As > Source Code**.
![](images/open-as.png)
![](images/open-as.png)
8. Replace the content of the `<scenes>` element with the following:
@ -471,18 +470,17 @@ All iOS applications require a splash page.
9. Immediately after scenes but before the close of the `</document>` tag add the following `<resources>`.
```xml
<resources>
>
<image name="Image" width="64" height="64"/>
</resources>
</document>
>
>
```
10. Choose **Run > Run app** in the emulator.
The emulator now contains a new splash screen.
![](images/splash.png)
The emulator now contains a new splash screen.
![](images/splash.png)
### Update the Main.storyboard
@ -495,58 +493,59 @@ Rather than have you build up your own UI in the interface builder, this section
defines the graphical elements, and their functionality will be defined in
a respective `.swift` file.
3. Within the `<viewController>` element, replace the existing `<view>` sub-element with the following:
3. Within the `<viewController>` element, replace the existing `<view>` sub-element with the following:
```xml
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="hello-blockstack-ios" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9eE-ZS-LU9">
<rect key="frame" x="0.0" y="101" width="375" height="50"/>
<color key="backgroundColor" red="0.44735813140000003" green="0.1280144453" blue="0.57268613580000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="U5v-13-4Ux"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lfp-KX-BDb">
<rect key="frame" x="100" y="382" width="175" height="40"/>
<color key="backgroundColor" red="0.1215686275" green="0.12941176469999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="8fN-Ro-Krn"/>
</constraints>
<color key="tintColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<state key="normal" title="Sign into Blocksack">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="signIn:" destination="BYZ-38-t0r" eventType="touchUpInside" id="nV7-rt-euZ"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="9eE-ZS-LU9" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="2ZP-tU-h9Y"/>
<constraint firstItem="9eE-ZS-LU9" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="81" id="DBh-q0-pAV"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="Lfp-KX-BDb" secondAttribute="trailing" constant="100" id="MHO-ew-4Bd"/>
<constraint firstItem="Lfp-KX-BDb" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="100" id="Rsm-LP-ya7"/>
<constraint firstItem="Lfp-KX-BDb" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="362" id="chE-B7-ya6"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="9eE-ZS-LU9" secondAttribute="trailing" id="j0x-8j-04u"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
```
4. Select the Main.storyboard and choose **Open as > Interface Builder - Storyboard**.
![](images/main-storyboard.png)
You should see the following:
![](images/new-storyboard.png)
```xml
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="hello-blockstack-ios" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9eE-ZS-LU9">
<rect key="frame" x="0.0" y="101" width="375" height="50"/>
<color key="backgroundColor" red="0.44735813140000003" green="0.1280144453" blue="0.57268613580000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="U5v-13-4Ux"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lfp-KX-BDb">
<rect key="frame" x="100" y="382" width="175" height="40"/>
<color key="backgroundColor" red="0.1215686275" green="0.12941176469999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="8fN-Ro-Krn"/>
</constraints>
<color key="tintColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<state key="normal" title="Sign into Blocksack">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="signIn:" destination="BYZ-38-t0r" eventType="touchUpInside" id="nV7-rt-euZ"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="9eE-ZS-LU9" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="2ZP-tU-h9Y"/>
<constraint firstItem="9eE-ZS-LU9" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="81" id="DBh-q0-pAV"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="Lfp-KX-BDb" secondAttribute="trailing" constant="100" id="MHO-ew-4Bd"/>
<constraint firstItem="Lfp-KX-BDb" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="100" id="Rsm-LP-ya7"/>
<constraint firstItem="Lfp-KX-BDb" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="362" id="chE-B7-ya6"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="9eE-ZS-LU9" secondAttribute="trailing" id="j0x-8j-04u"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
`
```
4. Select the Main.storyboard and choose **Open as > Interface Builder - Storyboard**.
![](images/main-storyboard.png)
You should see the following:
![](images/new-storyboard.png)
### Add the UI variables to the ViewController file.
@ -574,37 +573,36 @@ In this section, you edit the `ViewController.swift` file using the storyboard a
9. Add an import statement for the `Blockstack` and another for the `SafariServices` module.
When you are done, your `ViewController.swift` file contains the following:
When you are done, your `ViewController.swift` file contains the following:
```swift
import UIKit
import Blockstack
import SafariServices
```swift
import UIKit
import Blockstack
import SafariServices
class ViewController: UIViewController {
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet var signInButton: UIButton!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet var signInButton: UIButton!
}
```
}
```
And XCode has added two outlines to the `Main.storyboard` source.
And XCode has added two outlines to the `Main.storyboard` source.
```xml
<connections>
<outlet property="nameLabel" destination="9eE-ZS-LU9" id="Ahv-Te-ZZo"/>
<outlet property="signInButton" destination="Lfp-KX-BDb" id="yef-Jj-uPt"/>
</connections>
```
Your connectors will have their own `destination` and `id` values.
```xml
<connections>
<outlet property="nameLabel" destination="9eE-ZS-LU9" id="Ahv-Te-ZZo"/>
<outlet property="signInButton" destination="Lfp-KX-BDb" id="yef-Jj-uPt"/>
</connections>
```
Your connectors will have their own `destination` and `id` values.
### Edit the ViewController.swift file
@ -619,14 +617,15 @@ already created for you:
This web application already has a redirect in place for you. You'll reference
this application in your mobile add for now. In XCode, do the following;
1. Open the `ViewController.swift` file.
2. Add an import both for `Blockstack`.
```
import UIKit
import Blockstack
```
t
k
`
```
3. Add a private `updateUI()` function.
@ -651,14 +650,14 @@ this application in your mobile add for now. In XCode, do the following;
}
}
}
```
```
The function uses the `Blockstack.shared.isUserSignedIn()` method to determine if
the user is already logged into Blockstack or not. It then uses the
`Blockstack.shared.loadUserData()` method to load the user data and update
the application display with the username.
5. Replace the content of the `viewDidLoad()` function so that it calls this private function.
4. Replace the content of the `viewDidLoad()` function so that it calls this private function.
```swift
override func viewDidLoad() {
@ -666,44 +665,46 @@ this application in your mobile add for now. In XCode, do the following;
// Do any additional setup after loading the view, typically from a nib.
self.updateUI()
}
```
`
9. Create a `signIn()` function that handles both sign in and out.
```
5. Create a `signIn()` function that handles both sign in and out.
The function uses the `Blockstack.shared.signIn()` and
`Blockstack.shared.signUserOut()` methods to sign the user into the application.
```swift
@IBAction func signIn(_ sender: UIButton) {
if Blockstack.shared.isUserSignedIn() {
print("Currently signed in so signing out.")
Blockstack.shared.signUserOut()
self.updateUI()
} else {
print("Currently signed out so signing in.")
// Address of deployed example web app
Blockstack.shared.signIn(redirectURI: URL(string: "https://heuristic-brown-7a88f8.netlify.app/redirect.html")!,
appDomain: URL(string: "https://heuristic-brown-7a88f8.netlify.app")!) { authResult in
switch authResult {
case .success(let userData):
print("Sign in SUCCESS", userData.profile?.name as Any)
self.updateUI()
case .cancelled:
print("Sign in CANCELLED")
case .failed(let error):
print("Sign in FAILED, error: ", error ?? "n/a")
}
}
}
```swift
@IBAction func signIn(_ sender: UIButton) {
if Blockstack.shared.isUserSignedIn() {
print("Currently signed in so signing out.")
Blockstack.shared.signUserOut()
self.updateUI()
} else {
print("Currently signed out so signing in.")
// Address of deployed example web app
Blockstack.shared.signIn(redirectURI: URL(string: "https://heuristic-brown-7a88f8.netlify.app/redirect.html")!,
appDomain: URL(string: "https://heuristic-brown-7a88f8.netlify.app")!) { authResult in
switch authResult {
case .success(let userData):
print("Sign in SUCCESS", userData.profile?.name as Any)
self.updateUI()
case .cancelled:
print("Sign in CANCELLED")
case .failed(let error):
print("Sign in FAILED, error: ", error ?? "n/a")
}
}
}
}
```
}
```
## Troubleshooting your build in XCode
XCode builds can retain old data. To ensure your builds are clean, try the following:
1. Reset the simulator by choosing **Hardware -> Erase all content and settings** from the menu.
2. In XCode, clean the project by choosing **Product > Clean** from the menu or press `Command + Shift + K` on your keyboard.
2. In XCode, clean the project by choosing **Product > Clean** from the menu or press `Command + Shift + K` on your keyboard.
3. Clean the build folder by pressing `Command + Option + Shift + K` on your keyboard.
4. Run the code on the simulator again.

6
src/pages/org/address_check.md

@ -1,9 +1,9 @@
---
description: "Blockstack Network documentation"
description: 'Blockstack Network documentation'
---
# Check your address
We recommend that you confirm your address is correct by going through the following steps in the Stacks Wallet:
If you created a software wallet, using the "New Wallet" option, choose "Restore from Seed Phrase" when you start the Stacks Wallet application, then enter your Seed Phrase, and click "Restore." The address that you see on the next screen should match the address you created earlier.

20
src/pages/org/faq.md

@ -1,25 +1,27 @@
---
description: "Blockstack Network documentation"
description: 'Blockstack Network documentation'
---
# FAQs about Stacks tokens and wallet
## Stacks tokens
{% for faq in site.data.theFAQs.faqs %}
{% if faq.category == 'tokens' %}
{% if faq.category == 'tokens' %}
### {{ faq.question }}
{{ faq.answer }}
{% endif %}
{% endif %}
{% endfor %}
## Stacks Wallet
{% for faq in site.data.theFAQs.faqs %}
{% if faq.category == 'wallet' %}
{% if faq.category == 'wallet' %}
### {{ faq.question }}
{{ faq.answer }}
{% endif %}
{% endif %}
{% endfor %}

15
src/pages/org/overview.md

@ -1,20 +1,17 @@
---
description: "Blockstack Network documentation"
description: 'Blockstack Network documentation'
---
# Overview of Blockstack
Blockstack is a full-stack decentralized computing network that enables a new generation of applications where developers and users can interact fairly and securely. Blockstack uses blockchain technology to build protocols and developer tools designed to enable a fair and open Internet that returns digital rights to developers and consumers.
## What is the Blockstack Ecosystem?
The Blockstack Ecosystem is the legal entities and community structures that support the Blockstack technology, the apps that rely on it, and the people that work with it. The ecosystem’s mission is to foster an open and decentralized Internet that establishes and protects privacy, security and freedom for all users.
The documentation on this site focuses on the technologies produced by three entities in the ecosystem.
### Blockstack Public Benefit Corp (PBC)
Blockstack Public Benefit Corp. (PBC) started development of the Blockstack
@ -42,22 +39,22 @@ effort developing expertise in specialized languages or technologies.
Through the 2017 Blockstack token offering, Blockstack Token LLC created the
Stacks token. This year's hard fork is an especially exciting milestone for the ecosystem because it distributes the first Stacks tokens to existing purchasers and recipients. This hard fork launches the Stacks blockchain v1, and enables the following two features for the Blockstack network:
* Registration of all digital assets and smart contracts for registering digital assets with the Stacks token.
- Registration of all digital assets and smart contracts for registering digital assets with the Stacks token.
* A genesis block that distributes Stacks tokens to existing purchasers.
- A genesis block that distributes Stacks tokens to existing purchasers.
A full technical description of the upgrade is available on <a href="https://forum.blockstack.org/t/blockstack-annual-hard-fork-2018/6518" target="\blank" >the Blockstack forum</a>.
In future upgrades and hard forks, the blockchain will expand to introduce a new
scalable consensus algorithm to increase the number of transactions it can
process. This consensus algorithm is planned to be introduced in additional
process. This consensus algorithm is planned to be introduced in additional
hard forks in 2019.
Addtionally, a future Stacks blockchain will support truly decentralized mobile
applications by removing the need to trust a remote Stacks Node.
Instead, it will be possible for light clients to calculate the economic weight
of different Stacks blockchain forks, and identify the fork with the most
economic activity. Today, light clients rely on other trusted sources for fork
economic activity. Today, light clients rely on other trusted sources for fork
selection and cannot make that decision independently. For mobile apps this
enables functionality like looking up names without having to rely on a remote
Stacks Node.

13
src/pages/org/secureref.md

@ -1,8 +1,7 @@
---
description: "Blockstack Network documentation"
description: 'Blockstack Network documentation'
---
# Wallet and identity security
It is important that you understand how to keep good security for your Stacks Wallet software and your Blockstack identity.
@ -13,10 +12,10 @@ Both your wallet seed phrase and your Secret Recovery Code are cryptographic key
The CrtypoCurrency Security Standard publishes <a href="https://cryptoconsortium.github.io/CCSS/Details/#1.03" target="_blank">guidelines for key storage</a>. These guidelines are presented from least (Level I) to most secure (Level III). We recommend you store your keys with at least Level II security. This level states that you should:
* Back up each of your cryptographic keys.
* Store the backup in a location separate location from where you use a key. For example, if you use the key at the office, you can store the key are your office.
* Protect your backup from access by unauthorized parties. For example, a safe, safe deposit box, or lock box are good examples of protecting access to a backup.
* Employ some form of tamper mechanism that allows your to determine when if you key was accessed by someone else. For example, you could use a sealed paper envelopes with handwritten signatures over the seal as a tamper mechanism.
- Back up each of your cryptographic keys.
- Store the backup in a location separate location from where you use a key. For example, if you use the key at the office, you can store the key are your office.
- Protect your backup from access by unauthorized parties. For example, a safe, safe deposit box, or lock box are good examples of protecting access to a backup.
- Employ some form of tamper mechanism that allows your to determine when if you key was accessed by someone else. For example, you could use a sealed paper envelopes with handwritten signatures over the seal as a tamper mechanism.
You are responsible for recalling and protecting your keys. Blockstack does not store your seed phrase or **Secret Recovery Code**. If you lose your seed phrase, you lose the key to your STX tokens, which can be a very costly mistake. If you lose your **Secret Recovery Code**, you lose the key to your identity and cannot access your applications or the data you created with them.

5
src/pages/org/terms.md

@ -1,8 +1,7 @@
---
description: "Blockstack Network documentation"
description: 'Blockstack Network documentation'
---
# Glossary
<!-- <table class="uk-table uk-table-large uk-table-striped"> -->

11
src/pages/org/token.md

@ -1,8 +1,7 @@
---
description: "Blockstack token holder documentation"
description: 'Blockstack token holder documentation'
---
# Learn more about the Stacks token
Stacks is the name of a token developed by Blockstack Token LLC in 2017 and
@ -44,11 +43,11 @@ documentation.</div>
The genesis block launch makes possible the following interactions:
* Token holders can purchase names and namespaces with the Stacks token. Previously, names and namespaces required the purchaser to hold Bitcoin. Initially, this process relies on the Blockstack command-line interface (CLI).
- Token holders can purchase names and namespaces with the Stacks token. Previously, names and namespaces required the purchaser to hold Bitcoin. Initially, this process relies on the Blockstack command-line interface (CLI).
* Application developers can earn Stacks by building an application on the Blockstack ecosystem.
- Application developers can earn Stacks by building an application on the Blockstack ecosystem.
* Any Stacks tokens held at the time of launch or after remain usable under the Stacks Blockchain platform.
- Any Stacks tokens held at the time of launch or after remain usable under the Stacks Blockchain platform.
Finally, in addition to the development of Stacks token, this launch enables
further development of Stacks Blockchain itself.

12
src/pages/org/tokenholders.md

@ -1,18 +1,16 @@
---
description: "Blockstack token holder documentation"
description: 'Blockstack token holder documentation'
---
# Information for current token holders
The information on this page is intended for **current Stacks (STX) token holders** during Blockstack’s token sale through early 2018.
## Find your token balance and unlock date
{% include important.html content=" If you <strong>purchased Stacks tokens during Summer 2019</strong>, the form below will <strong>not</strong> work for your allocation. Please <a href='https://explorer.blockstack.org/verifier' target='_blank'>check your allocation using this tool instead</a>. "%}
During your the initial grant process, you should have submitted a public *Stacks (STX) address* (also known as a *wallet address*) to Blockstack. A STX address is a string of letters and numbers starting with an `SP` or `SM`, for example: `SM3KJBA4RZ7Z20KD2HBXNSXVPCR1D3CRAV6Q05MKT`
During your the initial grant process, you should have submitted a public _Stacks (STX) address_ (also known as a _wallet address_) to Blockstack. A STX address is a string of letters and numbers starting with an `SP` or `SM`, for example: `SM3KJBA4RZ7Z20KD2HBXNSXVPCR1D3CRAV6Q05MKT`
If you purchased STX tokens through CoinList, you can find your address at
[CoinList](https://coinlist.co/distributions). If you submitted your Stacks
@ -21,10 +19,10 @@ Phrase** feature on the Stacks Wallet or contact us at <hello@stackstoken.com> f
help.
Use the following form to check your Stacks allocation:
<!-- TODO: make work with react -->
<!-- <div class="uk-background-secondary uk-padding uk-panel"> -->
<!-- <script> -->
<!-- function process() -->
<!-- { -->
@ -48,7 +46,6 @@ You should see a report detailing the tokens allocated to your address and when
If you have questions or concerns about your report, please contact <hello@StacksToken.com>.
## Understanding the timeline for unlocking your tokens
In October 2018, the Stacks blockchain launched under the STX token. With the
@ -59,7 +56,6 @@ token holder, the dates of these events depend on the holders’s purchase date.
The general timeline for unlocking tokens and the capabilities that are
potentially possible, are as follows:
![](images/unlocking.png)
Your specific unlock date depends on when you purchased or were granted tokens.

33
src/pages/org/wallet-install.md

@ -1,8 +1,7 @@
---
description: "How to use the Blockstack Software"
description: 'How to use the Blockstack Software'
---
# Install the Stacks Wallet software
You use the Stacks Wallet software client alone or with a hardware wallet to send and receive Stacks (STX) tokens. On this page, you learn how to install the Stacks Wallet software. This page contains the following:
@ -14,7 +13,6 @@ attack, verify your downloaded wallet software as detailed in the installation
instructions below. Verification confirms that you received the software signed
by Blockstack PBC." %}
## Mac Installation
1. <a href="https://wallet.blockstack.org" target="\_blank">Go to the wallet download page</a> in your browser.
@ -38,16 +36,14 @@ by Blockstack PBC." %}
5. In the terminal window, type the following Command
```
shasum -a 512 Stacks-Wallet-macOS-3.0.0.dmg
```
```
shasum -a 512 Stacks-Wallet-macOS-3.0.0.dmg
```
![](images/mac-shasum.png)
![](images/mac-shasum.png)
6. Verify that the resulting hash (a string of letters and numbers) is the same as the latest hash published <a href="https://github.com/blockstack/stacks-wallet/releases" target="\_blank">on this page</a>.
## Windows Installation
1. Select the **Windows Download** button <a href="https://wallet.blockstack.org/" target="\_blank">on this page</a>.
@ -70,11 +66,11 @@ by Blockstack PBC." %}
4. In the command prompt window, type the following at the command prompt.
```
certUtil -hashfile Stacks-Wallet-win10-3.0.0.exe SHA512
```
```
certUtil -hashfile Stacks-Wallet-win10-3.0.0.exe SHA512
```
![](images/windows-certutil.png)
![](images/windows-certutil.png)
5. Verify that the resulting hash (a string of letters and numbers) is the same as the latest hash published <a href="https://github.com/blockstack/stacks-wallet/releases" target="\_blank">on this page</a>.
@ -90,14 +86,11 @@ You need very small fractions of Bitcoin to fuel your Stacks Wallet transactions
If you have a paper wallet or a custodial wallet, you should set up a secondary hardware. You can then transfer small amounts to this hardware wallet for use with your Stacks Wallet. You can use any of these hardware wallets with the Stacks Wallet:
* <a href="https://trezor.io/" target="\_blank">Trezor</a> One
* <a href="https://www.ledger.com/" target="\_blank">Ledger</a> Nano S
* Ledger Blue
- <a href="https://trezor.io/" target="\_blank">Trezor</a> One
- <a href="https://www.ledger.com/" target="\_blank">Ledger</a> Nano S
- Ledger Blue
{% include note.html content="Blockstack only supports the hardware wallets listed above. Other wallets, for example, the Trezor Model T, <strong>are not supported</strong>. If you have questions about wallet support, please <a href='emailto:support@blockstack.org' target='_blank'>contact Blockstack support</a>." %}
For information on setting up a hardware wallet, refer to the vendor's
documentation. We cannot help you set up your hardware wallet.

10
src/pages/org/wallet-intro.md

@ -1,8 +1,7 @@
---
description: "How to use the Blockstack Software"
description: 'How to use the Blockstack Software'
---
# Understand cryptocurrency wallets
If you are, or plan to be a Stacks token holder, you need to think about how you
@ -12,7 +11,7 @@ receive your tokens? STX tokens are a cryptocurrency and you manage your tokens
## Wallets, addresses, and tokens
Cryptocurrency wallets are software that make sending and receiving cryptocurrency easier. Unlike the wallets you carry physical money in, a cryptocurrency wallet doesn’t
contain your tokens. A wallet has one or more cryptocurrency addresses, in the case of Stacks these are *Stacks token address*.
contain your tokens. A wallet has one or more cryptocurrency addresses, in the case of Stacks these are _Stacks token address_.
An address is public and can be viewed by other people much like your house is visible to any passerby. To open a particular address, you must know the address value and you must have the private key for that address. Wallets can read existing addresses to send from or create new addresses to send to. A wallet can show you the history of transactions for an address on the blockchain.
@ -20,7 +19,7 @@ Exchanging cryptocurrency requires moving currency from one address to another.
![](images/key.png)
Token exchanges are recorded by *transactions* on a blockchain. In the case of STX, these exchanges appear on the Stacks blockchain. The movement of tokens from Lena to Bitbook is recorded on the blockchain. The private key Lena uses is not recorded.
Token exchanges are recorded by _transactions_ on a blockchain. In the case of STX, these exchanges appear on the Stacks blockchain. The movement of tokens from Lena to Bitbook is recorded on the blockchain. The private key Lena uses is not recorded.
<div class="uk-card uk-card-default uk-card-body">
<h5>Security tip: What to share and what not to</h5>
@ -54,7 +53,6 @@ Custody
Solutions?](https://www.investopedia.com/news/what-are-cryptocurrency-custody-solutions/)
is one place to start.
## Choosing a cryptocurrency wallet
You can choose among different types of cryptocurrency wallets. There are mainly

20
src/pages/org/wallet-troubleshoot.md

@ -1,18 +1,20 @@
---
description: "How to use the Blockstack Software"
description: 'How to use the Blockstack Software'
---
# Wallet FAQs and Troubleshooting
This page contains frequently asked questions and troubleshooting related to the wallet.
## Frequently asked questions
{% for faq in site.data.theFAQs.faqs %}
{% if faq.category == 'wallet' %}
{% if faq.category == 'wallet' %}
### {{ faq.question }}
{{ faq.answer }}
{% endif %}
{% endif %}
{% endfor %}
## Change from a software-only wallet to a hardware wallet
@ -26,7 +28,6 @@ To change from a software-only wallet to a hardware wallet, do the following:
5. Login into your Coinlist account.
6. Change your Stacks wallet address.
## View or change your Stacks wallet address on Coinlist
If you purchased Stacks via Coinlist during in the token sale, your Stacks address is located at this URL:
@ -47,8 +48,10 @@ To view or change your Stacks address on Coinlist, do the following:
2. Enter a URL in this format:
```
https://sale.stackstoken.com/stacks-token-sale/YOUR_COINLIST_USERNAME/wallet_address
```
https://sale.stackstoken.com/stacks-token-sale/YOUR_COINLIST_USERNAME/wallet_address
```
```
3. Change your address if necessary.
@ -64,3 +67,4 @@ If you previously set up your CoinList account by logging in with your AngelList
6. Use the instructions in the recovery email to create a unique password for your CoinList account.
Going forward, you can access your CoinList account by logging in with your email and new password.
```

76
src/pages/org/wallet-use.md

@ -1,23 +1,23 @@
---
description: "Blockstack Network documentation"
description: 'Blockstack Network documentation'
---
# Use the Stacks Wallet software
This page describes how to use the Stacks Wallet software to manager your Stacks (STX) tokens. This page contains the following topics:
The Stacks Wallet software is installed on your computer, it is not a web application. You should have already [downloaded, verified, and installed the wallet software](wallet-install.html).
## Key concepts you should understand
You use Stacks Wallet software to manage STX tokens. Using the wallet you can:
You use Stacks Wallet software to manage STX tokens. Using the wallet you can:
* send STX from a specific STX address
* receive STX at a specific STX address
* view balances on an address
* review transaction history associated with an address
- send STX from a specific STX address
- receive STX at a specific STX address
- view balances on an address
- review transaction history associated with an address
To send STX, you need Bitcoin in your wallet. Bitcoin is the "gas" for transactions on the Stacks blockchain. A **_very small_** amount of Bitcoin is required to send STX. The gas price fluctuates like any market and is driven by the price of Bitcoin. Gas is not required to receive STX.
To send STX, you need Bitcoin in your wallet. Bitcoin is the "gas" for transactions on the Stacks blockchain. A **_very small_** amount of Bitcoin is required to send STX. The gas price fluctuates like any market and is driven by the price of Bitcoin. Gas is not required to receive STX.
You can use the Stacks Wallet software by itself or together with a hardware wallet. Using with a hardware wallet is recommended but not required.
@ -30,9 +30,9 @@ You can use the Stacks Wallet software by itself or together with a hardware wal
You can use any of these hardware wallets with the Stacks Wallet:
* Trezor One
* Ledger Nano S
* Ledger Blue
- Trezor One
- Ledger Nano S
- Ledger Blue
{% include note.html content="Blockstack only supports the hardware wallets listed above. Other wallets, for example, the Trezor Model T, <strong>are not supported</strong>. If you have questions about wallet support, please <a href='emailto:support@blockstack.org' target='_blank'>contact Blockstack support</a>." %}
@ -40,7 +40,7 @@ The private key on your hardware wallet is used by the Stacks Wallet software to
### Software only wallet and a seed phrase
You can use the Stacks Wallet software without a hardware device to create one or more software wallets. Each wallet has its own address which corresponds to a STX address on the Stacks blockchain. You access this address with a unique, **seed phrase**. The software generates a seed phrase for you when create a software-only wallet. The seed phrase consists of 24 words in a sequence. Both the word _and its position the sequence_ are important.
You can use the Stacks Wallet software without a hardware device to create one or more software wallets. Each wallet has its own address which corresponds to a STX address on the Stacks blockchain. You access this address with a unique, **seed phrase**. The software generates a seed phrase for you when create a software-only wallet. The seed phrase consists of 24 words in a sequence. Both the word _and its position the sequence_ are important.
Write down your seed phrase and store it in a secure location such as a safe deposit box. When you write the seed phrase down, include its position, for example,`1-frog, 2-horse, 3-building` and so on until you reach a final position `24-ocean`.
@ -56,7 +56,6 @@ If you used the original, v1, version of the wallet, you should instead begin us
The v2 version of the wallet required a hardware wallet to send and receive. You can connect this same hardware wallet to the v3 version of the Stacks Wallet software. If this is your situation, choose **Use existing wallet** when you first start the Stacks Wallet v3; you don't need to create a new wallet.
## Create a new or open an existing wallet
When you start the Stacks Wallet it prompts you to create a new or choose an existing wallet. You should create a new wallet if you have not previously connected a hardware device to the Stacks Wallet v3 software or if you do not have an existing 24 word seed phrase.
@ -92,7 +91,7 @@ When your hardware device is ready, do the following:
2. Double-click on the wallet software to open it.
3. Select **Create new wallet** or **Use existing wallet**.
If you connected your hardware device to an old version of the Stacks Wallet software, you choose **Create new wallet**. After you make this initial connection, the *next time* you start the wallet, you can choose **Use existing wallet**.
If you connected your hardware device to an old version of the Stacks Wallet software, you choose **Create new wallet**. After you make this initial connection, the _next time_ you start the wallet, you can choose **Use existing wallet**.
The system asks if you have a hardware wallet.
@ -119,7 +118,6 @@ When your hardware device is ready, do the following:
The Stacks Wallet shows the current wallet balance.
### Software only wallet
If you have an existing 24 word seed phrase from this or a previous version of the Stacks Wallet software, you don't need to create a new wallet, you can **Use existing wallet**. This procedure assumes you are creating a wallet for the first time.
@ -135,14 +133,14 @@ If you have an existing 24 word seed phrase from this or a previous version of t
4. Choose **Continue without a hardware wallet**.
The system generates a seed phrase for you and prompts you to write it down.
Don't lose your seed phrase. If you lose your seed phrase, you lose your STX tokens and can never get them back.
The system generates a seed phrase for you and prompts you to write it down.
Don't lose your seed phrase. If you lose your seed phrase, you lose your STX tokens and can never get them back.
5. Write down each word and its position, for example,` 1 - frog`.
5. Write down each word and its position, for example,`1 - frog`.
6. Store your written seed phrase in a secure location such as a safe deposit box.
7. Click **I've written down my seed phrase**.
The system prompts you to re-enter your seed phrase. The sequence numbers are out of order. For example, `5` may appear in the `1` position. Enter the corresponding `5` and `1` word as appropriate.
The system prompts you to re-enter your seed phrase. The sequence numbers are out of order. For example, `5` may appear in the `1` position. Enter the corresponding `5` and `1` word as appropriate.
8. Select **Done**.
@ -168,7 +166,6 @@ Stacks you have unlocked. The **Allocation** is the amount still locked up.
![](images/token-holder-balance.png)
## Receive Stacks
To receive Stacks: you give a STX address directly to a user via email or text, for
@ -180,7 +177,7 @@ example.
2. Email or text the address to the person or organization sending to you.
A Stacks address is a public addresses. Anyone with the address, can view the address balance or send money _**to**_ the address.
A Stacks address is a public addresses. Anyone with the address, can view the address balance or send money _**to**_ the address.
3. Look for the receipt transaction in your transaction history.
@ -190,8 +187,6 @@ example.
Blockchain transactions take time. It may be minutes or hours before the transaction is recorded in the blockchain. When the transaction is complete, you can see a receipt for the transaction in your Stacks Wallet. The **PENDING** marker goes away once the funds are recorded on the blockchain.
## Add Bitcoin gas
The Stacks Wallet uses very small amounts of Bitcoin to pay fees for sending transactions. You need very small fractions of Bitcoin (BTC) for gas. The cost of gas you need fluctuates with the market price of Bitcoin.
@ -206,16 +201,16 @@ If you attempt to send STX with your wallet and you do not have enough Bitcoin t
![](images/not-enough.png)
To increase your Bitcoin for transactions, do the following:
To increase your Bitcoin for transactions, do the following:
1. Click the <span class="uk-margin-small-center" uk-icon="cog"></span>
(settings icon) in the upper right corner of the wallet.
1. Click the <span class="uk-margin-small-center" uk-icon="cog"></span>
(settings icon) in the upper right corner of the wallet.
The system opens the **Settings** dialog.
The system opens the **Settings** dialog.
![](images/settings.png)
![](images/settings.png)
This dialog shows you how much BTC you currently have in your account.
This dialog shows you how much BTC you currently have in your account.
2. Select **Add BTC**.
@ -253,12 +248,12 @@ Sending stacks is a transaction you must authorize or sign. If you have connecte
5. Select **Continue**.
If you do not have enough Bitcoin to fuel the transaction, the system
notifies you. If you don't have enough Bitcoin, you must **Top Up**.
Otherwise, the system prompts you to connect to your hardware wallet. Your
hardware wallet will prompt you for additional information and actions.
If you do not have enough Bitcoin to fuel the transaction, the system
notifies you. If you don't have enough Bitcoin, you must **Top Up**.
Otherwise, the system prompts you to connect to your hardware wallet. Your
hardware wallet will prompt you for additional information and actions.
![](images/device-check.png)
![](images/device-check.png)
6. Select **Continue**.
@ -278,25 +273,22 @@ Sending stacks is a transaction you must authorize or sign. If you have connecte
Select **Refresh** if you don't immediately see the transaction in your
history.
## Reset the wallet
Resetting a wallet clears all your data from the Stacks Wallet and returns the
wallet to its original state.
* If you entered a Stacks address, resetting clears the address from the Stacks Wallet.
* If you connected to a hardware wallet, resetting removes the connection to the hardware wallet.
- If you entered a Stacks address, resetting clears the address from the Stacks Wallet.
- If you connected to a hardware wallet, resetting removes the connection to the hardware wallet.
Resetting the wallet does nothing to your addresses or their associated balances.
They are maintained.
Once you reset the wallet, you have to start over from the *Terms of Use*. If
Once you reset the wallet, you have to start over from the _Terms of Use_. If
you do not restart the wallet, you can simple close it.
1. Click the <span class="uk-margin-small-center" uk-icon="cog"></span>
(settings icon) in the upper right corner of the wallet.
(settings icon) in the upper right corner of the wallet.
The system opens the **Settings** dialog.

291
src/pages/storage/amazon-s3-deploy.md

@ -1,9 +1,9 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# Configure a hub on Amazon EC2
This teaches you how to run a Gaia hub on Amazon EC2. Amazon EC2 is an affordable and convenient cloud computing provider. This example uses Amazon EC2 instance together with an [EBS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonEBS.html) disk for file storage.
<div class="uk-card uk-card-default uk-card-body">
@ -20,7 +20,7 @@ This teaches you how to run a Gaia hub on Amazon EC2. Amazon EC2 is an affordabl
This procedure uses Amazon AWS to choose and configure an Amazon Machine Image
(AMI) running a Gaia service. For this reason, you should have an AWS account
on the <a href="https://aws.amazon.com/free/" target="\_blank">Amazon AWS free
tier</a>, personal account, or corporate account. These instructions assume you
tier</a>, personal account, or corporate account. These instructions assume you
are using a free tier account.
These instructions assume you have already created a free <a
@ -46,7 +46,7 @@ If `watch` is not located, install it on your workstation.
![](/storage/images/us-west-2.png)
3. Under **Build a solution** choose **Launch a virtual machine**.
3. Under **Build a solution** choose **Launch a virtual machine**.
The system opens the EC2 dashboard.
@ -71,127 +71,128 @@ If `watch` is not located, install it on your workstation.
So, the `blockstack-gaia_hub-ephemeral-2.5.3-hvm - ami-0c8fc48c10a42737e` image uses ephemeral storage, is at version `2.5.3` and has the `0c8fc48c10a42737e` tag.
6. Select the most recent version image with the storage you want. The images are not sorted; The most recent images is not necessarily at the top of the list.
6. Select the most recent version image with the storage you want. The images are not sorted; The most recent images is not necessarily at the top of the list.
After you select an image, the system displays **Step 2: Choose an Instance Type** page.
![](/storage/images/tier-2-image.png)
7. Select **t2.micro** and choose **Next: Configure Instance Details**.
To configure instance details, do the following:
<div class="uk-card uk-card-body">
<ol>
<li>
<p>Select a VPC.</p>
<p>A default VPC is created with a free tier account. You can use this
default VPC. Or you can choose another VPC. If you choose another VPC,
ensure the <code class="highlighter-rouge">Subnet</code> value is set to a subnet reachable by a public IP.
</p>
<div class="uk-alert-warning uk-alert" uk-alert=""><b>Important:</b> If you're using a private subnet, you
should attach an elastic IP (EIP) to the VM. This EIP allows you to
reboot the instance without worrying whether the address will reset. To
attach an IP, <strong>press allocate new address</strong> and follow the
instructions to <a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-eips-associating" target="_blank">attach the EIP</a> to your new EC2 instance.
</div>
</li>
<li>
<p>Set <strong>Protect against accidental termination</strong>.</p>
<p>If you terminate a Gaia instance, you lose all the data associated with it. Protection adds an extra step to terminating your Gaia instance.</p>
</li>
<li>
<p>Open the <strong>Advanced Details</strong>.</p>
<p>At this point, you are going to configure environment variables for your instance.</p>
</li>
<li>
<p>Paste the following into the <strong>Advanced Details</strong>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
{
"ignition": { "version": "2.2.0" },
"storage": {
"files": [{
"filesystem": "root",
"path": "/etc/environment",
"mode": 420,
"contents": {
"source": "data:application/octet-stream,API_KEY%3DKEYPHRASE%0ADOMAIN%3DNAME_OF_DOMAIN%0ASTAGING%3DSTAGING_VALUE"
}
}]
}
}
</code></pre></div> </div>
</li>
<li>
<p>Replace the following values in the JSON.</p>
<table class="uk-table uk-table-small uk-table-divider">
<tbody>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
<tr>
<td><code>&lt;KEYPHRASE&gt;</code></td>
<td>A phrase to pass when using the hub admin. For example, <code>hubba</code> is a fun key phrase.</td>
</tr>
<tr>
<td><code>&lt;NAME_OF_DOMAIN&gt;</code></td>
<td>Your hub's domain name. For example, <code>maryhub.ml</code> is the domain name in this example.</td>
</tr>
<tr>
<td><code>&lt;STAGING_VALUE&gt;</code></td>
<td>
<p>Indicates what type of SSL to create, testing (`1`) or production (`0`). Set testing if you want to test without worrying about rate limiting. A testing cerificate is not secure.</p>
<p>For this tutorial, use production (`0`).</p>
</td>
</tr>
</tbody>
</table>
</li>
<li>
<p>Check your <strong>Advanced Details</strong> they should look similar to the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> {
"ignition": { "version": "2.2.0" },
"storage": {
"files": [{
"filesystem": "root",
"path": "/etc/environment",
"mode": 420,
"contents": {
"source": "data:application/octet-stream,API_KEY%3Dhubba%0ADOMAIN%3Dmaryhub.ml%0ASTAGING%3D0"
}
}]
}
}
</code></pre></div> </div>
</li>
</ol>
</div>
7. Select **t2.micro** and choose **Next: Configure Instance Details**.
To configure instance details, do the following:
<div class="uk-card uk-card-body">
<ol>
<li>
<p>Select a VPC.</p>
<p>A default VPC is created with a free tier account. You can use this
default VPC. Or you can choose another VPC. If you choose another VPC,
ensure the <code class="highlighter-rouge">Subnet</code> value is set to a subnet reachable by a public IP.
</p>
<div class="uk-alert-warning uk-alert" uk-alert=""><b>Important:</b> If you're using a private subnet, you
should attach an elastic IP (EIP) to the VM. This EIP allows you to
reboot the instance without worrying whether the address will reset. To
attach an IP, <strong>press allocate new address</strong> and follow the
instructions to <a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-eips-associating" target="_blank">attach the EIP</a> to your new EC2 instance.
</div>
</li>
<li>
<p>Set <strong>Protect against accidental termination</strong>.</p>
<p>If you terminate a Gaia instance, you lose all the data associated with it. Protection adds an extra step to terminating your Gaia instance.</p>
</li>
<li>
<p>Open the <strong>Advanced Details</strong>.</p>
<p>At this point, you are going to configure environment variables for your instance.</p>
</li>
<li>
<p>Paste the following into the <strong>Advanced Details</strong>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
{
"ignition": { "version": "2.2.0" },
"storage": {
"files": [{
"filesystem": "root",
"path": "/etc/environment",
"mode": 420,
"contents": {
"source": "data:application/octet-stream,API_KEY%3DKEYPHRASE%0ADOMAIN%3DNAME_OF_DOMAIN%0ASTAGING%3DSTAGING_VALUE"
}
}]
}
}
</code></pre></div> </div>
</li>
<li>
<p>Replace the following values in the JSON.</p>
<table class="uk-table uk-table-small uk-table-divider">
<tbody>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
<tr>
<td><code>&lt;KEYPHRASE&gt;</code></td>
<td>A phrase to pass when using the hub admin. For example, <code>hubba</code> is a fun key phrase.</td>
</tr>
<tr>
<td><code>&lt;NAME_OF_DOMAIN&gt;</code></td>
<td>Your hub's domain name. For example, <code>maryhub.ml</code> is the domain name in this example.</td>
</tr>
<tr>
<td><code>&lt;STAGING_VALUE&gt;</code></td>
<td>
<p>Indicates what type of SSL to create, testing (`1`) or production (`0`). Set testing if you want to test without worrying about rate limiting. A testing cerificate is not secure.</p>
<p>For this tutorial, use production (`0`).</p>
</td>
</tr>
</tbody>
</table>
</li>
<li>
<p>Check your <strong>Advanced Details</strong> they should look similar to the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> {
"ignition": { "version": "2.2.0" },
"storage": {
"files": [{
"filesystem": "root",
"path": "/etc/environment",
"mode": 420,
"contents": {
"source": "data:application/octet-stream,API_KEY%3Dhubba%0ADOMAIN%3Dmaryhub.ml%0ASTAGING%3D0"
}
}]
}
}
</code></pre></div> </div>
</li>
</ol>
</div>
At this point, you have configured your instance details.
8. Choose **Next: Add Storage**.
8. Choose **Next: Add Storage**.
![](/storage/images/add-storage.png)
![](/storage/images/add-storage.png)
The storage is set according to the AMI you selected.
The storage is set according to the AMI you selected.
9. Choose **Next: Add tags**.
10. Optionally, add the following tags:
The tags are not required, they just apply searchable labels to an instance on an EC2 console.
* **Key** of `Purpose` with the **Value** `gaia`
* **Key** of `Name` with the **Value** `gaia-hub`
* **Key** of `Version` with the **Value** `2.5.3` (This value is an example, your version may be different.)
- **Key** of `Purpose` with the **Value** `gaia`
- **Key** of `Name` with the **Value** `gaia-hub`
- **Key** of `Version` with the **Value** `2.5.3` (This value is an example, your version may be different.)
![](/storage/images/tag-add.png)
11. Choose **Next: Configure Security Group**.
12. Create a security group with the following three types:
11) Choose **Next: Configure Security Group**.
12) Create a security group with the following three types:
<table class="uk-table uk-table-small uk-table-divider">
<tr>
@ -224,16 +225,16 @@ If `watch` is not located, install it on your workstation.
</tr>
</table>
13. Choose **Review and Launch**.
13) Choose **Review and Launch**.
The system may warn you that the selection is not free tier eligible. You can ignore this for now.
14. Press **Launch**.
14) Press **Launch**.
The system prompts you for a key pair.
15. Select **Create a new keypair** or **Choose an existing key pair**.
16. Select **Launch Instances**.
15) Select **Create a new keypair** or **Choose an existing key pair**.
16) Select **Launch Instances**.
The system launches your instance.
@ -243,7 +244,6 @@ During the launch process the machine starts and runs some initial setup process
![](/storage/images/instance-initialize.png)
## Task 2: Connect your Gaia server to your domain
Now, you are ready to test your Gaia server. This procedure ensures the Gaia services started correctly and they are configured to the domain name you provided in **Advanced Details** above.
@ -277,33 +277,32 @@ Now, you are ready to test your Gaia server. This procedure ensures the Gaia ser
7. Copy the IP and paste it in your browser.
<table class="uk-table uk-table-small uk-table-divider">
<tr>
<th>If the response is</th>
<th>Do this...</th>
</tr>
<tr>
<td><img src="{{ '/storage/images/private-connection.png' | prepend: site.baseurl }}"/></td>
<td> You should see a message that your connection is not private.
Everything is fine, continue to the next step, step 8.</td>
</tr>
<tr>
<td><img src="{{ '/storage/images/bad-connection.png' | prepend: site.baseurl }}"/></td>
<td>
<ol>
<li>Check that your domain's DNS configuration matches the public IP address of your instance.</li>
<li>Update the DNS site's configuration.</li>
<li>Restart your EC2 instance as per the <a href="#restart-services-and-reload-certificates">Restart and reload certificates</a> procedure on this page.</li>
<li>Continue with next step, step 8.</li>
</ol>
</td>
</tr>
</table>
8. Press **Advanced**.
9. Choose to proceed.
10. Extend the IP with the `PUBLIC_IP/hub_info` tag like so.
<table class="uk-table uk-table-small uk-table-divider">
<tr>
<th>If the response is</th>
<th>Do this...</th>
</tr>
<tr>
<td><img src="{{ '/storage/images/private-connection.png' | prepend: site.baseurl }}"/></td>
<td> You should see a message that your connection is not private.
Everything is fine, continue to the next step, step 8.</td>
</tr>
<tr>
<td><img src="{{ '/storage/images/bad-connection.png' | prepend: site.baseurl }}"/></td>
<td>
<ol>
<li>Check that your domain's DNS configuration matches the public IP address of your instance.</li>
<li>Update the DNS site's configuration.</li>
<li>Restart your EC2 instance as per the <a href="#restart-services-and-reload-certificates">Restart and reload certificates</a> procedure on this page.</li>
<li>Continue with next step, step 8.</li>
</ol>
</td>
</tr>
</table>
8) Press **Advanced**.
9) Choose to proceed.
10) Extend the IP with the `PUBLIC_IP/hub_info` tag like so.
You should see a response from your Gaia hub!
@ -314,7 +313,6 @@ Now, you are ready to test your Gaia server. This procedure ensures the Gaia ser
not required simple to run the hub services, Blockstack will only connect to
a hub and write to its storage over a valid `HTTPS` connection.
## Task 3: Configure a domain name
At this point, you can point a domain to your Gaia hub. Although it's not required, it is highly recommended. If you use a domain, you can migrate your instance to a different server (or even provider such as Azure or Dropbox) at any time, and still access it through the domain URL. Just point your domain at the IP address for your EC2 instance. Use an `A Record` DNS type.
@ -343,9 +341,9 @@ These instructions assume you have already created a free <a href="https://www.f
![Domain test](/storage/images/domain-test.png)
If you receive another **Your connection is not private** dialogs, take the option to proceed to your domain. The *Not secure* message should no longer appear in the browser bar. If the message does appear, try waiting a few minutes for your recent changes to propagate across the net domain servers. Then, refresh the page.
If you receive another **Your connection is not private** dialogs, take the option to proceed to your domain. The _Not secure_ message should no longer appear in the browser bar. If the message does appear, try waiting a few minutes for your recent changes to propagate across the net domain servers. Then, refresh the page.
9. Check the SSL certificate for your hub.
8. Check the SSL certificate for your hub.
Each browser has its own check procedure, for example, Chrome:
@ -354,7 +352,6 @@ These instructions assume you have already created a free <a href="https://www.f
At this point, you have the following. An EC2 instance running Gaia and a DNS
record pointing your domain to this instance.
## AWS hub tips and tricks
Once your Gaia storage hub is up and running on AWS, you may occassionally need to troubleshoot. This section contains some useful information for interacting with your EC2 instance.
@ -372,6 +369,7 @@ ssh -t -i <your keyfile.pem> core@<public ip address>
Your EC2 instance is running several `docker` services that support the Gaia hub. You can list these services using the `docker ps` command.
{% raw %}
```bash
$ docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.Names}}"
CONTAINER ID IMAGE COMMAND NAMES
@ -380,6 +378,7 @@ CONTAINER ID IMAGE COMMAND
16b229a20320 quay.io/blockstack/gaia-reader:v2.5.3 "node lib/index.js" gaia-reader
89739e338573 quay.io/blockstack/gaia-admin:v2.5.3 "docker-entrypoint.s…" gaia-admin
```
{% endraw %}
Each service plays a particular role in running your Gaia hub.
@ -419,7 +418,6 @@ Each service plays a particular role in running your Gaia hub.
</tbody>
</table>
### Locations of key files
<table class="uk-table uk-table-small uk-table-divider">
@ -513,7 +511,7 @@ This procedures requires you to interact from a workstation command line with yo
maryhub.ml has address 34.219.71.143
```
If the command returns the correct IP, the same as appears on your EC2 dashboard, stop the process with a` CTRL-C` on your keyboard.
If the command returns the correct IP, the same as appears on your EC2 dashboard, stop the process with a`CTRL-C` on your keyboard.
3. Change the permissions on your downloaded `.pem` file.
@ -542,7 +540,7 @@ This procedures requires you to interact from a workstation command line with yo
5. SSH from your workstation to reset back to first boot:
** This process will stop Gaia Hub, Nginx and remove any existing SSL certificates. It will then start the process of retrieving certificates and setting up the services again. This will not affect any existing data stored on the server.
\*\* This process will stop Gaia Hub, Nginx and remove any existing SSL certificates. It will then start the process of retrieving certificates and setting up the services again. This will not affect any existing data stored on the server.
This process requires that you know the location of the `.pem` file you downloaded when you created the keypair.
@ -556,4 +554,5 @@ This procedures requires you to interact from a workstation command line with yo
$ ssh -t -i /Users/manthony/gaia.pem -A core@34.219.71.143 "sudo systemctl restart reset-ssl-certs.service"
Connection to 34.219.71.143 closed.
```
After a few minutes, all Gaia Hub services will restart automatically and will retrieve a new SSL certificate.

13
src/pages/storage/authentication.md

@ -1,8 +1,7 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# Authentication and Gaia
Blockstack authentication is a bearer token-based authentication system. From an app user's perspective, login similar to third-party authentication techniques that they're familiar with. For an app developer, the flow is unlike the typical client-server flow of centralized sign-in services such as OAuth. With Blockstack the authentication flow happens entirely client-side.
@ -24,12 +23,12 @@ When a user chooses to "Sign in with Blockstack" on your DApp, the `redirectToSi
The app private key is application-specific. It is generated from the user's identity address private key using the `appDomain` as input. This key is deterministic, meaning that for a given Blockstack ID and domain name, the same private key is generated each time. The app private key is securely shared with the app on each authentication and encrypted by the Blockstack authenticator. The key serves three functions, it:
* is used to create the credentials that give an app access to the Gaia hub storage bucket for that specific app
* is used in the end-to-end encryption of files stored for the app on the user's Gaia hub
* serves as a cryptographic secret that apps can use to perform other cryptographic functions
- is used to create the credentials that give an app access to the Gaia hub storage bucket for that specific app
- is used in the end-to-end encryption of files stored for the app on the user's Gaia hub
- serves as a cryptographic secret that apps can use to perform other cryptographic functions
When an application writes to a Gaia hub, the authentication token, key, and the data are passed to the Gaia hub.
![Gaia writes](/storage/images/gaia-writes.png)
The token ensures the DApp has the authorization to write to the hub on the user's behalf.
The token ensures the DApp has the authorization to write to the hub on the user's behalf.

5
src/pages/storage/cliDocs.md

@ -1,8 +1,7 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# blockstack_cli reference
{% include commandline.md %}

350
src/pages/storage/config-schema.md

@ -1,203 +1,187 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# Hub configuration parameters
The following JSON schema details the possible parameters for a hub configuration:
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"argsTransport": {
"additionalProperties": false,
"properties": {
"colorize": {
"default": true,
"type": "boolean"
},
"handleExceptions": {
"default": true,
"type": "boolean"
},
"json": {
"default": false,
"type": "boolean"
},
"level": {
"default": "warn",
"enum": [
"debug",
"error",
"info",
"verbose",
"warn"
],
"type": "string"
},
"timestamp": {
"default": true,
"type": "boolean"
}
},
"type": "object"
},
"authTimestampCacheSize": {
"default": 50000,
"type": "integer"
},
"awsCredentials": {
"additionalProperties": false,
"description": "Required if `driver` is `aws`",
"properties": {
"accessKeyId": {
"type": "string"
},
"endpoint": {
"type": "string"
},
"secretAccessKey": {
"type": "string"
},
"sessionToken": {
"type": "string"
}
},
"type": "object"
},
"azCredentials": {
"additionalProperties": false,
"description": "Required if `driver` is `azure`",
"properties": {
"accountKey": {
"type": "string"
},
"accountName": {
"type": "string"
}
},
"type": "object"
},
"bucket": {
"default": "hub",
"type": "string"
},
"cacheControl": {
"default": "public, max-age=1",
"type": "string"
},
"diskSettings": {
"additionalProperties": false,
"description": "Required if `driver` is `disk`",
"properties": {
"storageRootDirectory": {
"type": "string"
}
},
"type": "object"
},
"driver": {
"enum": [
"aws",
"azure",
"disk",
"google-cloud"
],
"type": "string"
},
"gcCredentials": {
"additionalProperties": false,
"description": "Required if `driver` is `google-cloud`",
"properties": {
"credentials": {
"additionalProperties": false,
"properties": {
"client_email": {
"type": "string"
},
"private_key": {
"type": "string"
}
},
"type": "object"
},
"email": {
"type": "string"
},
"keyFilename": {
"type": "string"
},
"projectId": {
"type": "string"
}
},
"type": "object"
},
"maxFileUploadSize": {
"default": 20,
"description": "The maximum allowed POST body size in megabytes. \nThe content-size header is checked, and the POST body stream \nis monitoring while streaming from the client. \n[Recommended] Minimum 100KB (or approximately 0.1MB)",
"minimum": 0.1,
"type": "number"
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"argsTransport": {
"additionalProperties": false,
"properties": {
"colorize": {
"default": true,
"type": "boolean"
},
"handleExceptions": {
"default": true,
"type": "boolean"
},
"json": {
"default": false,
"type": "boolean"
},
"level": {
"default": "warn",
"enum": ["debug", "error", "info", "verbose", "warn"],
"type": "string"
},
"timestamp": {
"default": true,
"type": "boolean"
}
},
"type": "object"
},
"authTimestampCacheSize": {
"default": 50000,
"type": "integer"
},
"awsCredentials": {
"additionalProperties": false,
"description": "Required if `driver` is `aws`",
"properties": {
"accessKeyId": {
"type": "string"
},
"pageSize": {
"default": 100,
"maximum": 4096,
"minimum": 1,
"type": "integer"
"endpoint": {
"type": "string"
},
"port": {
"default": 3000,
"maximum": 65535,
"minimum": 0,
"type": "integer"
"secretAccessKey": {
"type": "string"
},
"proofsConfig": {
"additionalProperties": false,
"properties": {
"proofsRequired": {
"default": 0,
"type": "integer"
}
"sessionToken": {
"type": "string"
}
},
"type": "object"
},
"azCredentials": {
"additionalProperties": false,
"description": "Required if `driver` is `azure`",
"properties": {
"accountKey": {
"type": "string"
},
"accountName": {
"type": "string"
}
},
"type": "object"
},
"bucket": {
"default": "hub",
"type": "string"
},
"cacheControl": {
"default": "public, max-age=1",
"type": "string"
},
"diskSettings": {
"additionalProperties": false,
"description": "Required if `driver` is `disk`",
"properties": {
"storageRootDirectory": {
"type": "string"
}
},
"type": "object"
},
"driver": {
"enum": ["aws", "azure", "disk", "google-cloud"],
"type": "string"
},
"gcCredentials": {
"additionalProperties": false,
"description": "Required if `driver` is `google-cloud`",
"properties": {
"credentials": {
"additionalProperties": false,
"properties": {
"client_email": {
"type": "string"
},
"type": "object"
},
"readURL": {
"type": "string"
"private_key": {
"type": "string"
}
},
"type": "object"
},
"requireCorrectHubUrl": {
"default": false,
"type": "boolean"
"email": {
"type": "string"
},
"serverName": {
"default": "gaia-0",
"description": "Domain name used for auth/signing challenges. \nIf `requireCorrectHubUrl` is true then this must match the hub url in an auth payload.",
"type": "string"
"keyFilename": {
"type": "string"
},
"validHubUrls": {
"description": "If `requireCorrectHubUrl` is true then the hub specified in an auth payload can also be\ncontained within in array.",
"items": {
"type": "string"
},
"type": "array"
},
"whitelist": {
"description": "List of ID addresses allowed to use this hub. Specifying this makes the hub private \nand only accessible to the specified addresses. Leaving this unspecified makes the hub \npublicly usable by any ID.",
"items": {
"type": "string"
},
"type": "array"
"projectId": {
"type": "string"
}
},
"type": "object"
},
"required": [
"driver",
"port"
],
"type": "object"
"maxFileUploadSize": {
"default": 20,
"description": "The maximum allowed POST body size in megabytes. \nThe content-size header is checked, and the POST body stream \nis monitoring while streaming from the client. \n[Recommended] Minimum 100KB (or approximately 0.1MB)",
"minimum": 0.1,
"type": "number"
},
"pageSize": {
"default": 100,
"maximum": 4096,
"minimum": 1,
"type": "integer"
},
"port": {
"default": 3000,
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"proofsConfig": {
"additionalProperties": false,
"properties": {
"proofsRequired": {
"default": 0,
"type": "integer"
}
},
"type": "object"
},
"readURL": {
"type": "string"
},
"requireCorrectHubUrl": {
"default": false,
"type": "boolean"
},
"serverName": {
"default": "gaia-0",
"description": "Domain name used for auth/signing challenges. \nIf `requireCorrectHubUrl` is true then this must match the hub url in an auth payload.",
"type": "string"
},
"validHubUrls": {
"description": "If `requireCorrectHubUrl` is true then the hub specified in an auth payload can also be\ncontained within in array.",
"items": {
"type": "string"
},
"type": "array"
},
"whitelist": {
"description": "List of ID addresses allowed to use this hub. Specifying this makes the hub private \nand only accessible to the specified addresses. Leaving this unspecified makes the hub \npublicly usable by any ID.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": ["driver", "port"],
"type": "object"
}
```
The following is an simple example of a Gaia hub configuration:
@ -218,4 +202,4 @@ The following is an simple example of a Gaia hub configuration:
}
```
A full list of example can be found in [the Gaia repository on GitHub](https://github.com/blockstack/gaia/tree/master/hub).
A full list of example can be found in [the Gaia repository on GitHub](https://github.com/blockstack/gaia/tree/master/hub).

296
src/pages/storage/digital-ocean-deploy.md

@ -1,9 +1,9 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# Configure a hub on DigitalOcean
This teaches you how to run a Gaia storage hub on DigitalOcean (DO). DigitalOcean is an affordable and convenient cloud computing provider. This example uses DigitalOcean Spaces for file storage. A space is equivalent to AWS's S3 file storage solution.
DigitalOcean provides you with a compute machines known as a **Droplets** and storage called a **Spaces**. You need both to run a Gaia hub. The Gaia hub setup you create here, requires get a Digital Droplet with Docker pre-installed and a 250 GB Space. Droplets and storage each run for $5/month or a total of $10/month.
@ -19,19 +19,19 @@ DigitalOcean provides you with a compute machines known as a **Droplets** and st
## Prerequisites you need
You use DigitalOcean choose and configure assets for running droplets and spaces. To enable this, you must be sure to complete the prerequisites in this section.
You use DigitalOcean choose and configure assets for running droplets and spaces. To enable this, you must be sure to complete the prerequisites in this section.
You must create an account on <a href="https://digitalocean.com" target="\_blank">DigitalOcean</a>. DigitalOcean requires you to supply a credit card to create an account. You are only charged for the services you use the Gaia hub as of this writing should cost $10 USD a month.
You must create an account on <a href="https://digitalocean.com" target="\_blank">DigitalOcean</a>. DigitalOcean requires you to supply a credit card to create an account. You are only charged for the services you use the Gaia hub as of this writing should cost \$10 USD a month.
The easiest way to interact with your droplet is the DigitalOcean Console. Users who are comfortable using the secure shell (SSH) and private keys may prefer to open a local terminal on their home machine instead. To enable this, you should ensure you have the following prerequisites completed.
* Locate an existing SSH key pair on your Mac or <a href="https://help.dreamhost.com/hc/en-us/articles/115001736671-Creating-a-new-Key-pair-in-Mac-OS-X-or-Linux" target="\_blank">create a new SSH key pair</a>. Your key should have a passphrase, do not use a key pair without one.
- Locate an existing SSH key pair on your Mac or <a href="https://help.dreamhost.com/hc/en-us/articles/115001736671-Creating-a-new-Key-pair-in-Mac-OS-X-or-Linux" target="\_blank">create a new SSH key pair</a>. Your key should have a passphrase, do not use a key pair without one.
* Add the <a href="https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/to-account/" target="\_blank">SSH from your local machine to DigitalOcean</a>.
- Add the <a href="https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/to-account/" target="\_blank">SSH from your local machine to DigitalOcean</a>.
* Create a <a href="https://www.digitalocean.com/docs/api/create-personal-access-token/" target="\_blank">personal access token in DigitalOcean</a>.
- Create a <a href="https://www.digitalocean.com/docs/api/create-personal-access-token/" target="\_blank">personal access token in DigitalOcean</a>.
* Install `doctl` which is the DigitalOcean command line tool. For information on installing these, see which is the DigitalOcean command line utility. Check out their [installation instructions](https://github.com/digitalocean/doctl/blob/master/README.md#installing-doctl) to see how to install it on your computer.
- Install `doctl` which is the DigitalOcean command line tool. For information on installing these, see which is the DigitalOcean command line utility. Check out their [installation instructions](https://github.com/digitalocean/doctl/blob/master/README.md#installing-doctl) to see how to install it on your computer.
## Task 1: Create a DigitalOcean space
@ -64,13 +64,12 @@ In this task you create a **Space** which is where Gaia stores your files.
## Task 2: Enable File Listing and Set a Bucket Policy
On Digital Ocean, set **Enable File Listing**:
1. Navigate to the **Spaces** tab.
2. Select your newly created space and click **Settings**
3. Set **Enable File Listing** for your space.
3. Set **Enable File Listing** for your space.
4. Press **Save**.
On your local workstation, create a bucket policy to grant read permission on your space.
@ -79,28 +78,29 @@ On your local workstation, create a bucket policy to grant read permission on yo
2. <a href="https://www.digitalocean.com/docs/spaces/resources/s3cmd/" target="_blank">Install and configure the <strong>s3cmd</strong></a>.
3. In the current directory, use the `touch` command to create a file called `gaiahub-policy`.
```
touch gaiahub-policy
```
```
touch gaiahub-policy
```
4. Use your favorite editor to open the file.
5. Add the following policy to the file.
```json
{
"Version":"2012-10-17",
"Id": "read policy",
"Statement":[
{
"Sid":"PublicRead",
"Effect":"Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<SPACE_NAME>/*"
}
]
}
```
```json
{
"Version": "2012-10-17",
"Id": "read policy",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<SPACE_NAME>/*"
}
]
}
```
6. Edit the `Resource` line and replace the `<SPACE_NAME>` with your space name from Digital Ocean.
For example, if your space is named `meepers`, after editing the line you would have:
@ -120,7 +120,7 @@ On your local workstation, create a bucket policy to grant read permission on yo
Be sure to `SPACE_NAME` with the name of your space, for example:
```
```
s3cmd setpolicy gaiahub-policy s3://meepers
```
@ -128,23 +128,23 @@ On your local workstation, create a bucket policy to grant read permission on yo
1. On your local workstation, create a file called `gaiahub-cors.xml` that looks like this:
```xml
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedOrigin>*</AllowedOrigin>
<ExposeHeader>ETag</ExposeHeader>
<MaxAgeSeconds>0</MaxAgeSeconds>
</CORSRule>
</CORSConfiguration>
```
```xml
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedOrigin>*</AllowedOrigin>
<ExposeHeader>ETag</ExposeHeader>
<MaxAgeSeconds>0</MaxAgeSeconds>
</CORSRule>
</CORSConfiguration>
```
2. Use `s3cmd` to enact the configuration.
```
s3cmd setcors gaiahub-cors.xml s3://<SPACE_NAME>
```
```
s3cmd setcors gaiahub-cors.xml s3://<SPACE_NAME>
```
## Task 4: Create a DigitalOcean droplet
@ -165,9 +165,9 @@ In this task, you add a droplet to your account. The droplet is a droplet is a c
5. Select the **Docker** app from the options presented.
6. Scroll down to the **Choose a size** section and use the left arrow to display and select the **$5/mo** image.
6. Scroll down to the **Choose a size** section and use the left arrow to display and select the **\$5/mo** image.
This size gives you plenty of memory and disk space to run a personal hub.
This size gives you plenty of memory and disk space to run a personal hub.
7. Scroll down to the **Choose a datacenter region** section.
@ -181,11 +181,10 @@ In this task, you add a droplet to your account. The droplet is a droplet is a c
10. **Choose a hostname** for your droplet such as `moxie-gaiahub`.
11. Review your choices then click **Create** to start your droplet running.
11. Review your choices then click **Create** to start your droplet running.
At this point, your new droplet should appear in the list of resources on your DigitalOcean dashboard.
## Task 5: Open a console on your Droplet
A droplet console emulates the access you would have if you were sitting down with a keyboard and monitor attached to the actual server. In this section, you open a console on your droplet.
@ -203,7 +202,7 @@ A droplet console emulates the access you would have if you were sitting down wi
3. Choose **Access** from the control panel.
4. Select **Reset Root Password** to have DigitalOcean send you the root password.
DigitalOcean sends a temporary password to the email attached to your account. It takes a couple of minutes to reset the root password on your droplet.
DigitalOcean sends a temporary password to the email attached to your account. It takes a couple of minutes to reset the root password on your droplet.
5. Open your email and copy the password.
6. Switch back to the droplet control panel and choose **Launch Console**.
@ -225,7 +224,7 @@ A droplet console emulates the access you would have if you were sitting down wi
10. Provide and confirm a new password.
The system logins you in and gives you a welcome message. At the conclusion of the message, you are at the console prompt.
The system logins you in and gives you a welcome message. At the conclusion of the message, you are at the console prompt.
```
Welcome to DigitalOcean's One-Click Docker Droplet.
@ -246,7 +245,6 @@ A droplet console emulates the access you would have if you were sitting down wi
<p>If you find the output from ls difficult to read, try enter the following to change the console colors from the command line: <code>LS_COLORS="di=1&semi;31"</code> You can also edit your console <code>.bashrc</code>. file permanently, of course.</p>
</div>
## Task 6: Create a space key
1. In the DigitalOcean dashboard, go to the **API** page.
@ -261,13 +259,13 @@ A droplet console emulates the access you would have if you were sitting down wi
5. Press the check mark.
The system creates your key and displays both the key and its secret.
The system creates your key and displays both the key and its secret.
![Access key](/storage/images/space-access-key.png)
![Access key](/storage/images/space-access-key.png)
6. Save your secret in a secure password manager.
You should never share your secret.
You should never share your secret.
7. Leave the page up with your key and secret and go to your open console.
@ -304,9 +302,9 @@ You should have the console open as `root` on your Droplet. In this section, you
3. Copy the configuration sample to a new `config.json` file.
```
cp config.do.sample.json config.json
```
```
cp config.do.sample.json config.json
```
4. Edit your new `config.json` file with `vi` or `vim`.
@ -340,18 +338,20 @@ You should have the console open as `root` on your Droplet. In this section, you
"colorize": false,
"json": true
}
}
```
}
```
````
You'll find that the `driver` is set to `aws`. The DigitalOcean space API exactly mimics the S3 API. Since Gaia doesn't have a DigitalOcean driver, you can just use the `aws` driver with some special configuration.
You'll find that the `driver` is set to `aws`. The DigitalOcean space API exactly mimics the S3 API. Since Gaia doesn't have a DigitalOcean driver, you can just use the `aws` driver with some special configuration.
5. Set the `serverName` to the droplet you just created.
6. Set the `readURL` to the URL of the DigitalOcean space you just created.
If your space URL called `https://meepers-hub-space.sfo2.digitaloceanspaces.com `, the `readURL` name is `https://meepers-hub-space.sfo2.digitaloceanspaces.com`.
If your space URL called `https://meepers-hub-space.sfo2.digitaloceanspaces.com `, the `readURL` name is `https://meepers-hub-space.sfo2.digitaloceanspaces.com`.
7. Set the `bucket` to the name of the DigitalOcean space you just created.
If your space is called `meepers-hub-space`, the `bucket` value is `meepers-hub-space`.
If your space is called `meepers-hub-space`, the `bucket` value is `meepers-hub-space`.
8. Go back to your DigitalOcean dashboard open to your space key.
9. Copy the **Key** and paste it into the `accessKeyId` value in the `config.json` file.
@ -359,48 +359,48 @@ You should have the console open as `root` on your Droplet. In this section, you
11. In the DigitalOcean dashboard, choose the Spaces page.
12. Copy the section of your space URL that follows the name.
![Space endpoint](/storage/images/space-endpoint.png)
![Space endpoint](/storage/images/space-endpoint.png)
In this example, you would copy the `sfo2.digitaloceanspaces.com` section.
In this example, you would copy the `sfo2.digitaloceanspaces.com` section.
13. Paste the string you copied into the `endpoint` value.
14. Ensure the `proofsRequired` value is set to the number `0` (zero).
This will allow Blockstack user to write to your Gaia hub, without any social proofs required. You can change this later on, and do other things to lock-down this Gaia hub to just yourself, but that is outside the scope of this document.
At this point, the `json.config` file should be completed and appear similar to the following &&mdash;; but with your values.
```json
{
"serverName": "moxie-gaiahub",
"port": 4000,
"driver": "aws",
"readURL": "https://meepers-hub-space.sfo2.digitaloceanspaces.com",
"proofsConfig": {
"proofsRequired": 0
},
"pageSize": 20,
"bucket": "meepers-hub-space",
"awsCredentials": {
"endpoint": "sfo2.digitaloceanspaces.com",
"accessKeyId": "fb3J7AT/PGMGMPOA86EFLpx8IjGZQib99eXWjVR+QK0",
"secretAccessKey": "9ac685342eaa5bc4b44c13f3ecf43b001a3bdb9e2257114d44394d410dd91f66"
},
"argsTransport": {
"level": "debug",
"handleExceptions": true,
"stringify": true,
"timestamp": true,
"colorize": false,
"json": true
}
This will allow Blockstack user to write to your Gaia hub, without any social proofs required. You can change this later on, and do other things to lock-down this Gaia hub to just yourself, but that is outside the scope of this document.
At this point, the `json.config` file should be completed and appear similar to the following &&mdash;; but with your values.
```json
{
"serverName": "moxie-gaiahub",
"port": 4000,
"driver": "aws",
"readURL": "https://meepers-hub-space.sfo2.digitaloceanspaces.com",
"proofsConfig": {
"proofsRequired": 0
},
"pageSize": 20,
"bucket": "meepers-hub-space",
"awsCredentials": {
"endpoint": "sfo2.digitaloceanspaces.com",
"accessKeyId": "fb3J7AT/PGMGMPOA86EFLpx8IjGZQib99eXWjVR+QK0",
"secretAccessKey": "9ac685342eaa5bc4b44c13f3ecf43b001a3bdb9e2257114d44394d410dd91f66"
},
"argsTransport": {
"level": "debug",
"handleExceptions": true,
"stringify": true,
"timestamp": true,
"colorize": false,
"json": true
}
```
}
```
15. Save your config file and close the `vim` editor.
The system returns you back to the prompt.
The system returns you back to the prompt.
## Task 8: Run the Gaia image with Docker
@ -408,38 +408,42 @@ While your console is still in the the `gaia/hub` folder, build the `gaia.hub` i
1. Enter the following `docker` command at the console command line.
```
docker build -t gaia.hub .
```
This build users the `Dockerfile` already in the `gaia/hub` folder. The output of the command is similar to the following:
````
```
....
docker build -t gaia.hub .
npm WARN gaia-hub@2.3.4 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
```
This build users the `Dockerfile` already in the `gaia/hub` folder. The output of the command is similar to the following:
added 877 packages from 540 contributors and audited 3671 packages in 38.122s
found 0 vulnerabilities
```
Removing intermediate container b0aef024879f
---> 5fd126019708
Step 5/5 : CMD ["npm", "run", "start"]
---> Running in ae459cc0865b
Removing intermediate container ae459cc0865b
---> b1ced6c39784
Successfully built b1ced6c39784
Successfully tagged gaia.hub:latest
```
....
npm WARN gaia-hub@2.3.4 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
added 877 packages from 540 contributors and audited 3671 packages in 38.122s
found 0 vulnerabilities
Removing intermediate container b0aef024879f
---> 5fd126019708
Step 5/5 : CMD ["npm", "run", "start"]
---> Running in ae459cc0865b
Removing intermediate container ae459cc0865b
---> b1ced6c39784
Successfully built b1ced6c39784
Successfully tagged gaia.hub:latest
````
2. Run your Gaia hub image.
```bash
docker run --restart=always -v ~/gaia/hub/config.json:/src/hub/config.json -p 3000:3000 -e CONFIG_PATH=/src/hub/config.json gaia.hub
```
```bash
docker run --restart=always -v ~/gaia/hub/config.json:/src/hub/config.json -p 3000:3000 -e CONFIG_PATH=/src/hub/config.json gaia.hub
````
This runs your Gaia hub on port `3000`. If everything runs successfully, the last line outputted from this command should be:
This runs your Gaia hub on port `3000`. If everything runs successfully, the last line outputted from this command should be:
```bash
Successfully compiled 13 files with Babel.
@ -450,11 +454,11 @@ While your console is still in the the `gaia/hub` folder, build the `gaia.hub` i
4. Run the the image again with this new command.
```
docker run --restart=always -v ~/gaia/hub/config.json:/src/hub/config.json -p 3000:3000 -e CONFIG_PATH=/src/hub/config.json -d gaia.hub
```
```
docker run --restart=always -v ~/gaia/hub/config.json:/src/hub/config.json -p 3000:3000 -e CONFIG_PATH=/src/hub/config.json -d gaia.hub
```
This command includes `-d` option to `docker run`. This runs Docker in detached mode, so that it runs in the background. You can run `docker ps` to see your running docker images, and get the `id` of your Gaia server.
This command includes `-d` option to `docker run`. This runs Docker in detached mode, so that it runs in the background. You can run `docker ps` to see your running docker images, and get the `id` of your Gaia server.
```bash
@ -471,16 +475,16 @@ In this task, you set up a simple Nginx reverse proxy to serve your Docker conta
1. Install nginx into the droplet.
```
sudo apt-get install nginx
```
```
sudo apt-get install nginx
```
2. Enter `y` to confirm the installation.
3. Edit the nginx default configuration file.
```
vi /etc/nginx/sites-available/default
```
```
vi /etc/nginx/sites-available/default
```
4. Inside the `location /` block (line 48), enter the following configuration:
@ -504,30 +508,30 @@ In this task, you set up a simple Nginx reverse proxy to serve your Docker conta
}
more_set_headers 'Access-Control-Allow-Origin: *';
}
```
```
This simple configuration passes all requests through to your Gaia hub running at port `3000`.
5. Save and close the file.
6. Run `nginx -t` to make sure you have no syntax errors.
```
root@meepers:~/gaia/hub# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```
```
root@meepers:~/gaia/hub# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```
7. Restart `nginx` with your new configuration.
```
systemctl restart nginx
```
```
systemctl restart nginx
```
8. Allow access to your Gaia hub by exposing port 80 to the public.
```
ufw allow 80
```
```
ufw allow 80
```
## Task 10: Test your Gaia server
@ -541,14 +545,13 @@ Now, you are ready to test your Gaia server and make sure it is up and running.
3. Copy the IP address for it.
4. In your browser, visit the page `MY_DROPLET_IP/hub_info`.
You should see a response from your Gaia hub!
You should see a response from your Gaia hub!
![Hub test](/storage/images/hub-running.png)
The `read_url_prefix` should be combine from the bucket and endpoint create
in your `config.json` file, for example,
`https://meepers-hub-space.s3.amazonaws.com/`.
![Hub test](/storage/images/hub-running.png)
The `read_url_prefix` should be combine from the bucket and endpoint create
in your `config.json` file, for example,
`https://meepers-hub-space.s3.amazonaws.com/`.
## Task 11: Configure a domain name
@ -578,7 +581,6 @@ These instructions assume you have already created a free <a href="https://www.f
![Domain test](/storage/images/domain-test.png)
## Task 12: Set up SSL
If you've configured a domain to point to your Gaia hub, then it's highly

55
src/pages/storage/gaia-admin.md

@ -1,9 +1,9 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# Use the admin service
A Gaia service can run a simple administrative service co-located with your Gaia hub. This service allows you to administer the Gaia hub with the help of an API key. Gaia hubs installed using the Gaia Amazon Machine Image (AMI) have this service integrated automatically.
In this section, you learn how to use the Gaia admin service with your Gaia hub.
@ -12,20 +12,18 @@ In this section, you learn how to use the Gaia admin service with your Gaia hub.
The examples in this section assume that Gaia and the admin service
were installed through the Configure a hub on Amazon EC2." %}
## Understand the configuration files
The admin service relies on two configuration files, the hub's configuration and the configuration of the admin service itself. The hub's configuration is mounted `/tmp/hub-config/config.json` in the `docker_admin_1` container. Your EC2 instance has the admin service configuration in the `/gaia/docker/admin-config/config.json` file.
The admin service needs to know the following:
* where the Gaia hub config file is located
* which API key(s) to use when authenticating administrative requests
* which command(s) to run to restart the Gaia hub on a config change
- where the Gaia hub config file is located
- which API key(s) to use when authenticating administrative requests
- which command(s) to run to restart the Gaia hub on a config change
The following is the standard admin service config installed with your EC2 instance.
```json
{
"argsTransport": {
@ -37,16 +35,13 @@ The following is the standard admin service config installed with your EC2 insta
"json": true
},
"port": 8009,
"apiKeys": [ "hello" ],
"apiKeys": ["hello"],
"gaiaSettings": {
"configPath": "/tmp/hub-config/config.json"
},
"reloadSettings": {
"command": "/bin/sh",
"argv": [
"-c",
"docker restart docker_hub_1 &"
],
"argv": ["-c", "docker restart docker_hub_1 &"],
"env": {},
"setuid": 1000,
"setgid": 1000
@ -54,8 +49,7 @@ The following is the standard admin service config installed with your EC2 insta
}
```
The `port` is the port where Gaia is running. The `apiKeys` field is key used for making calls to the hub. The `gaiaSettings`
The `port` is the port where Gaia is running. The `apiKeys` field is key used for making calls to the hub. The `gaiaSettings`
The `argsTransport` section configures the hub logging. The service uses the `winston` logging service. Refer to their documentation for full details on the [logging configuration options](https://github.com/winstonjs/winston).
@ -128,7 +122,6 @@ The `reloadSettings` configure the command that is used to reload your Gaia hub.
</tbody>
</table>
## Using the admin service APIs
You use the admin service APIs to manage the hub. Administrating a hub requires
@ -148,11 +141,10 @@ export API_KEY="hello"
You may find it useful to install a JSON processor such as `jq` to process the
output of the admin commands.
### Restart the Gaia Hub (`POST /v1/admin/reload`)
The admin service will make changes to the Gaia hub's config file, but the
changes will only take effect when the Gaia hub is reloaded. You can do this
changes will only take effect when the Gaia hub is reloaded. You can do this
as follows:
```bash
@ -164,21 +156,21 @@ $ curl -H "Authorization: bearer $API_KEY" -X POST http://localhost:8009/v1/admi
When you `POST` to this endpoint, the admin service runs the command described
in the `reloadSettings` section of the config file. It attempts to spawn a
subprocess from the given `reloadSettings.command` binary, and pass it the
arguments given in `reloadSettings.argv`. Note that the subprocess will *NOT*
arguments given in `reloadSettings.argv`. Note that the subprocess will _NOT_
be run in a shell.
#### Errors
If you do not supply a valid API key, this method fails with HTTP 403.
This endpoint returns HTTP 500 if the reload command fails. If this
This endpoint returns HTTP 500 if the reload command fails. If this
happens, you will get back the command's exit code and possibly the signal that
killed it.
### Get the hub configuration (`GET /v1/admin/config`)
This endpoint is used to read and write a Gaia hub's non-driver-related
settings. These include the port it listens on, and its proof-checking
settings. These include the port it listens on, and its proof-checking
settings.
To read the Gaia hub settings, you would run the following:
@ -188,12 +180,11 @@ $ export API_KEY="hello"
$ curl -H "Authorization: bearer $API_KEY" http://localhost:8009/v1/admin/config {"config":{"port":4000,"proofsConfig":{"proofsRequired":0}}}
```
### Set the hub configuration (`POST /v1/admin/config`)
### Set the hub configuration (`POST /v1/admin/config`)
To set Gaia hub settings, you simply `POST` the changed JSON fields to this
endpoint.
```bash
$ export API_KEY="hello"
$ curl -H "Authorization: bearer $API_KEY" -H 'Content-Type: application/json' -X POST --data-raw '{"port": 3001}' http://localhost:8009/v1/admin/config
@ -202,10 +193,10 @@ $ curl -H "Authorization: bearer $API_KEY" -H 'Content-Type: application/json' -
If the settings were successfully applied, the method returns a message to reload your Gaia hub. You can set multiple drivers' settings with a single call. For example, you can set:
* The driver to use (`driver`)
* The Gaia's read URL endpoint (`readURL`)
* The number of items to return when listing files (`pageSize`)
* The driver-specific settings
- The driver to use (`driver`)
- The Gaia's read URL endpoint (`readURL`)
- The number of items to return when listing files (`pageSize`)
- The driver-specific settings
The data accepted on `POST` must contain a valid Hub configuration, for example:
@ -264,12 +255,12 @@ const GAIA_CONFIG_SCHEMA = {
The same fields are returned on `GET` within a `config` object.
#### Errors
If you do not supply a valid API key, both the `GET` and `POST` method fail with HTTP 403.
Only relevant Gaia hub config fields are set. If you `POST` invalid settings
Only relevant Gaia hub config fields are set. If you `POST` invalid settings
values, you get an HTTP 400 error.
## Example: Read and write driver settings
Use the `/v1/admin/config` endpoint to read and write storage driver settings. To get the current driver settings, you would run:
@ -302,14 +293,16 @@ $ curl -H "Authorization: bearer $API_KEY" http://localhost:8009/v1/admin/config
{"config":{"whitelist":["15hUKXg1URbQsmaEHKFV2vP9kCeCsT8gUu"]}}
```
To set the whitelist, you must set the *entire* whitelist. To set the list, pass a command such as the following:
To set the whitelist, you must set the _entire_ whitelist. To set the list, pass a command such as the following:
{% raw %}
```bash
$ export API_KEY="hello"
$ curl -H "Authorization: bearer $API_KEY" -H 'Content-Type: application/json' -X POST --data-raw '{"whitelist": ["1KDcaHsYJqD7pwHtpDn6sujCVQCY2e1ktw", "15hUKXg1URbQsmaEHKFV2vP9kCeCsT8gUu"]}' http://localhost:8009/v1/admin/config
{"message":"Config updated -- you should reload your Gaia hub now."}
```
{% endraw %}
## View logs for the hub or admin service

110
src/pages/storage/hello-hub-choice.md

@ -1,7 +1,5 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# Hello hub choice tutorial
@ -22,23 +20,23 @@ In this section, you build an initial React.js application called `hello-hub-cho
1. Create the `hello-hub-choice` directory.
```bash
mkdir hello-hub-choice
```
```bash
mkdir hello-hub-choice
```
2. Change into your new directory.
```bash
cd hello-hub-choice
```
```bash
cd hello-hub-choice
```
3. Use Yeoman and the Blockstack application generator to create your initial `hello-hub-choice` application.
```bash
yo blockstack
```
```bash
yo blockstack
```
You should see several interactive prompts.
You should see several interactive prompts.
{% raw %}
@ -53,15 +51,17 @@ In this section, you build an initial React.js application called `hello-hub-cho
4. Respond to the prompts to populate the initial app.
After the process completes successfully, you see a prompt similar to the following:
After the process completes successfully, you see a prompt similar to the following:
{% raw %}
```bash
...
{% raw %}
```bash
...
create public/icon-192x192.png
create public/index.html
create public/robots.txt
create public/manifest.json
```
Im all done. Running npm install for you to install the required dependencies. If this fails, try running the command yourself.
@ -82,19 +82,18 @@ In this section, you build an initial React.js application called `hello-hub-cho
npm install blockstack@18.3.0
```
Depending on your environment you may have some problems with the `npm` packages. Go ahead and fix these before continuing to the next section.
## Task 2. Start the server and view the application
When you start the server, it will create a Node.js server, start it locally,
and open your browser `http://localhost:5000`. From the root of your new application directory:
and open your browser `http://localhost:5000`. From the root of your new application directory:
1. Start the application server.
```bash
npm run start
```
```bash
npm run start
```
2. Choose **Allow**.
@ -108,7 +107,7 @@ and open your browser `http://localhost:5000`. From the root of your new applic
## Task 3: Enable hub selection
By default, the app generator assumes you want to use the default flow `redirectToSignIn()` method. In this section, you replace that method and use the `makeAuthRequest()` method instead. The `makeAuthRequest()` method takes the following parameters:
By default, the app generator assumes you want to use the default flow `redirectToSignIn()` method. In this section, you replace that method and use the `makeAuthRequest()` method instead. The `makeAuthRequest()` method takes the following parameters:
<dl class="uk-description-list">
<dt class="uk-text-lowercase">
@ -150,41 +149,40 @@ To replace the default login, do the following:
3. Replace `redirectToSignIn()` method with the `blockstack.UserSession.redirectToSignInWithAuthRequest(authRequest)` method.
```javascript
var userSession = new UserSession()
userSession.redirectToSignInWithAuthRequest(authRequest)
var userSession = new UserSession();
userSession.redirectToSignInWithAuthRequest(authRequest);
```
The `authRequest` is the authentication request generated by `makeAuthRequest()` method.
4. Immediately above the method you just added and below the `event.preventDefault()` method, construct a String `const` for the `authRequest`:
```
const authRequest = userSession.makeAuthRequest(
userSession.generateAndStoreTransitKey(),
'http://localhost:5000/',
'http://localhost:5000/manifest.json',
['store_write', 'publish_data'],
'http://localhost:5000/',
blockstack.nextHour().getTime(), {
solicitGaiaHubUrl: true
} // new options param
);
```
```
const authRequest = userSession.makeAuthRequest(
userSession.generateAndStoreTransitKey(),
'http://localhost:5000/',
'http://localhost:5000/manifest.json',
['store_write', 'publish_data'],
'http://localhost:5000/',
blockstack.nextHour().getTime(), {
solicitGaiaHubUrl: true
} // new options param
);
```
{% include note.html content="If your app is running a different port than <code>500</code>, enter that port instead. " %}
{% include note.html content="If your app is running a different port than <code>500</code>, enter that port instead. " %}
The extra `solicitGaiaHubUrl` parameter of `true` will cause the Blockstack Browser to prompt new identity creators for a storage hub URL.
5. Save and close the `public/app.js` file.
6. Make sure your app rebuilds cleanly.
## Task 4: Try the new authentication flow
Try your new authentication code.
1. Refresh the client at `http://localhost:5000/`.
2. Click *Sign in with Blockstack*.
2. Click _Sign in with Blockstack_.
The Blockstack Browser prompts you to sign in. I you are _not already authenticated_ with the browser, you should see the following:
@ -241,20 +239,25 @@ If you want to create specific sign-up flows for your DApp, you can pass a prese
do this if you have a corporate client whose employees would all like to use
your application with a company-run Gaia hub.
To suggest a Gaia hub URL, provide an additional `recommendedGaiaHubUrl` value
To suggest a Gaia hub URL, provide an additional `recommendedGaiaHubUrl` value
alongside the `solicitGaiaHubUrl`, for example:
```javascript
import {
makeAuthRequest,
redirectToSignInWithAuthRequest
} from 'blockstack';
import { makeAuthRequest, redirectToSignInWithAuthRequest } from 'blockstack';
var userSession = new UserSession()
const authRequest = userSession.makeAuthRequest(undefined, undefined, undefined, undefined, undefined, undefined, {
solicitGaiaHubUrl: true,
recommendedGaiaHubUrl: 'https://mygaiahub.com'
});
var userSession = new UserSession();
const authRequest = userSession.makeAuthRequest(
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
{
solicitGaiaHubUrl: true,
recommendedGaiaHubUrl: 'https://mygaiahub.com',
}
);
const authRequest = userSession.makeAuthRequest(
generateAndStoreTransitKey(),
@ -262,9 +265,10 @@ const authRequest = userSession.makeAuthRequest(
'http://localhost:5000/manifest.json',
['store_write', 'publish_data'],
'http://localhost:5000/',
nextHour().getTime(), {
nextHour().getTime(),
{
solicitGaiaHubUrl: true, //new options param
recommendedGaiaHubUrl: 'https://mygaiahub.com' // new options param
recommendedGaiaHubUrl: 'https://mygaiahub.com', // new options param
}
);
@ -275,6 +279,6 @@ Passing these parameters changes the storage hub URL prompt to the following:
![Gaiastorage](/storage/images/recommended-provider.png)
## Related information
[`makeAuthRequest()`](https://blockstack.github.io/blockstack.js/#makeauthrequest) method

19
src/pages/storage/hub-operation.md

@ -1,19 +1,19 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
redirect_from:
- /storage/hello-hub-choice.html
- /storage/hello-hub-choice.html
---
# Understand hub operation
This page describes the considerations hub operators must take into account when creating and operating a Gaia storage hub.
## Configuration files
You should store a JSON configuration file either in the top-level directory of
the hub server. Alternatively, you can specify a file location using the
`CONFIG_PATH` environment variable. The following is an example configuration file for Amazon S3:
`CONFIG_PATH` environment variable. The following is an example configuration file for Amazon S3:
```json
{
@ -24,8 +24,8 @@ the hub server. Alternatively, you can specify a file location using the
"pageSize": 20,
"bucket": "YOUR_BUCKET_NAME",
"awsCredentials": {
"accessKeyID": "YOUR_ACCESS_KEY",
"secretAccessKey": "YOUR_SECRET_KEY"
"accessKeyID": "YOUR_ACCESS_KEY",
"secretAccessKey": "YOUR_SECRET_KEY"
},
"argsTransport": {
"level": "debug",
@ -74,7 +74,6 @@ Past users could configure this setting as a crude spam-control mechanism.
However, for the smoothest operation of your Gaia hub, set the
`proofsConfig.proofsRequired` value to `0`.
## Open or private hubs
You can configure an open-membership storage hub or a private storage hub. An open-membership hub, as it sounds, allows any user to use the hub service. A private hub limits the use of the service. In this section, you learn about configuring each type.
@ -94,7 +93,7 @@ via _whitelisting_ the addresses allowed to write files. Recall that each applic
support application storage, your configuration must add to the whitelist each application you wish to use.
Alternatively, the user's client can use the authentication scheme and generate
an association token for each app. The user should whitelist her address, and
use her associated private key to sign each app's association token. This
an association token for each app. The user should whitelist her address, and
use her associated private key to sign each app's association token. This
removes the need to whitelist each application, but with the caveat that the
user needs to take care that her association tokens do not get misused.

17
src/pages/storage/overview.md

@ -1,8 +1,7 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# A decentralized storage architecture
The Blockstack Network stores application data using a storage system called
@ -12,7 +11,7 @@ ensures that Blockstack applications can provide users with high performance and
high availability for data reads and writes without introducing central trust
parties.
## Understand Gaia in the Blockstack architecture
## Understand Gaia in the Blockstack architecture
The following diagram depicts the Blockstack architecture and Gaia's place in it:
@ -20,7 +19,7 @@ The following diagram depicts the Blockstack architecture and Gaia's place in it
## User control or how is Gaia decentralized?
A Gaia hub runs as a service which writes to data storage. The storage itself is a simple key-value store. The hub service
A Gaia hub runs as a service which writes to data storage. The storage itself is a simple key-value store. The hub service
writes to data storage by requiring a valid authentication token from a requestor. Typically, the hub service runs on a compute resource and the storage itself on separate, dedicated storage resource. Typically, both resources belong to the same cloud computing provider.
![Gaiastorage](/storage/images/gaia-storage.png)
@ -32,8 +31,8 @@ The control of user data lies in the way that user data is accessed. When an app
1. Fetch the `zonefile` for `alice.id`.
2. Read her profile URL from her `zonefile`.
3. Fetch Alice's profile.
4. _Verify_ that the profile is signed by `alice.id`'s key
5. Read the `gaiaHubUrl` (e.g. `https://gaia.alice.org/`) out of the profile
4. _Verify_ that the profile is signed by `alice.id`'s key
5. Read the `gaiaHubUrl` (e.g. `https://gaia.alice.org/`) out of the profile
6. Fetch the file from `https://gaia.alice.org/data.txt`.
Because `alice.id` has access to her zonefile, she can change where her profile is stored. For example, she may do this if the current profile's service provider or storage is compromised. To change where her profile is stored, she changes her Gaia hub URL to another Gaia hub URL. If a user has sufficient compute and storage resources, a user may run their own Gaia Storage System and bypass a commercial Gaia hub provider all together.
@ -41,7 +40,7 @@ Because `alice.id` has access to her zonefile, she can change where her profile
{% include note.html content="Users with existing identities cannot yet migrate
their data from one hub to another." %}
Applications writing directly on behalf of `alice.id` do not need to perform a lookup. Instead, the [Blockstack authentication flow](http://blockstack.github.io/blockstack.js/index.html) provides Alice's chosen application root URL to the application. This authentication flow _is also_ within Alice's control because Alice's browser _must_ generate the authentication response.
Applications writing directly on behalf of `alice.id` do not need to perform a lookup. Instead, the [Blockstack authentication flow](http://blockstack.github.io/blockstack.js/index.html) provides Alice's chosen application root URL to the application. This authentication flow _is also_ within Alice's control because Alice's browser _must_ generate the authentication response.
## Understand data storage
@ -51,7 +50,7 @@ Client libraries (such as `blockstack.js`) are capable of providing these guaran
## Gaia versus other storage systems
Here's how Gaia stacks up against other decentralized storage systems. Features
Here's how Gaia stacks up against other decentralized storage systems. Features
that are common to all storage systems are omitted for brevity.
<table class="uk-table uk-table-striped">

11
src/pages/storage/write-to-read.md

@ -1,18 +1,16 @@
---
description: "Storing user data with Blockstack"
description: 'Storing user data with Blockstack'
---
# Storage write and read
Once a user authenticates and a DApp obtains authentication, the application interacts with Gaia through the blockstack.js library. There are two simple methods for working with data in Gaia hub: the `putFile()` and `getFile()` methods. This section goes into greater detail about the methods, how they interact with a hub, and how to use them.
## Write-to and Read-from URL Guarantees
Gaia is built on a driver model that supports many storage services. So, with
very few lines of code, you can interact with providers on Amazon S3, Dropbox,
and so forth. The simple `getFile()` and `putFile()` interfaces are kept simple
and so forth. The simple `getFile()` and `putFile()` interfaces are kept simple
because Blockstack assumes and wants to encourage a community of
open-source-data-management libraries.
@ -23,7 +21,7 @@ be able to read from the `https://myreads.com/foo/bar` URL. Note that, while the
prefix in the write-to url (for example,`myhub.service.org/store`) and the read-from URL
(`https://myreads.com`) are different, the `foo/bar` suffixes are the same.
By default, `putFile()` encrypts information while `getFile()` decrypts it by default. Data stored in an encrypted format means only the user that stored it can view it. For applications that want other users to view data, the application should set the `encrypt` option to `false`. And, corresponding, the `decrypt` option on `getFile()` should also be `false`.
By default, `putFile()` encrypts information while `getFile()` decrypts it by default. Data stored in an encrypted format means only the user that stored it can view it. For applications that want other users to view data, the application should set the `encrypt` option to `false`. And, corresponding, the `decrypt` option on `getFile()` should also be `false`.
Consistent, identical suffixes allow an application to know _exactly_ where a
written file can be read from, given the read prefix. The Gaia service defines a `hub_info` endpoint to obtain that read prefix:
@ -54,7 +52,6 @@ https://myservice.org/store/1DHvWDj834zPAkwMhpXdYbCYh4PomwQfzz/0/profile.json
When you use the `putFile()` method it takes the user data and POSTs it to the user's Gaia storage hub. The data POSTs directly to the hub, the blockchain is not used and no data is stored there. The limit on file upload is currently 25mb.
## Address-based access-control
Access control in a Gaia storage hub is performed on a per-address basis.

Loading…
Cancel
Save