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.
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 <ahref="#installCommandLine">install the command line</a> before you
can use the commands.
can use the commands.
## List of commands
{:.no_toc}
To see the usage and options for the command in general, enter `blockstack-cli` without any subcommands. To see a list of subcommands enter `blockstack-cli help`. Enter `blockstack-cli SUBCOMMAND_NAME help` to see a subcommand with its usage. The following are the available subcommands:
* TOC
{:toc}
- TOC
{:toc}
{% for entry in site.data.cliRef %}
## {{ entry.command }}
**Group**: {{ entry.group }}
@ -33,6 +33,7 @@ To see the usage and options for the command in general, enter `blockstack-cli`
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. <ahref="https://github.com/blockstack/cli-blockstack"target="\_blank">Download or `git clone` the command line repository code</a>.
1. <ahref="https://github.com/blockstack/cli-blockstack"target="\_blank">Download or `git clone` the command line repository code</a>.
Downloading or cloning the repo creates a `cli-blockstack` repository on your system.
@ -72,29 +75,38 @@ To install the command line, do the following:
```
cd cli-blockstack
```
```
```
3. Install the dependencies with `npm`.
```
npm install
```
```
npm install
```
4. Build the command line command.
```
npm run build
```
```
npm run build
```
5. Link the command.
```
sudo npm link
```
```
sudo npm link
```
### Troubleshooting the CLI installation
If you run into `EACCES` permissions errors, try the following:
* See https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally.
* Use [`Node Version Manager`](https://github.com/nvm-sh/nvm).
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
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.
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.
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" %}
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.
@ -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:
When the Blockstack App receives the request, it generates an (`authResponse`) token to the application using an _ephemeral transit key_ . The ephemeral transit key is just used for the particular instance of the application, in this case, to sign the `authRequest`. The application stores the ephemeral transit key during the request generation. The public portion of the transit key is passed in the `authRequest` token. The Blockstack App uses the public portion of the key to encrypt an _app-private key_ which is returned via the `authResponse`.
When the Blockstack App receives the request, it generates an (`authResponse`) token to the application using an _ephemeral transit key_ . The ephemeral transit key is just used for the particular instance of the application, in this case, to sign the `authRequest`. The application stores the ephemeral transit key during the request generation. The public portion of the transit key is passed in the `authRequest` token. The Blockstack App uses the public portion of the key to encrypt an _app-private key_ which is returned via the `authResponse`.
During sign in, the Blockstack App generates the app-private key from the user's _identity-address private_ key and the application's `appDomain`. The app private key serves three functions:
* It is used to create the credentials that give an app access to the Gaia storage bucket for that specific app.
* It is used in the end-to-end encryption of files stored for the app in the user's Gaia storage.
* It serves as a cryptographic secret that apps can use to perform other cryptographic functions.
- It is used to create the credentials that give an app access to the Gaia storage bucket for that specific app.
- It is used in the end-to-end encryption of files stored for the app in the user's Gaia storage.
- It serves as a cryptographic secret that apps can use to perform other cryptographic functions.
Finally, the app private key is deterministic, meaning that for a given user ID and domain name, the same private key is generated each time.
Finally, the app private key is deterministic, meaning that for a given user ID and domain name, the same private key is generated each time.
description: Interacting with the Stacks 2.0 Blockchain
---
With the launch of Stacks 2.0, a new version of the Blockstack blockchain was released. There are two ways of interacting with the blockchain, either using the Stacks Blockchain API or by making RPC calls to a Stacks Core directly.
## Stacks Core API
The Stacks 2.0 blockchain's Rust implementation exposes RPC endpoints (in JSON format), which can be used to interface with the Stacks blockchain. [You can find the RPC API references here](https://docs.blockstack.org/core/smart/rpc-api.html).
## Stacks Blockchain API
The Stacks Blockchain API was built to maintain pageable materialized views of the Stacks 2.0 Blockchain. It is a server that exposes a RESTful JSON API, hosted by PBC. It introduces aidditonal functionality (e.g. get all transactions), as well as proxies calls directly to Stacks Node. [You can find the OpenAPI specification and documentation here](https://blockstack.github.io/stacks-blockchain-sidecar/).
*Note: Using this API requires you to trust the server, but provides a faster onboarding experience. It also addresses performance issues for which querying a node itself would be too slow or difficult.*
_Note: Using this API requires you to trust the server, but provides a faster onboarding experience. It also addresses performance issues for which querying a node itself would be too slow or difficult._
{% include note.html content="If you are looking for the Stacks 1.0 RPC endpoint references, please follow [this link](https://core.blockstack.org/)." %}
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
* 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.
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.
@ -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/).
@ -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
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).
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
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. |
| `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.
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
- **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.
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:
@ -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.
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:
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);
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
*<ahref="clarityRef.html">Clarity language reference</a>
-<ahref="clarityRef.html">Clarity language reference</a>
@ -6,13 +6,13 @@ description: Learn to Test Clarity Contract Code with JavaScript and Mocha
## Overview
| Experience | | **Advanced**|
| Experience | | **Advanced** |
| Duration | | **15 minutes** |
Clarity, Blockstack's smart contracting language, is based on [LISP](https://en.wikipedia.org/wiki/Lisp_(programming_language)). Clarity is an interpreted language, and [decidable](https://en.wikipedia.org/wiki/Recursive_language). In this tutorial, you will learn how to test Clarity and how use [Mocha](https://mochajs.org/) to test Clarity contracts while you develop them.
Clarity, Blockstack's smart contracting language, is based on [LISP](<https://en.wikipedia.org/wiki/Lisp_(programming_language)>). Clarity is an interpreted language, and [decidable](https://en.wikipedia.org/wiki/Recursive_language). In this tutorial, you will learn how to test Clarity and how use [Mocha](https://mochajs.org/) to test Clarity contracts while you develop them.
* Have a working Clarity starter project
* Understand how to test Clarity code using `.ts` files and Mocha.
- Have a working Clarity starter project
- Understand how to test Clarity code using `.ts` files and Mocha.
## Prerequisites
@ -83,7 +83,7 @@ Take a few seconds to review the contents of the file. You should ignore the tes
Note that we're importing modules from the `@blockstack/clarity` package:
```js
import { Client, Provider, ProviderRegistry, Result } from "@blockstack/clarity";
import { Client, Provider, ProviderRegistry, Result } from '@blockstack/clarity';
@ -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
*<ahref="tutorial-counter.html">Next tutorial: Writing a counter smart contract</a>
*<ahref="tutorial-test.html">Tutorial: Testing contracts with JavaScript and Mocha</a>
-<ahref="tutorial-counter.html">Next tutorial: Writing a counter smart contract</a>
-<ahref="tutorial-test.html">Tutorial: Testing contracts with JavaScript and Mocha</a>
@ -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.
(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.
* `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
*`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
*`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`).
* 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.
* 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
* 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.
Collections support data portability between applications. Blockstack supplies a `Contact` collection for use by Blockstack applications. Developers can create additional collection types, use them in their own applications, and publish them so other developers can make use of them too.
In this section, you learn the coding guidelines for creating and publishing a new `Collection` type. The following topics are included:
@ -26,17 +26,17 @@ This section demonstrates how to create a new collection type using Typescript.
1. Create a new `.ts` file and open it for editing.
2. Import the `Collection` class.
```js
import { Collection, Attrs, Serializable } from 'blockstack-collections'
```
```js
import { Collection, Attrs, Serializable } from 'blockstack-collections';
```
3. Extend the abstract `Collection` class from the `blockstack-collections` package.
```js
export class Contact extends Collection implements Serializable {
...
}
```
```js
export class Contact extends Collection implements Serializable {
...
}
```
4. Give your `Collection` a unique identifier.
@ -46,57 +46,57 @@ This section demonstrates how to create a new collection type using Typescript.
static get collectionName(): string {
return 'contact'
}
```
```
{% include warning.html content="While you must specify a unique identifier, the Blockstack platform does not currently enforce uniqueness. If your <code>Collection</code> type shares the same identifier as another type, it will lead to data corruption for the user. In the future, the Blockstack platform will enforce unique collection names. " %}
{% include warning.html content="While you must specify a unique identifier, the Blockstack platform does not currently enforce uniqueness. If your <code>Collection</code> type shares the same identifier as another type, it will lead to data corruption for the user. In the future, the Blockstack platform will enforce unique collection names. " %}
5. Define a static `schema` constant.
This is your type's schema.
```js
static schema = {
identifier: String,
firstName: String,
lastName: String,
blockstackID: String,
email: String,
website: String,
address: String,
telephone: String,
organization: String
}
```
```js
static schema = {
identifier: String,
firstName: String,
lastName: String,
blockstackID: String,
email: String,
website: String,
address: String,
telephone: String,
organization: String
}
```
6. Determine if you need to set the `singleFile` storage flag.
By default, the `singleFile` flag is false. This setting causes every record in a collection to store in Gaia as a separate file. The default works well for larger types that describe data such as documents or photos. If your `Collection` type only has a few fields and is not expected to have a large number of records, set the `singleFile` data format flag to `true`.
By default, the `singleFile` flag is false. This setting causes every record in a collection to store in Gaia as a separate file. The default works well for larger types that describe data such as documents or photos. If your `Collection` type only has a few fields and is not expected to have a large number of records, set the `singleFile` data format flag to `true`.
```js
static singleFile = true
```
```js
static singleFile = true
```
7. Define the `fromObject` and `fromData` serializaiton methods.
These methods serialize and deserialize your `Collection` type. You can use any serialization method you want. Data encryption is handled automatically by the parent `Collection` class, so you *should not* perform any additional encryption.
These methods serialize and deserialize your `Collection` type. You can use any serialization method you want. Data encryption is handled automatically by the parent `Collection` class, so you _should not_ perform any additional encryption.
In the following example code, data is converted to JSON string for storage.
```js
static fromObject(object: object) {
// Create from plain Javascript object
return new Contact(object)
}
static fromData(data: string) {
// Deserialize JSON data
return new Contact(JSON.parse(data))
}
serialize() {
// Serialize to JSON string
return JSON.stringify(this.attrs)
}
```
```js
static fromObject(object: object) {
// Create from plain Javascript object
return new Contact(object)
}
static fromData(data: string) {
// Deserialize JSON data
return new Contact(JSON.parse(data))
}
serialize() {
// Serialize to JSON string
return JSON.stringify(this.attrs)
}
```
8. Test and iterate development of your type in your application.
9. Publish your type for others to use.
@ -144,7 +144,7 @@ To perform additional processing of a collection, you can override the `get`, `s
## Publish your new type for others to use
While you *can* use your collection exclusively in your application, the Collections feature is intended to enable data portability between DApps. So, you should publish your new type so other developers can make use of it.
While you _can_ use your collection exclusively in your application, the Collections feature is intended to enable data portability between DApps. So, you should publish your new type so other developers can make use of it.
To publish your Collection type, do the following:
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';
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.
| 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 = () => (
<ConnectauthOptions={authOptions}>
// the rest of your app's components
</Connect>
)
const App = () => <ConnectauthOptions={authOptions}>// the rest of your app's components</Connect>;
```
Later, when you want to begin the onboarding process, use the `useConnect` hook to get `connect`'s `doOpenAuth` method.
@ -78,12 +74,8 @@ import { useConnect } from '@blockstack/connect';
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`:
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:
| `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 <ahref="https://blockstack.github.io/blockstack.js/classes/appconfig.html"target="\_blank">AppConfig</a> object. If no `scopes` array is provided to the `redirectToSignIn` or `makeAuthRequest`
functions, the default is to request `['store_write']`.
@ -59,9 +58,9 @@ How you implement CORS depends in part on which platform/service you use to serv
Blockstack Auth makes extensive use of public key cryptography. Blockstack uses ECDSA with the `secp256k1` curve. The following sections describe the three public-private key pairs used in the authentication process:
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 <ahref='https://github.com/blockstack/jsontokens-js'>Javascript</a> and <ahref='https://github.com/blockstack/ruby-jwt-blockstack'>Ruby</a> available on the Blockstack Github to allow you to work with these tokens." %}
### Example: authRequest payload schema
```JavaScript
```JavaScript
const requestPayload = {
jti, // UUID
iat, // JWT creation time in seconds
@ -131,7 +129,6 @@ const requestPayload = {
}
```
### Example: authResponse payload schema
```JavaScript
@ -163,28 +160,23 @@ To decode the token and see what information it holds:
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 `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`.
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';
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 <ahref="https://github.com/blockstack/radiks/blob/master/src/models/user-group.ts"target="_blank"><code>UserGroup</code></a> class to build a collaborative group with Radiks. In this section, you learn about this class.
## Understand the UserGroup workflow
The key model behind a collaborative group is `UserGroup`. By default, it only has one attribute, `name`, which is encrypted. You can subclass `UserGroup` with different attributes as needed.
The key model behind a collaborative group is `UserGroup`. By default, it only has one attribute, `name`, which is encrypted. You can subclass `UserGroup` with different attributes as needed.
The general workflow for creating a collaborative group that can share and edit encrypted models is as follows:
1. The admin of the group creates a new `UserGroup`.
This group acts as the 'hub' and controls the logic around inviting and removing users.
2. The admin invites one or more other users to a group:
* The admin specifies the username of the user they want to invite
* Radiks looks up the user's public key
* Radiks creates an 'invitation' that is encrypted with the user's public key, and contains information about the `UserGroup`
- The admin specifies the username of the user they want to invite
- Radiks looks up the user's public key
- Radiks creates an 'invitation' that is encrypted with the user's public key, and contains information about the `UserGroup`
3. When the invited user 'activates' an invitation, they create a `GroupMembership`.
They use this membership instance to reference information (such as private keys and signing keys) related to the group.
@ -44,7 +44,6 @@ import { UserGroup } from 'radiks';
Calling `create` on a new `UserGroup` will create the group and activate an invitation for the group's creator.
```javascript
const group = new UserGroup({ name: 'My Group Name' });
await group.create();
@ -52,7 +51,6 @@ await group.create();
A group's creator is also the group's admin.
### Invite users to become members
Use the `makeGroupMembership` method on a `UserGroup` instance to invite a user. The only argument passed to this method is the user's `username`.
@ -70,21 +68,20 @@ console.log(invitation._id); // the ID used to later activate an invitation
You can also create a generic invitation that any user can activate, if they are provided with randomly generated secret key, which should be used to decrypt the invitation. The key is generated when the generic invitation is being created.
~~~javascript
```javascript
import { GenericGroupInvitation, UserGroup } from 'radiks';
const group = await UserGroup.findById(myGroupId);
The Blockstack Radiks feature enables Blockstack decentralized applications (DApps) to index and store across data belonging to multiple users. Radiks works with Blockstack's Gaia Storage System. Using Radiks, you can build multi-player DApps that:
The Blockstack Radiks feature enables Blockstack decentralized applications (DApps) to index and store across data belonging to multiple users. Radiks works with Blockstack's Gaia Storage System. Using Radiks, you can build multi-player DApps that:
- index, store, and query application data
- query a user's publicly saved data
- display real-time updates that reflect in progress changes
- support collaboration among sets of users
## Why use Radiks?
Many applications serve data that users create to share publicly with others. Facebook, Twitter, and Instagram are examples of such applications. Decentralized applications that want to create comparable multi-user experiences must ensure that anything a user creates for public sharing is still under control of the creator in the user's Gaia storage.
Many applications serve data that users create to share publicly with others. Facebook, Twitter, and Instagram are examples of such applications. Decentralized applications that want to create comparable multi-user experiences must ensure that anything a user creates for public sharing is still under control of the creator in the user's Gaia storage.
For example, if Twitter wanted to be a decentralized application while still having many different users creating their own tweets, those tweets would be stored in each user's own Gaia storage. In such a situation, Twitter still needs a way to keep track of everyone's tweets, display those tweets in user timelines, and perform searches across the platform. Radiks exists to support these kinds of scenarios. It allows applications to query across multiple user data using complicated queries like text search, joins, and filters.
@ -33,9 +30,9 @@ Radiks can store both public and sensitive, non-public data since all data is en
## How Radiks authorizes writes
Radiks must ensure that the user is writing to their own data. To ensure this, Radiks creates and manages *signing keys*. These keys sign all writes that a user performs. Radiks server-validates all signatures before performing a write. This guarantees that a user is not able to overwrite another user's data.
Radiks must ensure that the user is writing to their own data. To ensure this, Radiks creates and manages _signing keys_. These keys sign all writes that a user performs. Radiks server-validates all signatures before performing a write. This guarantees that a user is not able to overwrite another user's data.
A Radiks server is also built to support writes in a collaborative but private situation. For example, consider a collaborative document editing application, where users can create organizations and invite users to that organization. All users in that organization should have read and write privileges to the organization data. Thus, these organizations will have a single shared key that is used to sign and encrypt data.
A Radiks server is also built to support writes in a collaborative but private situation. For example, consider a collaborative document editing application, where users can create organizations and invite users to that organization. All users in that organization should have read and write privileges to the organization data. Thus, these organizations will have a single shared key that is used to sign and encrypt data.
When an organization administrator needs to remove a user from the group, they are expected to revoke the previous key and create a new one. Radiks is aware of these relationships, and will only support writes that are signed with the currently active key related to an organization.
@ -65,5 +62,5 @@ Although Radiks applications rely on a centrally-hosted database, an application
</tr>
</table>
If you are not familiar with Gaia, see
If you are not familiar with Gaia, see
[read the Gaia documentation](({{site.baseurl}}/storage/overview.html).
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 <ahref="https://github.com/blockstack/radiks/blob/master/src/model.ts"target="_blank">the <code>Model</code> class</a> in the `radiks` repo to get an overview of the class functionality.
Then, create a class that extends this model, and provide a schema. Refer to <ahref="https://github.com/blockstack/radiks/blob/master/src/model.ts"target="_blank">the <code>Model</code> class</a> in the `radiks` repo to get an overview of the class functionality.
Your new class must define a static `className` property. This property is used when storing and querying information. If you fail to add a `className`, Radiks defaults to the actual model's class name (`foobar.ts`) and your application will behave unpredictably.
Your new class must define a static `className` property. This property is used when storing and querying information. If you fail to add a `className`, Radiks defaults to the actual model's class name (`foobar.ts`) and your application will behave unpredictably.
The example class code extends `Model` to create a class named `Todo`:
@ -24,11 +24,12 @@ import { Model, User } from 'radiks';
class Todo extends Model {
static className = 'Todo';
static schema = { // all fields are encrypted by default
static schema = {
// all fields are encrypted by default
title: String,
completed: Boolean,
}
};
};
}
// after authentication:
const todo = new Todo({ title: 'Use Radiks in an app' });
@ -38,8 +39,9 @@ todo.update({
});
await todo.save();
const incompleteTodos = await Todo.fetchOwnList({ // fetch todos that this user created
completed: false
const incompleteTodos = await Todo.fetchOwnList({
// fetch todos that this user created
completed: false,
});
console.log(incompleteTodos.length); // 0
```
@ -55,14 +57,15 @@ Every class must have a static `schema` property which defines the attributes of
```javascript
class Todo extends Model {
static className = 'Todo';
static schema = { // all fields are encrypted by default
static schema = {
// all fields are encrypted by default
title: String,
completed: Boolean,
}
};
};
}
```
The `key` in this object is the field name and the value, for example,`String`, `Boolean`, or `Number`. In this case, the `title` is a `String` field. Alternatively, you can pass options instead of a type.
The `key` in this object is the field name and the value, for example, `String`, `Boolean`, or `Number`. In this case, the `title` is a `String` field. Alternatively, you can pass options instead of a type.
To define options, pass an object, with a mandatory `type` field. The only supported option right now is `decrypted`. This defaults to `false`, meaning the field is encrypted before the data is stored publicly. If you specify `true`, then the field is not encrypted.
@ -86,13 +89,13 @@ class Person extends Model {
isHuman: Boolean,
likesDogs: {
type: Boolean,
decrypted: true // all users will know if this record likes dogs!
}
}
decrypted: true, // all users will know if this record likes dogs!
},
};
static defaults = {
likesDogs: true
}
likesDogs: true,
};
}
```
@ -123,12 +126,11 @@ The default `User` model defines a `username`, but you can add a `displayName` t
In this section, you learn how to use a model you have defined.
### About the _id attribute
### About the \_id attribute
All model instances have an `_id` attribute. An `_id` is used as a primary key when storing data and is used for fetching a model. Radiks also creates a `createdAt` and `updatedAt` property when creating and saving models.
If, when constructing a model's instance, you don't pass an `_id`, Radiks creates an `_id` for you automatically. This automatically created id uses the [`uuid/v4`](https://github.com/kelektiv/node-uuid) format. This automatic `_id` is returned by the constructor.
If, when constructing a model's instance, you don't pass an `_id`, Radiks creates an `_id` for you automatically. This automatically created id uses the [`uuid/v4`](https://github.com/kelektiv/node-uuid) format. This automatic `_id` is returned by the constructor.
### Construct a model instance
@ -138,19 +140,18 @@ To create an instance, pass some attributes to the constructor of that class:
const person = new Person({
name: 'Hank',
isHuman: false,
likesDogs: false // just an example, I love dogs!
})
likesDogs: false, // just an example, I love dogs!
});
```
### Fetch an instance
To fetch an existing instance of an instance, you need the instance's `id` property. Then, call the `findById()` method or the `fetch()` method, which returns a promise.
To fetch an existing instance of an instance, you need the instance's `id` property. Then, call the `findById()` method or the `fetch()` method, which returns a promise.
```javascript
const person = await Person.findById('404eab3a-6ddc-4ba6-afe8-1c3fff464d44');
```
After calling these methods, Radiks automatically decrypts all encrypted fields.
### Access attributes
@ -169,9 +170,9 @@ To quickly update multiple attributes of an instance, pass those attributes to t
```javascript
const newAttributes = {
likesDogs: false,
age: 30
}
person.update(newAttributes)
age: 30,
};
person.update(newAttributes);
```
Important, calling `update` does **not** save the instance.
@ -217,14 +218,14 @@ class Task extends Model {
order: {
type: Number,
decrypted: true,
}
}
},
};
}
const tasks = await Task.fetchList({
completed: false,
sort: '-order'
})
sort: '-order',
});
```
You can read the [`query-to-mongo`](https://github.com/pbatey/query-to-mongo) package documentation to learn how to do complex querying, sorting, limiting, and so forth.
@ -244,7 +245,7 @@ Use the `fetchOwnList` method to find instances that were created by the current
```javascript
const tasks = await Task.fetchOwnList({
completed: false
completed: false,
});
```
@ -276,8 +277,8 @@ Whenever you save a task, you should save a reference to the project it's in:
```javascript
const task = new Task({
name: 'Improve radiks documentation',
projectId: project._id
})
projectId: project._id,
});
await task.save();
```
@ -286,7 +287,7 @@ Then, later you'll want to fetch all tasks for a certain project:
```javascript
const tasks = await Task.fetchList({
projectId: project._id,
})
});
```
Radiks lets you define an `afterFetch` method. Use this method to automatically fetch child records when you fetch the parent instance.
@ -294,12 +295,12 @@ Radiks lets you define an `afterFetch` method. Use this method to automatically
[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,
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. <ahref="https://docs.mongodb.com/manual/administration/install-community/"target="_blank">Download and install MongoDB 3.6 or higher</a> on your workstation.
You can also install MongoDB using your favorite package manager; for example, Homebrew is recommended for macOS. If you are testing on a local workstation, you can use a `docker` image instead of installing locally.
You can also install MongoDB using your favorite package manager; for example, Homebrew is recommended for macOS. If you are testing on a local workstation, you can use a `docker` image instead of installing locally.
2. Start the MongoDB service and verify it is running.
@ -27,34 +27,35 @@ In the future, Radiks-server will support various different databases, but right
4. Create a username/password combination with `root` privileges on your new database.
### Install and start the Radiks server
The easiest way to run `radiks-server` is to use the pre-packaged `node.js` server.
1. Install the `radiks-server` on a workstation or server.
```bash
npm install -g radiks-server
```
Or, if you prefer `yarn`:
```bash
npm install -g radiks-server
```
```bash
yarn global add radiks-server
```
The default port for Mongodb is `27017`; your instance may be configured differently. By default, Radiks-server will use `'mongodb://localhost:27017/radiks-server'` as the `MongoDB_URI` value. This is suitable for local testing, but in production, you'll want to change the hostname and possibly the database name.
Or, if you prefer `yarn`:
3. Start the `radiks-server` in the command line to confirm your installation.
```bash
yarn global add radiks-server
```
The default port for Mongodb is `27017`; your instance may be configured differently. By default, Radiks-server will use `'mongodb://localhost:27017/radiks-server'` as the `MongoDB_URI` value. This is suitable for local testing, but in production, you'll want to change the hostname and possibly the database name.
2. Start the `radiks-server` in the command line to confirm your installation.
```
$ radiks-server
(node:37750) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
radiks-server is ready on http://localhost:1260
```
radiks-server is ready on http://localhost:1260
```
The `radiks-server` defaults to running on port `1260`. To change the default port, specify the `PORT` environment variable in your environment.
The `radiks-server` defaults to running on port `1260`. To change the default port, specify the `PORT` environment variable in your environment.
4. By default, the server is running at `http://localhost:1260`
3. By default, the server is running at `http://localhost:1260`
4. Stop the `radiks` server process after you confirm it runs, and your installation was a success.
@ -88,42 +89,42 @@ If you are using `blockstack.js` version 18 or earlier, you must use the Radiks
1. Start the mongo shell application.
```
$ mongo
MongoDB shell version v4.2.0
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
## 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.
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 <ahref="https://blockstack.github.io/blockstack.js/classes/usersession.html#putfile"target="_blank">UserSession.putFile</a>
@ -82,6 +80,7 @@ var userSession = new UserSession()
```
## Reading another user's unencrypted file
In order for files to be publicly readable, the app must request
You use the <ahref="https://blockstack.github.io/blockstack.js/classes/usersession.html#deletefile"target="_blank">UserSession.deleteFile</a> from the application's data store.
```JavaScript
var userSession = new UserSession()
@ -115,4 +113,5 @@ var userSession = new UserSession()
```
## Related Information
To learn more about the guarantees provided by Gaia, see [Storage write and read]({{ site.baseurl }}/storage/write-to-read.html#)
This is a comprehensive list of all the Blockstack FAQs.
@ -98,10 +98,10 @@ This is a comprehensive list of all the Blockstack FAQs.
## Important disclaimer
*The Securities and Exchange Commission (SEC) has qualified the offering statement that we have filed with the SEC under Regulation A for our offering of certain of our Stacks Tokens. The information in that offering statement is more complete than the information we are providing now, and could differ in important ways. You must read the documents filed with the SEC before investing. The offering is being made only by means of its offering statement. This document shall not constitute an offer to sell or the solicitation of an offer to buy, nor shall there be any sale of these securities in any state or jurisdiction in which such offer, solicitation or sale would be unlawful prior to registration or qualification under the securities laws of any such state or jurisdiction.*
_The Securities and Exchange Commission (SEC) has qualified the offering statement that we have filed with the SEC under Regulation A for our offering of certain of our Stacks Tokens. The information in that offering statement is more complete than the information we are providing now, and could differ in important ways. You must read the documents filed with the SEC before investing. The offering is being made only by means of its offering statement. This document shall not constitute an offer to sell or the solicitation of an offer to buy, nor shall there be any sale of these securities in any state or jurisdiction in which such offer, solicitation or sale would be unlawful prior to registration or qualification under the securities laws of any such state or jurisdiction._
*An indication of interest involves no obligation or commitment of any kind. Any person interested in investing in any offering of Stacks Tokens should review our disclosures and the publicly filed offering statement and the f<ahref='https://stackstoken.com/circular'>final offering circular</a>that is part of that offering statement. Blockstack is not registered, licensed or supervised as a broker dealer or investment adviser by the SEC, the Financial Industry Regulatory Authority (FINRA) or any other financial regulatory authority or licensed to provide any financial advice or services.*
_An indication of interest involves no obligation or commitment of any kind. Any person interested in investing in any offering of Stacks Tokens should review our disclosures and the publicly filed offering statement and the f<ahref='https://stackstoken.com/circular'>final offering circular</a> that is part of that offering statement. Blockstack is not registered, licensed or supervised as a broker dealer or investment adviser by the SEC, the Financial Industry Regulatory Authority (FINRA) or any other financial regulatory authority or licensed to provide any financial advice or services._
## Forward-looking statements
*This communication contains forward-looking statements that are based on our beliefs and assumptions and on information currently available to us. In some cases, you can identify forward-looking statements by the following words: “will,” “expect,” “would,” “intend,” “believe,” or other comparable terminology. Forward-looking statements in this document include, but are not limited to, statements about our plans for developing the platform and future utility for the Stacks Token, our Clarity smart contracting language, and potential mining operations. These statements involve risks, uncertainties, assumptions and other factors that may cause actual results or performance to be materially different. More information on the factors, risks and uncertainties that could cause or contribute to such differences is included in our filings with the SEC, including in the “Risk Factors” and “Management’s Discussion & Analysis” sections of our offering statement on Form 1-A. We cannot assure you that the forward-looking statements will prove to be accurate. These forward-looking statements speak only as of the date hereof. We disclaim any obligation to update these forward-looking statements.*
_This communication contains forward-looking statements that are based on our beliefs and assumptions and on information currently available to us. In some cases, you can identify forward-looking statements by the following words: “will,” “expect,” “would,” “intend,” “believe,” or other comparable terminology. Forward-looking statements in this document include, but are not limited to, statements about our plans for developing the platform and future utility for the Stacks Token, our Clarity smart contracting language, and potential mining operations. These statements involve risks, uncertainties, assumptions and other factors that may cause actual results or performance to be materially different. More information on the factors, risks and uncertainties that could cause or contribute to such differences is included in our filings with the SEC, including in the “Risk Factors” and “Management’s Discussion & Analysis” sections of our offering statement on Form 1-A. We cannot assure you that the forward-looking statements will prove to be accurate. These forward-looking statements speak only as of the date hereof. We disclaim any obligation to update these forward-looking statements._
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 <ahref="https://github.com/blockstack/photoblock-demo"target="_blank">photoblock-demo</a>.
If you want to download a complete application rather than working through a tutorial, see this _alternative_ sample, the <ahref="https://github.com/blockstack/photoblock-demo"target="_blank">photoblock-demo</a>.
## Understand the sample application flow
@ -102,62 +102,62 @@ In this section, you build an initial React.js application called
1. Create a `hello-blockstack` directory.
```bash
mkdir hello-blockstack
```
```bash
mkdir hello-blockstack
```
2. Change into your new directory.
```bash
cd hello-blockstack
```
```bash
cd hello-blockstack
```
3. Create your initial `hello-world-tutorial` application.
```bash
$ npx generator-blockstack --react
npx: installed 338 in 13.792s
create package.json
create .gitignore
create webpack.config.js
create netlify.toml
create firebase.json
...
I'm all done. Running npm install for you to install the required dependencies. If this fails, try running the command yourself.
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:
<tableclass="uk-table uk-table-small">
<tr>
<th>Product Name</th>
<td><code>hello-blockstack-ios</code></td>
</tr>
<tr>
<th>Organization Name</th>
<td><code><i>USERNAME</i></code></td>
</tr>
<tr>
<th>User Interface</th>
<td>Storyboard</td>
</tr>
</table>
![](images/choose-new-options.png)
<tableclass="uk-table uk-table-small">
<tr>
<th>Product Name</th>
<td><code>hello-blockstack-ios</code></td>
</tr>
<tr>
<th>Organization Name</th>
<td><code><i>USERNAME</i></code></td>
</tr>
<tr>
<th>User Interface</th>
<td>Storyboard</td>
</tr>
</table>
![](images/choose-new-options.png)
6. Press **Next**.
@ -288,7 +286,6 @@ menu items and therefore these procedures may be differœent on your version.
8. Close XCode.
### Add and edit a Podfile
To use CocoaPods you need to define the XCode target to link them to.
@ -299,16 +296,17 @@ lines after.
1. Open a terminal window on your workstation.
2. Change directory into your new project directory where your `hello-blockstack-ios.xcodeproj` file was created.
```swift
$ cd hello-blockstack-ios
```
```swift
$ cd hello-blockstack-ios
```
3. Create a Podfile.
```bash
$ pod init
```
```bash
$ pod init
```
The command creates a `Podfile` in the directory.
The command creates a `Podfile` in the directory.
4. Open the `Podfile` for editing.
5. Add a line stating the Blockstack dependency.
@ -318,20 +316,20 @@ lines after.
# platform :ios, '9.0'
target 'hello-blockstack-ios' do
#Commentthe next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
s
!
#Podsfor hello-blockstack-ios
pod 'Blockstack'
s
'
target'hello-blockstack-iosTests'do
inherit! :search_paths
# Pods for testing
end
o
s
g
d
end
```
8. Save and close the `Podfile`.
6. Save and close the `Podfile`.
### Install Blockstack SDK and open the pod project
@ -339,26 +337,26 @@ lines after.
2. In terminal, make sure it is open to the root of your `hello-blockstack-ios` project.
3. Initialize the project with Cocoapods via the `pod install` command.
```bash
$ pod install
Analyzing dependencies
Downloading dependencies
Installing Blockstack (1.0.1)
Installing CryptoSwift (0.15.0)
Installing PromisesObjC (1.2.8)
Installing PromisesSwift (1.2.8)
Installing STRegex (2.1.0)
Generating Pods project
Integrating client project
[!] Please close any current XCode sessions and use `hello-blockstack-ios.xcworkspace` for this project from now on.
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 2 total pods installed.
[!] Automatically assigning platform `ios` with version `11.3` on target `hello-blockstack-ios` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
```
```bash
$ pod install
Analyzing dependencies
Downloading dependencies
Installing Blockstack (1.0.1)
Installing CryptoSwift (0.15.0)
Installing PromisesObjC (1.2.8)
Installing PromisesSwift (1.2.8)
Installing STRegex (2.1.0)
Generating Pods project
Integrating client project
[!] Please close any current XCode sessions and use `hello-blockstack-ios.xcworkspace` for this project from now on.
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 2 total pods installed.
[!] Automatically assigning platform `ios` with version `11.3` on target `hello-blockstack-ios` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
```
This command creates a number of files
This command creates a number of files
4. Review the files that the `pod` installation created:
@ -368,22 +366,23 @@ lines after.
Podfile.lock hello-blockstack-ios.xcodeproj
Pods hello-blockstack-ios.xcworkspace
```
5. Start XCode and choose **Open another project**.
6. Choose the `.xcworkspace` file created in your project folder.
![](images/open-xcworkspace.png)
![](images/open-xcworkspace.png)
When you open the workspace, the system will begin indexing the project. Then, after indexing, you **may** see a warning indicator at the top in the
project title. If you see the warning, continue to step 7. Otherwise, go to the next section.
When you open the workspace, the system will begin indexing the project. Then, after indexing, you **may** see a warning indicator at the top in the
project title. If you see the warning, continue to step 7. Otherwise, go to the next section.
7. Click the signal to reveal the warning.
8. Click **Next**.
![](images/indicator.png)
![](images/indicator.png)
9. Select all the targets and press **Next** and **Continue** when prompted.
Make sure you have no errors; warnings are acceptable to continue.
Make sure you have no errors; warnings are acceptable to continue.
### Choose a custom protocol handler
@ -391,20 +390,20 @@ You'll need to choose a custom protocol handler that is unique to your app. This
is so that your app's web-based authentication `redirect.html` endpoint can redirect
the user back to your iOS app. In this example, you use `myblockstackapp://`.
1. Open the `.xcworkspace` file in XCode if it isn't open already.
2. Select the top node of your project.
3. Select the **Info** tab in XCode.
4. Scroll to **URL Types** and press **+** (plus) sign.
5. Enter an **Identifier** and **URL Schemes** value.
1. Open the `.xcworkspace` file in XCode if it isn't open already.
2. Select the top node of your project.
3. Select the **Info** tab in XCode.
4. Scroll to **URL Types** and press **+** (plus) sign.
5. Enter an **Identifier** and **URL Schemes** value.
| **Identifier** | `MyBlockstackApp` |
| **URL Schemes** | `myblockstackapp` |
| **Identifier** | `MyBlockstackApp` |
| **URL Schemes** | `myblockstackapp` |
6. Set the **Role** to **Editor**.
6. Set the **Role** to **Editor**.
When you are done the **URL Types** appears as follows:
When you are done the **URL Types** appears as follows:
![](images/url-type.png)
![](images/url-type.png)
### Add a splash screen
@ -422,12 +421,12 @@ All iOS applications require a splash page.
5. Drag the downloaded file into the **3X** position in your new Images folder.
![](images/image-set-1.png)
![](images/image-set-1.png)
6. Select the `LaunchScreen.storyboard`.
7. Choose **Open As > Source Code**.
![](images/open-as.png)
![](images/open-as.png)
8. Replace the content of the `<scenes>` element with the following:
@ -471,18 +470,17 @@ All iOS applications require a splash page.
9. Immediately after scenes but before the close of the `</document>` tag add the following `<resources>`.
```xml
<resources>
>
<imagename="Image"width="64"height="64"/>
</resources>
</document>
>
>
```
10. Choose **Run > Run app** in the emulator.
The emulator now contains a new splash screen.
![](images/splash.png)
The emulator now contains a new splash screen.
![](images/splash.png)
### Update the Main.storyboard
@ -495,58 +493,59 @@ Rather than have you build up your own UI in the interface builder, this section
defines the graphical elements, and their functionality will be defined in
a respective `.swift` file.
3. Within the `<viewController>` element, replace the existing `<view>` sub-element with the following:
3. Within the `<viewController>` element, replace the existing `<view>` sub-element with the following:
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.
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 <ahref="https://forum.blockstack.org/t/blockstack-annual-hard-fork-2018/6518"target="\blank">the Blockstack forum</a>.
In future upgrades and hard forks, the blockchain will expand to introduce a new
scalable consensus algorithm to increase the number of transactions it can
process. This consensus algorithm is planned to be introduced in additional
process. This consensus algorithm is planned to be introduced in additional
hard forks in 2019.
Addtionally, a future Stacks blockchain will support truly decentralized mobile
applications by removing the need to trust a remote Stacks Node.
Instead, it will be possible for light clients to calculate the economic weight
of different Stacks blockchain forks, and identify the fork with the most
economic activity. Today, light clients rely on other trusted sources for fork
economic activity. Today, light clients rely on other trusted sources for fork
selection and cannot make that decision independently. For mobile apps this
enables functionality like looking up names without having to rely on a remote
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 <ahref="https://cryptoconsortium.github.io/CCSS/Details/#1.03"target="_blank">guidelines for key storage</a>. These guidelines are presented from least (Level I) to most secure (Level III). We recommend you store your keys with at least Level II security. This level states that you should:
* Back up each of your cryptographic keys.
* Store the backup in a location separate location from where you use a key. For example, if you use the key at the office, you can store the key are your office.
* Protect your backup from access by unauthorized parties. For example, a safe, safe deposit box, or lock box are good examples of protecting access to a backup.
* Employ some form of tamper mechanism that allows your to determine when if you key was accessed by someone else. For example, you could use a sealed paper envelopes with handwritten signatures over the seal as a tamper mechanism.
- Back up each of your cryptographic keys.
- Store the backup in a location separate location from where you use a key. For example, if you use the key at the office, you can store the key are your office.
- Protect your backup from access by unauthorized parties. For example, a safe, safe deposit box, or lock box are good examples of protecting access to a backup.
- Employ some form of tamper mechanism that allows your to determine when if you key was accessed by someone else. For example, you could use a sealed paper envelopes with handwritten signatures over the seal as a tamper mechanism.
You are responsible for recalling and protecting your keys. Blockstack does not store your seed phrase or **Secret Recovery Code**. If you lose your seed phrase, you lose the key to your STX tokens, which can be a very costly mistake. If you lose your **Secret Recovery Code**, you lose the key to your identity and cannot access your applications or the data you created with them.
Stacks is the name of a token developed by Blockstack Token LLC in 2017 and
@ -44,11 +43,11 @@ documentation.</div>
The genesis block launch makes possible the following interactions:
* Token holders can purchase names and namespaces with the Stacks token. Previously, names and namespaces required the purchaser to hold Bitcoin. Initially, this process relies on the Blockstack command-line interface (CLI).
- Token holders can purchase names and namespaces with the Stacks token. Previously, names and namespaces required the purchaser to hold Bitcoin. Initially, this process relies on the Blockstack command-line interface (CLI).
* Application developers can earn Stacks by building an application on the Blockstack ecosystem.
- Application developers can earn Stacks by building an application on the Blockstack ecosystem.
* Any Stacks tokens held at the time of launch or after remain usable under the Stacks Blockchain platform.
- Any Stacks tokens held at the time of launch or after remain usable under the Stacks Blockchain platform.
Finally, in addition to the development of Stacks token, this launch enables
The information on this page is intended for **current Stacks (STX) token holders** during Blockstack’s token sale through early 2018.
## Find your token balance and unlock date
{% include important.html content=" If you <strong>purchased Stacks tokens during Summer 2019</strong>, the form below will <strong>not</strong> work for your allocation. Please <ahref='https://explorer.blockstack.org/verifier'target='_blank'>check your allocation using this tool instead</a>. "%}
During your the initial grant process, you should have submitted a public *Stacks (STX) address* (also known as a *wallet address*) to Blockstack. A STX address is a string of letters and numbers starting with an `SP` or `SM`, for example: `SM3KJBA4RZ7Z20KD2HBXNSXVPCR1D3CRAV6Q05MKT`
During your the initial grant process, you should have submitted a public _Stacks (STX) address_ (also known as a _wallet address_) to Blockstack. A STX address is a string of letters and numbers starting with an `SP` or `SM`, for example: `SM3KJBA4RZ7Z20KD2HBXNSXVPCR1D3CRAV6Q05MKT`
If you purchased STX tokens through CoinList, you can find your address at
[CoinList](https://coinlist.co/distributions). If you submitted your Stacks
@ -21,10 +19,10 @@ Phrase** feature on the Stacks Wallet or contact us at <hello@stackstoken.com> f
help.
Use the following form to check your Stacks allocation:
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. <ahref="https://wallet.blockstack.org"target="\_blank">Go to the wallet download page</a> in your browser.
@ -38,16 +36,14 @@ by Blockstack PBC." %}
5. In the terminal window, type the following Command
```
shasum -a 512 Stacks-Wallet-macOS-3.0.0.dmg
```
```
shasum -a 512 Stacks-Wallet-macOS-3.0.0.dmg
```
![](images/mac-shasum.png)
![](images/mac-shasum.png)
6. Verify that the resulting hash (a string of letters and numbers) is the same as the latest hash published <ahref="https://github.com/blockstack/stacks-wallet/releases"target="\_blank">on this page</a>.
## Windows Installation
1. Select the **Windows Download** button <ahref="https://wallet.blockstack.org/"target="\_blank">on this page</a>.
@ -70,11 +66,11 @@ by Blockstack PBC." %}
4. In the command prompt window, type the following at the command prompt.
5. Verify that the resulting hash (a string of letters and numbers) is the same as the latest hash published <ahref="https://github.com/blockstack/stacks-wallet/releases"target="\_blank">on this page</a>.
@ -90,14 +86,11 @@ You need very small fractions of Bitcoin to fuel your Stacks Wallet transactions
If you have a paper wallet or a custodial wallet, you should set up a secondary hardware. You can then transfer small amounts to this hardware wallet for use with your Stacks Wallet. You can use any of these hardware wallets with the Stacks Wallet:
*<ahref="https://trezor.io/"target="\_blank">Trezor</a> One
*<ahref="https://www.ledger.com/"target="\_blank">Ledger</a> Nano S
* Ledger Blue
-<ahref="https://trezor.io/"target="\_blank">Trezor</a> One
-<ahref="https://www.ledger.com/"target="\_blank">Ledger</a> Nano S
- Ledger Blue
{% include note.html content="Blockstack only supports the hardware wallets listed above. Other wallets, for example, the Trezor Model T, <strong>are not supported</strong>. If you have questions about wallet support, please <ahref='emailto:support@blockstack.org'target='_blank'>contact Blockstack support</a>." %}
For information on setting up a hardware wallet, refer to the vendor's
documentation. We cannot help you set up your hardware wallet.
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.
<divclass="uk-card uk-card-default uk-card-body">
<h5>Security tip: What to share and what not to</h5>
This page describes how to use the Stacks Wallet software to manager your Stacks (STX) tokens. This page contains the following topics:
The Stacks Wallet software is installed on your computer, it is not a web application. You should have already [downloaded, verified, and installed the wallet software](wallet-install.html).
## Key concepts you should understand
You use Stacks Wallet software to manage STX tokens. Using the wallet you can:
You use Stacks Wallet software to manage STX tokens. Using the wallet you can:
* send STX from a specific STX address
* receive STX at a specific STX address
* view balances on an address
* review transaction history associated with an address
- send STX from a specific STX address
- receive STX at a specific STX address
- view balances on an address
- review transaction history associated with an address
To send STX, you need Bitcoin in your wallet. Bitcoin is the "gas" for transactions on the Stacks blockchain. A **_very small_** amount of Bitcoin is required to send STX. The gas price fluctuates like any market and is driven by the price of Bitcoin. Gas is not required to receive STX.
To send STX, you need Bitcoin in your wallet. Bitcoin is the "gas" for transactions on the Stacks blockchain. A **_very small_** amount of Bitcoin is required to send STX. The gas price fluctuates like any market and is driven by the price of Bitcoin. Gas is not required to receive STX.
You can use the Stacks Wallet software by itself or together with a hardware wallet. Using with a hardware wallet is recommended but not required.
@ -30,9 +30,9 @@ You can use the Stacks Wallet software by itself or together with a hardware wal
You can use any of these hardware wallets with the Stacks Wallet:
* Trezor One
* Ledger Nano S
* Ledger Blue
- Trezor One
- Ledger Nano S
- Ledger Blue
{% include note.html content="Blockstack only supports the hardware wallets listed above. Other wallets, for example, the Trezor Model T, <strong>are not supported</strong>. If you have questions about wallet support, please <ahref='emailto:support@blockstack.org'target='_blank'>contact Blockstack support</a>." %}
@ -40,7 +40,7 @@ The private key on your hardware wallet is used by the Stacks Wallet software to
### Software only wallet and a seed phrase
You can use the Stacks Wallet software without a hardware device to create one or more software wallets. Each wallet has its own address which corresponds to a STX address on the Stacks blockchain. You access this address with a unique, **seed phrase**. The software generates a seed phrase for you when create a software-only wallet. The seed phrase consists of 24 words in a sequence. Both the word _and its position the sequence_are important.
You can use the Stacks Wallet software without a hardware device to create one or more software wallets. Each wallet has its own address which corresponds to a STX address on the Stacks blockchain. You access this address with a unique, **seed phrase**. The software generates a seed phrase for you when create a software-only wallet. The seed phrase consists of 24 words in a sequence. Both the word _and its position the sequence_ are important.
Write down your seed phrase and store it in a secure location such as a safe deposit box. When you write the seed phrase down, include its position, for example,`1-frog, 2-horse, 3-building` and so on until you reach a final position `24-ocean`.
@ -56,7 +56,6 @@ If you used the original, v1, version of the wallet, you should instead begin us
The v2 version of the wallet required a hardware wallet to send and receive. You can connect this same hardware wallet to the v3 version of the Stacks Wallet software. If this is your situation, choose **Use existing wallet** when you first start the Stacks Wallet v3; you don't need to create a new wallet.
## Create a new or open an existing wallet
When you start the Stacks Wallet it prompts you to create a new or choose an existing wallet. You should create a new wallet if you have not previously connected a hardware device to the Stacks Wallet v3 software or if you do not have an existing 24 word seed phrase.
@ -92,7 +91,7 @@ When your hardware device is ready, do the following:
2. Double-click on the wallet software to open it.
3. Select **Create new wallet** or **Use existing wallet**.
If you connected your hardware device to an old version of the Stacks Wallet software, you choose **Create new wallet**. After you make this initial connection, the *next time* you start the wallet, you can choose **Use existing wallet**.
If you connected your hardware device to an old version of the Stacks Wallet software, you choose **Create new wallet**. After you make this initial connection, the _next time_ you start the wallet, you can choose **Use existing wallet**.
The system asks if you have a hardware wallet.
@ -119,7 +118,6 @@ When your hardware device is ready, do the following:
The Stacks Wallet shows the current wallet balance.
### Software only wallet
If you have an existing 24 word seed phrase from this or a previous version of the Stacks Wallet software, you don't need to create a new wallet, you can **Use existing wallet**. This procedure assumes you are creating a wallet for the first time.
@ -135,14 +133,14 @@ If you have an existing 24 word seed phrase from this or a previous version of t
4. Choose **Continue without a hardware wallet**.
The system generates a seed phrase for you and prompts you to write it down.
Don't lose your seed phrase. If you lose your seed phrase, you lose your STX tokens and can never get them back.
The system generates a seed phrase for you and prompts you to write it down.
Don't lose your seed phrase. If you lose your seed phrase, you lose your STX tokens and can never get them back.
5. Write down each word and its position, for example,`1 - frog`.
5. Write down each word and its position, for example,`1 - frog`.
6. Store your written seed phrase in a secure location such as a safe deposit box.
7. Click **I've written down my seed phrase**.
The system prompts you to re-enter your seed phrase. The sequence numbers are out of order. For example, `5` may appear in the `1` position. Enter the corresponding `5` and `1` word as appropriate.
The system prompts you to re-enter your seed phrase. The sequence numbers are out of order. For example, `5` may appear in the `1` position. Enter the corresponding `5` and `1` word as appropriate.
8. Select **Done**.
@ -168,7 +166,6 @@ Stacks you have unlocked. The **Allocation** is the amount still locked up.
![](images/token-holder-balance.png)
## Receive Stacks
To receive Stacks: you give a STX address directly to a user via email or text, for
@ -180,7 +177,7 @@ example.
2. Email or text the address to the person or organization sending to you.
A Stacks address is a public addresses. Anyone with the address, can view the address balance or send money _**to**_ the address.
A Stacks address is a public addresses. Anyone with the address, can view the address balance or send money _**to**_ the address.
3. Look for the receipt transaction in your transaction history.
@ -190,8 +187,6 @@ example.
Blockchain transactions take time. It may be minutes or hours before the transaction is recorded in the blockchain. When the transaction is complete, you can see a receipt for the transaction in your Stacks Wallet. The **PENDING** marker goes away once the funds are recorded on the blockchain.
## Add Bitcoin gas
The Stacks Wallet uses very small amounts of Bitcoin to pay fees for sending transactions. You need very small fractions of Bitcoin (BTC) for gas. The cost of gas you need fluctuates with the market price of Bitcoin.
@ -206,16 +201,16 @@ If you attempt to send STX with your wallet and you do not have enough Bitcoin t
![](images/not-enough.png)
To increase your Bitcoin for transactions, do the following:
To increase your Bitcoin for transactions, do the following:
1. Click the <spanclass="uk-margin-small-center"uk-icon="cog"></span>
(settings icon) in the upper right corner of the wallet.
1. Click the <spanclass="uk-margin-small-center"uk-icon="cog"></span>
(settings icon) in the upper right corner of the wallet.
The system opens the **Settings** dialog.
The system opens the **Settings** dialog.
![](images/settings.png)
![](images/settings.png)
This dialog shows you how much BTC you currently have in your account.
This dialog shows you how much BTC you currently have in your account.
2. Select **Add BTC**.
@ -253,12 +248,12 @@ Sending stacks is a transaction you must authorize or sign. If you have connecte
5. Select **Continue**.
If you do not have enough Bitcoin to fuel the transaction, the system
notifies you. If you don't have enough Bitcoin, you must **Top Up**.
Otherwise, the system prompts you to connect to your hardware wallet. Your
hardware wallet will prompt you for additional information and actions.
If you do not have enough Bitcoin to fuel the transaction, the system
notifies you. If you don't have enough Bitcoin, you must **Top Up**.
Otherwise, the system prompts you to connect to your hardware wallet. Your
hardware wallet will prompt you for additional information and actions.
![](images/device-check.png)
![](images/device-check.png)
6. Select **Continue**.
@ -278,25 +273,22 @@ Sending stacks is a transaction you must authorize or sign. If you have connecte
Select **Refresh** if you don't immediately see the transaction in your
history.
## Reset the wallet
Resetting a wallet clears all your data from the Stacks Wallet and returns the
wallet to its original state.
* If you entered a Stacks address, resetting clears the address from the Stacks Wallet.
* If you connected to a hardware wallet, resetting removes the connection to the hardware wallet.
- If you entered a Stacks address, resetting clears the address from the Stacks Wallet.
- If you connected to a hardware wallet, resetting removes the connection to the hardware wallet.
Resetting the wallet does nothing to your addresses or their associated balances.
They are maintained.
Once you reset the wallet, you have to start over from the *Terms of Use*. If
Once you reset the wallet, you have to start over from the _Terms of Use_. If
you do not restart the wallet, you can simple close it.
1. Click the <spanclass="uk-margin-small-center"uk-icon="cog"></span>
(settings icon) in the upper right corner of the wallet.
(settings icon) in the upper right corner of the wallet.
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.
<divclass="uk-card uk-card-default uk-card-body">
@ -20,7 +20,7 @@ This teaches you how to run a Gaia hub on Amazon EC2. Amazon EC2 is an affordabl
This procedure uses Amazon AWS to choose and configure an Amazon Machine Image
(AMI) running a Gaia service. For this reason, you should have an AWS account
on the <ahref="https://aws.amazon.com/free/"target="\_blank">Amazon AWS free
tier</a>, personal account, or corporate account. These instructions assume you
tier</a>, personal account, or corporate account. These instructions assume you
are using a free tier account.
These instructions assume you have already created a free <a
@ -46,7 +46,7 @@ If `watch` is not located, install it on your workstation.
![](/storage/images/us-west-2.png)
3. Under **Build a solution** choose **Launch a virtual machine**.
3. Under **Build a solution** choose **Launch a virtual machine**.
The system opens the EC2 dashboard.
@ -71,127 +71,128 @@ If `watch` is not located, install it on your workstation.
So, the `blockstack-gaia_hub-ephemeral-2.5.3-hvm - ami-0c8fc48c10a42737e` image uses ephemeral storage, is at version `2.5.3` and has the `0c8fc48c10a42737e` tag.
6. Select the most recent version image with the storage you want. The images are not sorted; The most recent images is not necessarily at the top of the list.
6. Select the most recent version image with the storage you want. The images are not sorted; The most recent images is not necessarily at the top of the list.
After you select an image, the system displays **Step 2: Choose an Instance Type** page.
![](/storage/images/tier-2-image.png)
7. Select **t2.micro** and choose **Next: Configure Instance Details**.
To configure instance details, do the following:
<divclass="uk-card uk-card-body">
<ol>
<li>
<p>Select a VPC.</p>
<p>A default VPC is created with a free tier account. You can use this
default VPC. Or you can choose another VPC. If you choose another VPC,
ensure the <codeclass="highlighter-rouge">Subnet</code> value is set to a subnet reachable by a public IP.
</p>
<divclass="uk-alert-warning uk-alert"uk-alert=""><b>Important:</b> If you're using a private subnet, you
should attach an elastic IP (EIP) to the VM. This EIP allows you to
reboot the instance without worrying whether the address will reset. To
attach an IP, <strong>press allocate new address</strong> and follow the
instructions to <ahref="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-eips-associating"target="_blank">attach the EIP</a> to your new EC2 instance.
</div>
</li>
<li>
<p>Set <strong>Protect against accidental termination</strong>.</p>
<p>If you terminate a Gaia instance, you lose all the data associated with it. Protection adds an extra step to terminating your Gaia instance.</p>
</li>
<li>
<p>Open the <strong>Advanced Details</strong>.</p>
<p>At this point, you are going to configure environment variables for your instance.</p>
</li>
<li>
<p>Paste the following into the <strong>Advanced Details</strong>.</p>
<td>A phrase to pass when using the hub admin. For example, <code>hubba</code> is a fun key phrase.</td>
</tr>
<tr>
<td><code><NAME_OF_DOMAIN></code></td>
<td>Your hub's domain name. For example, <code>maryhub.ml</code> is the domain name in this example.</td>
</tr>
<tr>
<td><code><STAGING_VALUE></code></td>
<td>
<p>Indicates what type of SSL to create, testing (`1`) or production (`0`). Set testing if you want to test without worrying about rate limiting. A testing cerificate is not secure.</p>
<p>For this tutorial, use production (`0`).</p>
</td>
</tr>
</tbody>
</table>
</li>
<li>
<p>Check your <strong>Advanced Details</strong> they should look similar to the following:</p>
7. Select **t2.micro** and choose **Next: Configure Instance Details**.
To configure instance details, do the following:
<divclass="uk-card uk-card-body">
<ol>
<li>
<p>Select a VPC.</p>
<p>A default VPC is created with a free tier account. You can use this
default VPC. Or you can choose another VPC. If you choose another VPC,
ensure the <codeclass="highlighter-rouge">Subnet</code> value is set to a subnet reachable by a public IP.
</p>
<divclass="uk-alert-warning uk-alert"uk-alert=""><b>Important:</b> If you're using a private subnet, you
should attach an elastic IP (EIP) to the VM. This EIP allows you to
reboot the instance without worrying whether the address will reset. To
attach an IP, <strong>press allocate new address</strong> and follow the
instructions to <ahref="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-eips-associating"target="_blank">attach the EIP</a> to your new EC2 instance.
</div>
</li>
<li>
<p>Set <strong>Protect against accidental termination</strong>.</p>
<p>If you terminate a Gaia instance, you lose all the data associated with it. Protection adds an extra step to terminating your Gaia instance.</p>
</li>
<li>
<p>Open the <strong>Advanced Details</strong>.</p>
<p>At this point, you are going to configure environment variables for your instance.</p>
</li>
<li>
<p>Paste the following into the <strong>Advanced Details</strong>.</p>
<td>A phrase to pass when using the hub admin. For example, <code>hubba</code> is a fun key phrase.</td>
</tr>
<tr>
<td><code><NAME_OF_DOMAIN></code></td>
<td>Your hub's domain name. For example, <code>maryhub.ml</code> is the domain name in this example.</td>
</tr>
<tr>
<td><code><STAGING_VALUE></code></td>
<td>
<p>Indicates what type of SSL to create, testing (`1`) or production (`0`). Set testing if you want to test without worrying about rate limiting. A testing cerificate is not secure.</p>
<p>For this tutorial, use production (`0`).</p>
</td>
</tr>
</tbody>
</table>
</li>
<li>
<p>Check your <strong>Advanced Details</strong> they should look similar to the following:</p>
@ -224,16 +225,16 @@ If `watch` is not located, install it on your workstation.
</tr>
</table>
13. Choose **Review and Launch**.
13) Choose **Review and Launch**.
The system may warn you that the selection is not free tier eligible. You can ignore this for now.
14. Press **Launch**.
14) Press **Launch**.
The system prompts you for a key pair.
15. Select **Create a new keypair** or **Choose an existing key pair**.
16. Select **Launch Instances**.
15) Select **Create a new keypair** or **Choose an existing key pair**.
16) Select **Launch Instances**.
The system launches your instance.
@ -243,7 +244,6 @@ During the launch process the machine starts and runs some initial setup process
![](/storage/images/instance-initialize.png)
## Task 2: Connect your Gaia server to your domain
Now, you are ready to test your Gaia server. This procedure ensures the Gaia services started correctly and they are configured to the domain name you provided in **Advanced Details** above.
@ -277,33 +277,32 @@ Now, you are ready to test your Gaia server. This procedure ensures the Gaia ser
<li>Check that your domain's DNS configuration matches the public IP address of your instance.</li>
<li>Update the DNS site's configuration.</li>
<li>Restart your EC2 instance as per the <ahref="#restart-services-and-reload-certificates">Restart and reload certificates</a> procedure on this page.</li>
<li>Continue with next step, step 8.</li>
</ol>
</td>
</tr>
</table>
8. Press **Advanced**.
9. Choose to proceed.
10. Extend the IP with the `PUBLIC_IP/hub_info` tag like so.
<li>Check that your domain's DNS configuration matches the public IP address of your instance.</li>
<li>Update the DNS site's configuration.</li>
<li>Restart your EC2 instance as per the <ahref="#restart-services-and-reload-certificates">Restart and reload certificates</a> procedure on this page.</li>
<li>Continue with next step, step 8.</li>
</ol>
</td>
</tr>
</table>
8) Press **Advanced**.
9) Choose to proceed.
10) Extend the IP with the `PUBLIC_IP/hub_info` tag like so.
You should see a response from your Gaia hub!
@ -314,7 +313,6 @@ Now, you are ready to test your Gaia server. This procedure ensures the Gaia ser
not required simple to run the hub services, Blockstack will only connect to
a hub and write to its storage over a valid `HTTPS` connection.
## Task 3: Configure a domain name
At this point, you can point a domain to your Gaia hub. Although it's not required, it is highly recommended. If you use a domain, you can migrate your instance to a different server (or even provider such as Azure or Dropbox) at any time, and still access it through the domain URL. Just point your domain at the IP address for your EC2 instance. Use an `A Record` DNS type.
@ -343,9 +341,9 @@ These instructions assume you have already created a free <a href="https://www.f
![Domain test](/storage/images/domain-test.png)
If you receive another **Your connection is not private** dialogs, take the option to proceed to your domain. The *Not secure* message should no longer appear in the browser bar. If the message does appear, try waiting a few minutes for your recent changes to propagate across the net domain servers. Then, refresh the page.
If you receive another **Your connection is not private** dialogs, take the option to proceed to your domain. The _Not secure_ message should no longer appear in the browser bar. If the message does appear, try waiting a few minutes for your recent changes to propagate across the net domain servers. Then, refresh the page.
9. Check the SSL certificate for your hub.
8. Check the SSL certificate for your hub.
Each browser has its own check procedure, for example, Chrome:
@ -354,7 +352,6 @@ These instructions assume you have already created a free <a href="https://www.f
At this point, you have the following. An EC2 instance running Gaia and a DNS
record pointing your domain to this instance.
## AWS hub tips and tricks
Once your Gaia storage hub is up and running on AWS, you may occassionally need to troubleshoot. This section contains some useful information for interacting with your EC2 instance.
@ -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
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.
"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)",
"description": "Required if `driver` is `google-cloud`",
"properties": {
"credentials": {
"additionalProperties": false,
"properties": {
"client_email": {
"type": "string"
},
"type": "object"
},
"readURL": {
"type": "string"
"private_key": {
"type": "string"
}
},
"type": "object"
},
"requireCorrectHubUrl": {
"default": false,
"type": "boolean"
"email": {
"type": "string"
},
"serverName": {
"default": "gaia-0",
"description": "Domain name used for auth/signing challenges. \nIf `requireCorrectHubUrl` is true then this must match the hub url in an auth payload.",
"type": "string"
"keyFilename": {
"type": "string"
},
"validHubUrls": {
"description": "If `requireCorrectHubUrl` is true then the hub specified in an auth payload can also be\ncontained within in array.",
"items": {
"type": "string"
},
"type": "array"
},
"whitelist": {
"description": "List of ID addresses allowed to use this hub. Specifying this makes the hub private \nand only accessible to the specified addresses. Leaving this unspecified makes the hub \npublicly usable by any ID.",
"items": {
"type": "string"
},
"type": "array"
"projectId": {
"type": "string"
}
},
"type": "object"
},
"required": [
"driver",
"port"
],
"type": "object"
"maxFileUploadSize": {
"default": 20,
"description": "The maximum allowed POST body size in megabytes. \nThe content-size header is checked, and the POST body stream \nis monitoring while streaming from the client. \n[Recommended] Minimum 100KB (or approximately 0.1MB)",
"minimum": 0.1,
"type": "number"
},
"pageSize": {
"default": 100,
"maximum": 4096,
"minimum": 1,
"type": "integer"
},
"port": {
"default": 3000,
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"proofsConfig": {
"additionalProperties": false,
"properties": {
"proofsRequired": {
"default": 0,
"type": "integer"
}
},
"type": "object"
},
"readURL": {
"type": "string"
},
"requireCorrectHubUrl": {
"default": false,
"type": "boolean"
},
"serverName": {
"default": "gaia-0",
"description": "Domain name used for auth/signing challenges. \nIf `requireCorrectHubUrl` is true then this must match the hub url in an auth payload.",
"type": "string"
},
"validHubUrls": {
"description": "If `requireCorrectHubUrl` is true then the hub specified in an auth payload can also be\ncontained within in array.",
"items": {
"type": "string"
},
"type": "array"
},
"whitelist": {
"description": "List of ID addresses allowed to use this hub. Specifying this makes the hub private \nand only accessible to the specified addresses. Leaving this unspecified makes the hub \npublicly usable by any ID.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": ["driver", "port"],
"type": "object"
}
```
The following is an simple example of a Gaia hub configuration:
@ -218,4 +202,4 @@ The following is an simple example of a Gaia hub configuration:
}
```
A full list of example can be found in [the Gaia repository on GitHub](https://github.com/blockstack/gaia/tree/master/hub).
A full list of example can be found in [the Gaia repository on GitHub](https://github.com/blockstack/gaia/tree/master/hub).
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 <ahref="https://digitalocean.com"target="\_blank">DigitalOcean</a>. DigitalOcean requires you to supply a credit card to create an account. You are only charged for the services you use the Gaia hub as of this writing should cost $10 USD a month.
You must create an account on <ahref="https://digitalocean.com"target="\_blank">DigitalOcean</a>. DigitalOcean requires you to supply a credit card to create an account. You are only charged for the services you use the Gaia hub as of this writing should cost \$10 USD a month.
The easiest way to interact with your droplet is the DigitalOcean Console. Users who are comfortable using the secure shell (SSH) and private keys may prefer to open a local terminal on their home machine instead. To enable this, you should ensure you have the following prerequisites completed.
* Locate an existing SSH key pair on your Mac or <ahref="https://help.dreamhost.com/hc/en-us/articles/115001736671-Creating-a-new-Key-pair-in-Mac-OS-X-or-Linux"target="\_blank">create a new SSH key pair</a>. Your key should have a passphrase, do not use a key pair without one.
- Locate an existing SSH key pair on your Mac or <ahref="https://help.dreamhost.com/hc/en-us/articles/115001736671-Creating-a-new-Key-pair-in-Mac-OS-X-or-Linux"target="\_blank">create a new SSH key pair</a>. Your key should have a passphrase, do not use a key pair without one.
* Add the <ahref="https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/to-account/"target="\_blank">SSH from your local machine to DigitalOcean</a>.
- Add the <ahref="https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/to-account/"target="\_blank">SSH from your local machine to DigitalOcean</a>.
* Create a <ahref="https://www.digitalocean.com/docs/api/create-personal-access-token/"target="\_blank">personal access token in DigitalOcean</a>.
- Create a <ahref="https://www.digitalocean.com/docs/api/create-personal-access-token/"target="\_blank">personal access token in DigitalOcean</a>.
* Install `doctl` which is the DigitalOcean command line tool. For information on installing these, see which is the DigitalOcean command line utility. Check out their [installation instructions](https://github.com/digitalocean/doctl/blob/master/README.md#installing-doctl) to see how to install it on your computer.
- Install `doctl` which is the DigitalOcean command line tool. For information on installing these, see which is the DigitalOcean command line utility. Check out their [installation instructions](https://github.com/digitalocean/doctl/blob/master/README.md#installing-doctl) to see how to install it on your computer.
## Task 1: Create a DigitalOcean space
@ -64,13 +64,12 @@ In this task you create a **Space** which is where Gaia stores your files.
## Task 2: Enable File Listing and Set a Bucket Policy
On Digital Ocean, set **Enable File Listing**:
1. Navigate to the **Spaces** tab.
2. Select your newly created space and click **Settings**
3. Set **Enable File Listing** for your space.
3. Set **Enable File Listing** for your space.
4. Press **Save**.
On your local workstation, create a bucket policy to grant read permission on your space.
@ -79,28 +78,29 @@ On your local workstation, create a bucket policy to grant read permission on yo
2. <ahref="https://www.digitalocean.com/docs/spaces/resources/s3cmd/"target="_blank">Install and configure the <strong>s3cmd</strong></a>.
3. In the current directory, use the `touch` command to create a file called `gaiahub-policy`.
```
touch gaiahub-policy
```
```
touch gaiahub-policy
```
4. Use your favorite editor to open the file.
5. Add the following policy to the file.
```json
{
"Version":"2012-10-17",
"Id": "read policy",
"Statement":[
{
"Sid":"PublicRead",
"Effect":"Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<SPACE_NAME>/*"
}
]
}
```
```json
{
"Version": "2012-10-17",
"Id": "read policy",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<SPACE_NAME>/*"
}
]
}
```
6. Edit the `Resource` line and replace the `<SPACE_NAME>` with your space name from Digital Ocean.
For example, if your space is named `meepers`, after editing the line you would have:
@ -120,7 +120,7 @@ On your local workstation, create a bucket policy to grant read permission on yo
Be sure to `SPACE_NAME` with the name of your space, for example:
```
```
s3cmd setpolicy gaiahub-policy s3://meepers
```
@ -128,23 +128,23 @@ On your local workstation, create a bucket policy to grant read permission on yo
1. On your local workstation, create a file called `gaiahub-cors.xml` that looks like this:
@ -165,9 +165,9 @@ In this task, you add a droplet to your account. The droplet is a droplet is a c
5. Select the **Docker** app from the options presented.
6. Scroll down to the **Choose a size** section and use the left arrow to display and select the **$5/mo** image.
6. Scroll down to the **Choose a size** section and use the left arrow to display and select the **\$5/mo** image.
This size gives you plenty of memory and disk space to run a personal hub.
This size gives you plenty of memory and disk space to run a personal hub.
7. Scroll down to the **Choose a datacenter region** section.
@ -181,11 +181,10 @@ In this task, you add a droplet to your account. The droplet is a droplet is a c
10. **Choose a hostname** for your droplet such as `moxie-gaiahub`.
11. Review your choices then click **Create** to start your droplet running.
11. Review your choices then click **Create** to start your droplet running.
At this point, your new droplet should appear in the list of resources on your DigitalOcean dashboard.
## Task 5: Open a console on your Droplet
A droplet console emulates the access you would have if you were sitting down with a keyboard and monitor attached to the actual server. In this section, you open a console on your droplet.
@ -203,7 +202,7 @@ A droplet console emulates the access you would have if you were sitting down wi
3. Choose **Access** from the control panel.
4. Select **Reset Root Password** to have DigitalOcean send you the root password.
DigitalOcean sends a temporary password to the email attached to your account. It takes a couple of minutes to reset the root password on your droplet.
DigitalOcean sends a temporary password to the email attached to your account. It takes a couple of minutes to reset the root password on your droplet.
5. Open your email and copy the password.
6. Switch back to the droplet control panel and choose **Launch Console**.
@ -225,7 +224,7 @@ A droplet console emulates the access you would have if you were sitting down wi
10. Provide and confirm a new password.
The system logins you in and gives you a welcome message. At the conclusion of the message, you are at the console prompt.
The system logins you in and gives you a welcome message. At the conclusion of the message, you are at the console prompt.
```
Welcome to DigitalOcean's One-Click Docker Droplet.
@ -246,7 +245,6 @@ A droplet console emulates the access you would have if you were sitting down wi
<p>If you find the output from ls difficult to read, try enter the following to change the console colors from the command line: <code>LS_COLORS="di=1;31"</code> You can also edit your console <code>.bashrc</code>. file permanently, of course.</p>
</div>
## Task 6: Create a space key
1. In the DigitalOcean dashboard, go to the **API** page.
@ -261,13 +259,13 @@ A droplet console emulates the access you would have if you were sitting down wi
5. Press the check mark.
The system creates your key and displays both the key and its secret.
The system creates your key and displays both the key and its secret.
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.
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.
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.
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
A Gaia service can run a simple administrative service co-located with your Gaia hub. This service allows you to administer the Gaia hub with the help of an API key. Gaia hubs installed using the Gaia Amazon Machine Image (AMI) have this service integrated automatically.
In this section, you learn how to use the Gaia admin service with your Gaia hub.
@ -12,20 +12,18 @@ In this section, you learn how to use the Gaia admin service with your Gaia hub.
The examples in this section assume that Gaia and the admin service
were installed through the Configure a hub on Amazon EC2." %}
## Understand the configuration files
The admin service relies on two configuration files, the hub's configuration and the configuration of the admin service itself. The hub's configuration is mounted `/tmp/hub-config/config.json` in the `docker_admin_1` container. Your EC2 instance has the admin service configuration in the `/gaia/docker/admin-config/config.json` file.
The admin service needs to know the following:
* where the Gaia hub config file is located
* which API key(s) to use when authenticating administrative requests
* which command(s) to run to restart the Gaia hub on a config change
- where the Gaia hub config file is located
- which API key(s) to use when authenticating administrative requests
- which command(s) to run to restart the Gaia hub on a config change
The following is the standard admin service config installed with your EC2 instance.
```json
{
"argsTransport": {
@ -37,16 +35,13 @@ The following is the standard admin service config installed with your EC2 insta
"json": true
},
"port": 8009,
"apiKeys": ["hello"],
"apiKeys": ["hello"],
"gaiaSettings": {
"configPath": "/tmp/hub-config/config.json"
},
"reloadSettings": {
"command": "/bin/sh",
"argv": [
"-c",
"docker restart docker_hub_1 &"
],
"argv": ["-c", "docker restart docker_hub_1 &"],
"env": {},
"setuid": 1000,
"setgid": 1000
@ -54,8 +49,7 @@ The following is the standard admin service config installed with your EC2 insta
}
```
The `port` is the port where Gaia is running. The `apiKeys` field is key used for making calls to the hub. The `gaiaSettings`
The `port` is the port where Gaia is running. The `apiKeys` field is key used for making calls to the hub. The `gaiaSettings`
The `argsTransport` section configures the hub logging. The service uses the `winston` logging service. Refer to their documentation for full details on the [logging configuration options](https://github.com/winstonjs/winston).
@ -128,7 +122,6 @@ The `reloadSettings` configure the command that is used to reload your Gaia hub.
</tbody>
</table>
## Using the admin service APIs
You use the admin service APIs to manage the hub. Administrating a hub requires
@ -148,11 +141,10 @@ export API_KEY="hello"
You may find it useful to install a JSON processor such as `jq` to process the
output of the admin commands.
### Restart the Gaia Hub (`POST /v1/admin/reload`)
The admin service will make changes to the Gaia hub's config file, but the
changes will only take effect when the Gaia hub is reloaded. You can do this
changes will only take effect when the Gaia hub is reloaded. You can do this
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:
@ -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:
<dlclass="uk-description-list">
<dtclass="uk-text-lowercase">
@ -150,41 +149,40 @@ To replace the default login, do the following:
3. Replace `redirectToSignIn()` method with the `blockstack.UserSession.redirectToSignInWithAuthRequest(authRequest)` method.
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.
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.
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:
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.