From 795165358246c1e15889a3ba3c7424facb2deb03 Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 14 Jul 2020 17:03:55 -0500 Subject: [PATCH] lint: run prettier on all the files --- src/common/_includes/architecture.md | 11 +- src/common/_includes/commandline.md | 60 +- src/common/_includes/contribute_code.md | 12 +- src/common/_includes/contribute_community.md | 9 +- src/common/_includes/contribute_issues.md | 18 +- src/common/_includes/contribute_ovr.md | 7 +- src/common/_includes/create_id.md | 36 +- src/common/_includes/required-fields.md | 2 +- src/common/_includes/scaffolding.md | 2 +- src/common/_includes/sign_in.md | 12 +- src/pages/404.tsx | 4 +- src/pages/common/android_ref.md | 2 +- src/pages/common/community_ref.md | 2 +- src/pages/common/core_ref.md | 6 +- src/pages/common/ios_ref.md | 2 +- src/pages/common/javascript_ref.md | 2 +- src/pages/core/atlas/howitworks.md | 70 ++- src/pages/core/atlas/howtouse.md | 31 +- src/pages/core/atlas/overview.md | 67 ++- src/pages/core/best-practices.md | 64 +- src/pages/core/faq_developer.md | 13 +- src/pages/core/install-api.md | 9 +- src/pages/core/naming/architecture.md | 58 +- src/pages/core/naming/comparison.md | 112 ++-- src/pages/core/naming/creationhowto.md | 23 +- src/pages/core/naming/did.md | 44 +- src/pages/core/naming/forks.md | 86 +-- src/pages/core/naming/introduction.md | 155 ++--- src/pages/core/naming/manage.md | 55 +- src/pages/core/naming/namespaces.md | 89 +-- src/pages/core/naming/pickname.md | 84 +-- src/pages/core/naming/register.md | 62 +- src/pages/core/naming/resolving.md | 50 +- src/pages/core/naming/search.md | 15 +- src/pages/core/naming/subdomains.md | 78 +-- src/pages/core/naming/tutorial_subdomains.md | 35 +- src/pages/core/smart/clarityRef.md | 36 +- src/pages/core/smart/cli-wallet-quickstart.md | 4 +- src/pages/core/smart/install-source.md | 2 +- src/pages/core/smart/overview.md | 26 +- src/pages/core/smart/principals.md | 12 +- src/pages/core/smart/rpc-api.md | 24 +- src/pages/core/smart/testnet-node.md | 3 +- src/pages/core/smart/tutorial-counter.md | 104 ++-- src/pages/core/smart/tutorial-test.md | 22 +- src/pages/core/smart/tutorial.md | 40 +- src/pages/core/wire-format.md | 280 +++++---- src/pages/develop/cliDocs.md | 3 +- src/pages/develop/collection-type.md | 92 +-- src/pages/develop/collections.md | 130 ++--- src/pages/develop/connect/get-started.md | 40 +- src/pages/develop/deploy-tips.md | 26 +- src/pages/develop/overview_auth.md | 60 +- src/pages/develop/profiles.md | 35 +- src/pages/develop/radiks-collaborate.md | 25 +- src/pages/develop/radiks-intro.md | 15 +- src/pages/develop/radiks-models.md | 79 +-- src/pages/develop/radiks-server-extras.md | 18 +- src/pages/develop/radiks-setup.md | 162 +++--- src/pages/develop/storage.md | 7 +- src/pages/faqs/allFAQS.md | 10 +- src/pages/ios/tutorial.md | 547 +++++++++--------- src/pages/org/address_check.md | 6 +- src/pages/org/faq.md | 20 +- src/pages/org/overview.md | 15 +- src/pages/org/secureref.md | 13 +- src/pages/org/terms.md | 5 +- src/pages/org/token.md | 11 +- src/pages/org/tokenholders.md | 12 +- src/pages/org/wallet-install.md | 33 +- src/pages/org/wallet-intro.md | 10 +- src/pages/org/wallet-troubleshoot.md | 20 +- src/pages/org/wallet-use.md | 76 ++- src/pages/storage/amazon-s3-deploy.md | 291 +++++----- src/pages/storage/authentication.md | 13 +- src/pages/storage/cliDocs.md | 5 +- src/pages/storage/config-schema.md | 350 ++++++----- src/pages/storage/digital-ocean-deploy.md | 296 +++++----- src/pages/storage/gaia-admin.md | 55 +- src/pages/storage/hello-hub-choice.md | 110 ++-- src/pages/storage/hub-operation.md | 19 +- src/pages/storage/overview.md | 17 +- src/pages/storage/write-to-read.md | 11 +- 83 files changed, 2278 insertions(+), 2299 deletions(-) diff --git a/src/common/_includes/architecture.md b/src/common/_includes/architecture.md index 0239b6de..2d88f1c0 100644 --- a/src/common/_includes/architecture.md +++ b/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. diff --git a/src/common/_includes/commandline.md b/src/common/_includes/commandline.md index 75cd55df..c6707f74 100644 --- a/src/common/_includes/commandline.md +++ b/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 install the command line 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} @@ -50,21 +51,23 @@ To see the usage and options for the command in general, enter `blockstack-cli` - {% endfor %} +{% endfor %} +
{{ arg.format }}
{% endfor %}

 

-## 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. Download or `git clone` the command line repository code. +1. Download or `git clone` the command line repository code. 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). +``` diff --git a/src/common/_includes/contribute_code.md b/src/common/_includes/contribute_code.md index be2c2b98..bca685e7 100644 --- a/src/common/_includes/contribute_code.md +++ b/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). diff --git a/src/common/_includes/contribute_community.md b/src/common/_includes/contribute_community.md index 88025af2..8ff9a305 100644 --- a/src/common/_includes/contribute_community.md +++ b/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. diff --git a/src/common/_includes/contribute_issues.md b/src/common/_includes/contribute_issues.md index 0b151294..4e3b3202 100644 --- a/src/common/_includes/contribute_issues.md +++ b/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** — 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. diff --git a/src/common/_includes/contribute_ovr.md b/src/common/_includes/contribute_ovr.md index f49a2c78..a052ffc0 100644 --- a/src/common/_includes/contribute_ovr.md +++ b/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" %} diff --git a/src/common/_includes/create_id.md b/src/common/_includes/create_id.md index c98eff26..5e33cf08 100644 --- a/src/common/_includes/create_id.md +++ b/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. - diff --git a/src/common/_includes/required-fields.md b/src/common/_includes/required-fields.md index d9d20432..1502ae7f 100644 --- a/src/common/_includes/required-fields.md +++ b/src/common/_includes/required-fields.md @@ -53,4 +53,4 @@ Authentication Choose Blockstack; Blockstack Authentication is required to participate in Animal Kingdom. - \ No newline at end of file + diff --git a/src/common/_includes/scaffolding.md b/src/common/_includes/scaffolding.md index cac3413f..49210452 100644 --- a/src/common/_includes/scaffolding.md +++ b/src/common/_includes/scaffolding.md @@ -20,4 +20,4 @@ You use the Blockstack App Generator to create scaffolding for a starter applica -For example, to install a Vue scaffolding, you would use the `npx generator-blockstack --vue` command. \ No newline at end of file +For example, to install a Vue scaffolding, you would use the `npx generator-blockstack --vue` command. diff --git a/src/common/_includes/sign_in.md b/src/common/_includes/sign_in.md index d95327a0..5b53580c 100644 --- a/src/common/_includes/sign_in.md +++ b/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. \ No newline at end of file +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. diff --git a/src/pages/404.tsx b/src/pages/404.tsx index b4b37c6c..cbd8ca71 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -58,9 +58,7 @@ const NotFoundPage = () => { - - Looks like there's nothing here yet. - + Looks like there's nothing here yet. >> 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. diff --git a/src/pages/core/atlas/overview.md b/src/pages/core/atlas/overview.md index 7f675d35..a7ab04b0 100644 --- a/src/pages/core/atlas/overview.md +++ b/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. diff --git a/src/pages/core/best-practices.md b/src/pages/core/best-practices.md index feffd68f..26fa084e 100644 --- a/src/pages/core/best-practices.md +++ b/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. diff --git a/src/pages/core/faq_developer.md b/src/pages/core/faq_developer.md index 5a6a0400..c3fd705a 100644 --- a/src/pages/core/faq_developer.md +++ b/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 %} diff --git a/src/pages/core/install-api.md b/src/pages/core/install-api.md index e80093bb..39c1f57f 100644 --- a/src/pages/core/install-api.md +++ b/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 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 diff --git a/src/pages/core/naming/architecture.md b/src/pages/core/naming/architecture.md index 1603e249..f1702dc3 100644 --- a/src/pages/core/naming/architecture.md +++ b/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. diff --git a/src/pages/core/naming/comparison.md b/src/pages/core/naming/comparison.md index 05e5b617..475fb445 100644 --- a/src/pages/core/naming/comparison.md +++ b/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. diff --git a/src/pages/core/naming/creationhowto.md b/src/pages/core/naming/creationhowto.md index 69255477..9e82b42a 100644 --- a/src/pages/core/naming/creationhowto.md +++ b/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). - - diff --git a/src/pages/core/naming/did.md b/src/pages/core/naming/did.md index ccb8ac41..9891a263 100644 --- a/src/pages/core/naming/did.md +++ b/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 diff --git a/src/pages/core/naming/forks.md b/src/pages/core/naming/forks.md index 7e218f2f..918e965d 100644 --- a/src/pages/core/naming/forks.md +++ b/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. diff --git a/src/pages/core/naming/introduction.md b/src/pages/core/naming/introduction.md index 008bad7c..e92d63cf 100644 --- a/src/pages/core/naming/introduction.md +++ b/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 diff --git a/src/pages/core/naming/manage.md b/src/pages/core/naming/manage.md index 13586be2..f05f545a 100644 --- a/src/pages/core/naming/manage.md +++ b/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. diff --git a/src/pages/core/naming/namespaces.md b/src/pages/core/naming/namespaces.md index b5d232b0..c4d7082e 100644 --- a/src/pages/core/naming/namespaces.md +++ b/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 diff --git a/src/pages/core/naming/pickname.md b/src/pages/core/naming/pickname.md index e1cdaa28..655d6157 100644 --- a/src/pages/core/naming/pickname.md +++ b/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. diff --git a/src/pages/core/naming/register.md b/src/pages/core/naming/register.md index 98b7edd5..6df648d1 100644 --- a/src/pages/core/naming/register.md +++ b/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. diff --git a/src/pages/core/naming/resolving.md b/src/pages/core/naming/resolving.md index f94c44fc..3bce7882 100644 --- a/src/pages/core/naming/resolving.md +++ b/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)) diff --git a/src/pages/core/naming/search.md b/src/pages/core/naming/search.md index c1de09fd..cfbe68a0 100644 --- a/src/pages/core/naming/search.md +++ b/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 diff --git a/src/pages/core/naming/subdomains.md b/src/pages/core/naming/subdomains.md index c2c5fbcf..711089ae 100644 --- a/src/pages/core/naming/subdomains.md +++ b/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 diff --git a/src/pages/core/naming/tutorial_subdomains.md b/src/pages/core/naming/tutorial_subdomains.md index a49f7483..4dde491d 100644 --- a/src/pages/core/naming/tutorial_subdomains.md +++ b/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/`, `/v1/names/`, and `/v1/addresses/bitcoin/`) -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: diff --git a/src/pages/core/smart/clarityRef.md b/src/pages/core/smart/clarityRef.md index 93c09c2b..3458310b 100644 --- a/src/pages/core/smart/clarityRef.md +++ b/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 (``). +- Dynamic dispatch: the callee is passed as an argument, and typed + as a trait reference (``). ```scheme (define-public (swap (token-a ) @@ -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 + @@ -153,7 +153,6 @@ The following limitations are imposed on contract calls: - @@ -182,4 +181,3 @@ The following limitations are imposed on contract calls: - diff --git a/src/pages/core/smart/cli-wallet-quickstart.md b/src/pages/core/smart/cli-wallet-quickstart.md index 38db75da..3ef5cf42 100644 --- a/src/pages/core/smart/cli-wallet-quickstart.md +++ b/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 diff --git a/src/pages/core/smart/install-source.md b/src/pages/core/smart/install-source.md index 029f8031..b0e823a9 100644 --- a/src/pages/core/smart/install-source.md +++ b/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 diff --git a/src/pages/core/smart/overview.md b/src/pages/core/smart/overview.md index 963cd1a8..b38b6f37 100644 --- a/src/pages/core/smart/overview.md +++ b/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 — 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 diff --git a/src/pages/core/smart/principals.md b/src/pages/core/smart/principals.md index 1fb00f2b..a86e0689 100644 --- a/src/pages/core/smart/principals.md +++ b/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, diff --git a/src/pages/core/smart/rpc-api.md b/src/pages/core/smart/rpc-api.md index 7544840e..4d50e64e 100644 --- a/src/pages/core/smart/rpc-api.md +++ b/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..."] } ``` diff --git a/src/pages/core/smart/testnet-node.md b/src/pages/core/smart/testnet-node.md index a4372069..9fa34d44 100644 --- a/src/pages/core/smart/testnet-node.md +++ b/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: diff --git a/src/pages/core/smart/tutorial-counter.md b/src/pages/core/smart/tutorial-counter.md index ae889ef3..02b3ca33 100644 --- a/src/pages/core/smart/tutorial-counter.md +++ b/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 -* Clarity language reference +- Clarity language reference diff --git a/src/pages/core/smart/tutorial-test.md b/src/pages/core/smart/tutorial-test.md index e793738b..2bc1e323 100644 --- a/src/pages/core/smart/tutorial-test.md +++ b/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](). 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 -* Guide: Understanding principals -* Next tutorial: Writing a counter smart contract -* Clarity language reference +- Guide: Understanding principals +- Next tutorial: Writing a counter smart contract +- Clarity language reference diff --git a/src/pages/core/smart/tutorial.md b/src/pages/core/smart/tutorial.md index b1e65c8e..da2ef910 100644 --- a/src/pages/core/smart/tutorial.md +++ b/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 -* Next tutorial: Writing a counter smart contract -* Tutorial: Testing contracts with JavaScript and Mocha +- Next tutorial: Writing a counter smart contract +- Tutorial: Testing contracts with JavaScript and Mocha diff --git a/src/pages/core/wire-format.md b/src/pages/core/wire-format.md index 6d70418e..ba2451aa 100644 --- a/src/pages/core/wire-format.md +++ b/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 ` (2) | -| Payment scriptSig | Owner scriptPubKey (3) | +| **Inputs** | **Outputs** | +| ------------------------ | ------------------------- | +| Owner scriptSig (1) | `OP_RETURN ` (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\-_.+]*$' diff --git a/src/pages/develop/cliDocs.md b/src/pages/develop/cliDocs.md index bd88a65c..b412c085 100644 --- a/src/pages/develop/cliDocs.md +++ b/src/pages/develop/cliDocs.md @@ -1,7 +1,6 @@ --- - - --- + # Blockstack CLI Reference {% include commandline.md %} diff --git a/src/pages/develop/collection-type.md b/src/pages/develop/collection-type.md index 9043e229..edb87fdc 100644 --- a/src/pages/develop/collection-type.md +++ b/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 Collection 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 Collection 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: diff --git a/src/pages/develop/collections.md b/src/pages/develop/collections.md index 9ded4333..c96c1a2b 100644 --- a/src/pages/develop/collections.md +++ b/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 +}); ``` diff --git a/src/pages/develop/connect/get-started.md b/src/pages/develop/connect/get-started.md index 46f108e5..a7f266a0 100644 --- a/src/pages/develop/connect/get-started.md +++ b/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 = () => ( - - // the rest of your app's components - -) +const App = () => // the rest of your app's components; ``` 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 ( - - ) -} + return ; +}; ``` #### 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); ``` diff --git a/src/pages/develop/deploy-tips.md b/src/pages/develop/deploy-tips.md index 6661638b..18f5aa25 100644 --- a/src/pages/develop/deploy-tips.md +++ b/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. diff --git a/src/pages/develop/overview_auth.md b/src/pages/develop/overview_auth.md index d7927177..683b7458 100644 --- a/src/pages/develop/overview_auth.md +++ b/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 AppConfig 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 Javascript and Ruby 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`. diff --git a/src/pages/develop/profiles.md b/src/pages/develop/profiles.md index 4911a037..fb523c50 100644 --- a/src/pages/develop/profiles.md +++ b/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); ``` diff --git a/src/pages/develop/radiks-collaborate.md b/src/pages/develop/radiks-collaborate.md index 0e08fcc5..6f632424 100644 --- a/src/pages/develop/radiks-collaborate.md +++ b/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 UserGroup 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 diff --git a/src/pages/develop/radiks-intro.md b/src/pages/develop/radiks-intro.md index 4a54e4de..72591cab 100644 --- a/src/pages/develop/radiks-intro.md +++ b/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 -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). diff --git a/src/pages/develop/radiks-models.md b/src/pages/develop/radiks-models.md index 0658add2..186d22c5 100644 --- a/src/pages/develop/radiks-models.md +++ b/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 the Model class 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 the Model class 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, - }) + }); } } diff --git a/src/pages/develop/radiks-server-extras.md b/src/pages/develop/radiks-server-extras.md index 369421fe..4ecd7ca5 100644 --- a/src/pages/develop/radiks-server-extras.md +++ b/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 diff --git a/src/pages/develop/radiks-setup.md b/src/pages/develop/radiks-setup.md index 90e29673..8f8ee325 100644 --- a/src/pages/develop/radiks-setup.md +++ b/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. Download and install MongoDB 3.6 or higher 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. diff --git a/src/pages/develop/storage.md b/src/pages/develop/storage.md index 99eb3eb5..d09048e5 100644 --- a/src/pages/develop/storage.md +++ b/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 UserSession.putFile @@ -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 UserSession.deleteFile 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#) diff --git a/src/pages/faqs/allFAQS.md b/src/pages/faqs/allFAQS.md index b0047f3c..cba5bb32 100644 --- a/src/pages/faqs/allFAQS.md +++ b/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 ffinal offering circular 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 ffinal offering circular 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._ diff --git a/src/pages/ios/tutorial.md b/src/pages/ios/tutorial.md index ec58218a..c31a4e02 100644 --- a/src/pages/ios/tutorial.md +++ b/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 photoblock-demo. +If you want to download a complete application rather than working through a tutorial, see this _alternative_ sample, the photoblock-demo. ## 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 + ``` - ``` - - - - Hello, Blockstack! - - - - - ``` + ``` + + + + Hello, Blockstack! + + + + + ``` - 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: - - - - - - - - - - - - - -
Product Namehello-blockstack-ios
Organization NameUSERNAME
User InterfaceStoryboard
- - ![](images/choose-new-options.png) + + + + + + + + + + + + + +
Product Namehello-blockstack-ios
Organization NameUSERNAME
User InterfaceStoryboard
+ + ![](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 `` 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 `` tag add the following ``. ```xml - + > - - + > + > ``` 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 `` element, replace the existing `` sub-element with the following: +3. Within the `` element, replace the existing `` sub-element with the following: - ```xml - - - - - - - - - - - - - - - - - - - ``` -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 + + + + + + + + + + + + + + + + + + + ` + ``` + +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 - - - - - ``` - - Your connectors will have their own `destination` and `id` values. + ```xml + + + + + ``` + 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. diff --git a/src/pages/org/address_check.md b/src/pages/org/address_check.md index 3f18e3ef..92706afd 100644 --- a/src/pages/org/address_check.md +++ b/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. diff --git a/src/pages/org/faq.md b/src/pages/org/faq.md index af0e0a71..69054b76 100644 --- a/src/pages/org/faq.md +++ b/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 %} - - diff --git a/src/pages/org/overview.md b/src/pages/org/overview.md index 5cc01b03..70b4d66a 100644 --- a/src/pages/org/overview.md +++ b/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 the Blockstack forum. 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. diff --git a/src/pages/org/secureref.md b/src/pages/org/secureref.md index 49ddb23a..350b8b57 100644 --- a/src/pages/org/secureref.md +++ b/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 guidelines for key storage. 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. diff --git a/src/pages/org/terms.md b/src/pages/org/terms.md index f82c6f70..4f2ec14d 100644 --- a/src/pages/org/terms.md +++ b/src/pages/org/terms.md @@ -1,8 +1,7 @@ --- - -description: "Blockstack Network documentation" - +description: 'Blockstack Network documentation' --- + # Glossary diff --git a/src/pages/org/token.md b/src/pages/org/token.md index b5f66bf9..f089e2f1 100644 --- a/src/pages/org/token.md +++ b/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. 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. diff --git a/src/pages/org/tokenholders.md b/src/pages/org/tokenholders.md index ea6f9841..49f147bf 100644 --- a/src/pages/org/tokenholders.md +++ b/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 purchased Stacks tokens during Summer 2019, the form below will not work for your allocation. Please check your allocation using this tool instead. "%} -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 f help. Use the following form to check your Stacks allocation: + - @@ -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 . - ## 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. diff --git a/src/pages/org/wallet-install.md b/src/pages/org/wallet-install.md index 884ebf52..6ddbd615 100644 --- a/src/pages/org/wallet-install.md +++ b/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. Go to the wallet download page 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 on this page. - - ## Windows Installation 1. Select the **Windows Download** button on this page. @@ -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 on this page. @@ -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: -* 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, are not supported. If you have questions about wallet support, please contact Blockstack support." %} For information on setting up a hardware wallet, refer to the vendor's documentation. We cannot help you set up your hardware wallet. - - - diff --git a/src/pages/org/wallet-intro.md b/src/pages/org/wallet-intro.md index e2980341..1716c63d 100644 --- a/src/pages/org/wallet-intro.md +++ b/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.
Security tip: What to share and what not to
@@ -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 diff --git a/src/pages/org/wallet-troubleshoot.md b/src/pages/org/wallet-troubleshoot.md index 9acc3ed3..a257ba95 100644 --- a/src/pages/org/wallet-troubleshoot.md +++ b/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. +``` diff --git a/src/pages/org/wallet-use.md b/src/pages/org/wallet-use.md index 714155cd..1232eadd 100644 --- a/src/pages/org/wallet-use.md +++ b/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, are not supported. If you have questions about wallet support, please contact Blockstack support." %} @@ -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 - (settings icon) in the upper right corner of the wallet. +1. Click the + (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 - (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. diff --git a/src/pages/storage/amazon-s3-deploy.md b/src/pages/storage/amazon-s3-deploy.md index af27fa19..f002b917 100644 --- a/src/pages/storage/amazon-s3-deploy.md +++ b/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.
@@ -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 Amazon AWS free -tier, personal account, or corporate account. These instructions assume you +tier, personal account, or corporate account. These instructions assume you are using a free tier account. These instructions assume you have already created a free -
    -
  1. -

    Select a VPC.

    -

    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 Subnet value is set to a subnet reachable by a public IP. -

    -
    -
  2. -
  3. -

    Set Protect against accidental termination.

    -

    If you terminate a Gaia instance, you lose all the data associated with it. Protection adds an extra step to terminating your Gaia instance.

    -
  4. -
  5. -

    Open the Advanced Details.

    -

    At this point, you are going to configure environment variables for your instance.

    -
  6. -
  7. -

    Paste the following into the Advanced Details.

    - -
    
    -         {
    -            "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"
    -               }
    -               }]
    -            }
    -         }
    -         
    -
  8. -
  9. -

    Replace the following values in the JSON.

    - - - - - - - - - - - - - - - - - - - -
    ValueDescription
    <KEYPHRASE>A phrase to pass when using the hub admin. For example, hubba is a fun key phrase.
    <NAME_OF_DOMAIN>Your hub's domain name. For example, maryhub.ml is the domain name in this example.
    <STAGING_VALUE> -

    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.

    -

    For this tutorial, use production (`0`).

    -
    -
  10. -
  11. -

    Check your Advanced Details they should look similar to the following:

    - -
      {
    -            "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"
    -               }
    -               }]
    -            }
    -         }
    -         
    -
  12. -
-
+7. Select **t2.micro** and choose **Next: Configure Instance Details**. + + To configure instance details, do the following: + +
+
    +
  1. +

    Select a VPC.

    +

    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 Subnet value is set to a subnet reachable by a public IP. +

    +
    Important: 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, press allocate new address and follow the + instructions to attach the EIP to your new EC2 instance. +
    +
  2. +
  3. +

    Set Protect against accidental termination.

    +

    If you terminate a Gaia instance, you lose all the data associated with it. Protection adds an extra step to terminating your Gaia instance.

    +
  4. +
  5. +

    Open the Advanced Details.

    +

    At this point, you are going to configure environment variables for your instance.

    +
  6. +
  7. +

    Paste the following into the Advanced Details.

    + +
    
    +          {
    +             "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"
    +                }
    +                }]
    +             }
    +          }
    +          
    + +
  8. +
  9. +

    Replace the following values in the JSON.

    + + + + + + + + + + + + + + + + + + + +
    ValueDescription
    <KEYPHRASE>A phrase to pass when using the hub admin. For example, hubba is a fun key phrase.
    <NAME_OF_DOMAIN>Your hub's domain name. For example, maryhub.ml is the domain name in this example.
    <STAGING_VALUE> +

    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.

    +

    For this tutorial, use production (`0`).

    +
    +
  10. +
  11. +

    Check your Advanced Details they should look similar to the following:

    + +
      {
    +             "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"
    +                }
    +                }]
    +             }
    +          }
    +          
    + +
  12. +
+
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: @@ -224,16 +225,16 @@ If `watch` is not located, install it on your workstation.
-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. - - - - - - - - - - - - - -
If the response isDo this...
You should see a message that your connection is not private. - Everything is fine, continue to the next step, step 8.
-
    -
  1. Check that your domain's DNS configuration matches the public IP address of your instance.
  2. -
  3. Update the DNS site's configuration.
  4. -
  5. Restart your EC2 instance as per the Restart and reload certificates procedure on this page.
  6. -
  7. Continue with next step, step 8.
  8. -
-
- - -8. Press **Advanced**. -9. Choose to proceed. -10. Extend the IP with the `PUBLIC_IP/hub_info` tag like so. + + + + + + + + + + + + + +
If the response isDo this...
You should see a message that your connection is not private. +Everything is fine, continue to the next step, step 8.
+
    +
  1. Check that your domain's DNS configuration matches the public IP address of your instance.
  2. +
  3. Update the DNS site's configuration.
  4. +
  5. Restart your EC2 instance as per the Restart and reload certificates procedure on this page.
  6. +
  7. Continue with next step, step 8.
  8. +
+
+ +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 core@ 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. - ### Locations of key files @@ -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. diff --git a/src/pages/storage/authentication.md b/src/pages/storage/authentication.md index 9a90fb3c..fb646fd5 100644 --- a/src/pages/storage/authentication.md +++ b/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. diff --git a/src/pages/storage/cliDocs.md b/src/pages/storage/cliDocs.md index 509bf572..7badcbd0 100644 --- a/src/pages/storage/cliDocs.md +++ b/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 %} diff --git a/src/pages/storage/config-schema.md b/src/pages/storage/config-schema.md index 40136404..e7b5550f 100644 --- a/src/pages/storage/config-schema.md +++ b/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). \ No newline at end of file +A full list of example can be found in [the Gaia repository on GitHub](https://github.com/blockstack/gaia/tree/master/hub). diff --git a/src/pages/storage/digital-ocean-deploy.md b/src/pages/storage/digital-ocean-deploy.md index b7e7271e..3d33b02b 100644 --- a/src/pages/storage/digital-ocean-deploy.md +++ b/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 DigitalOcean. 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 DigitalOcean. 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 create a new SSH key pair. Your key should have a passphrase, do not use a key pair without one. +- Locate an existing SSH key pair on your Mac or create a new SSH key pair. Your key should have a passphrase, do not use a key pair without one. -* Add the SSH from your local machine to DigitalOcean. +- Add the SSH from your local machine to DigitalOcean. -* Create a personal access token in DigitalOcean. +- Create a personal access token in DigitalOcean. -* 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. Install and configure the s3cmd. 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:::/*" - } - ] - } - ``` + ```json + { + "Version": "2012-10-17", + "Id": "read policy", + "Statement": [ + { + "Sid": "PublicRead", + "Effect": "Allow", + "Principal": "*", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::/*" + } + ] + } + ``` + 6. Edit the `Resource` line and replace the `` 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 - - - GET - HEAD - * - ETag - 0 - - - ``` + ```xml + + + GET + HEAD + * + ETag + 0 + + + ``` 2. Use `s3cmd` to enact the configuration. - ``` - s3cmd setcors gaiahub-cors.xml s3:// - ``` + ``` + s3cmd setcors gaiahub-cors.xml s3:// + ``` ## 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

If you find the output from ls difficult to read, try enter the following to change the console colors from the command line: LS_COLORS="di=1;31" You can also edit your console .bashrc. file permanently, of course.

- ## 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 &—; 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 &—; 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
- ## 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 diff --git a/src/pages/storage/hello-hub-choice.md b/src/pages/storage/hello-hub-choice.md index 9eb8ff33..dc7a745b 100644 --- a/src/pages/storage/hello-hub-choice.md +++ b/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:
@@ -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 500, enter that port instead. " %} + {% include note.html content="If your app is running a different port than 500, 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 diff --git a/src/pages/storage/hub-operation.md b/src/pages/storage/hub-operation.md index e8267c1e..1f9a72b2 100644 --- a/src/pages/storage/hub-operation.md +++ b/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. diff --git a/src/pages/storage/overview.md b/src/pages/storage/overview.md index fe165420..b8bad167 100644 --- a/src/pages/storage/overview.md +++ b/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. diff --git a/src/pages/storage/write-to-read.md b/src/pages/storage/write-to-read.md index d9f33552..87cb5f90 100644 --- a/src/pages/storage/write-to-read.md +++ b/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.