This post was inspired by @jackzampolin’s post on Component Architecture and my discussions with members of the Blockstack engineering team and community:
–
A recurring theme in Blockstack is confusion over where to store state and where code should live in our decentralized system.
Since the system is decentralized, we want to store the state and run code in locations under user control or that the user can trust. For the most part, this is at the edges of the system, as close to the user as possible.
First, let’s take a look at the state as it currently (v0.15) exists in Blockstack. Then, we’ll take a brief look at some of the functionality provided by each of our main products. Finally, we’ll look at some proposals.
Current locations of state
Blockstack Browser
- Wallet seed
- Preordered, current name registrations
- Next unused address index
- Selected storage providers
- Storage provider access tokens
- URLs of providers such as UTXO provider, search provider, etc
Blockstack Core/CLI
- Wallet information
- Selected storage providers
- Storage provider access tokens
- URLs of providers such as UTXO provider, search provider, and other data in the directory containing
client.ini
Profile/token/key file
- Profile
- App public keys
- Device public keys
localStorage of apps using Blockstack.js
- Gaia storage session tokens
Current locations of code
Below is a list of some functionality provided by both Blockstack Core and Blockstack Browser. This partial list is not exhaustive, but simply to demonstrate the degree of overlap in functionality between our two main deliverables.
Blockstack Core/CLI (Python)
- Transaction interpretation & indexing
- Transaction generation
- Zone file creation
- Zone file storage
- Zone file retrieval
- Bitcoin wallet
- Identity wallet
- Profile retrieval & verification
- Profile generation
- Social proof verification
- Storage provider interface
- Gaia storage
Blockstack Browser (JavaScript)
- Zone file creation
- Bitcoin wallet
- Identity wallet
- Profile retrieval & verification
- Profile generation
- Storage provider interface
- Social proof verification
Challenges from current architecture
As you can see, our system has a state stored in various locations in the system. There’s also a large amount of overlap in functionality between our two main deliverables.
This results in a number of challenges for users trying to understand how the system works. It also makes it difficult for developers trying to build apps in our ecosystem and developers working on the core project.
The following are a list of some of the problems
Confusion from different state in CLI & Browser
Users are trained by centralized systems to expect to see the same view of state no matter which client they’re using to view a service. Users using both the CLI and the Browser see completely different views of the system. A name registered with one does not appear in the wallet of the other and vice versa.
Users are confused by multiple wallets.
It isn’t clear to them which wallet has their bitcoins and which one has their names and how to use one wallet in multiple browsers or devices.
Users can’t use a name bought on their computer on all browsers and in all apps
Users don’t understand why a name bought on their computer can’t be used in all browsers. Why does it appear in only one browser and not in the command line? (or vice versa)
Backing up state is complicated
Some state in ~/.blockstack
or ~/Library/Application Support/Blockstack/
while other is in a browser’s localStorage
. Many people, especially in our early adopter target market, always use incognito mode. The implications of using the browser in the fashion are not clear.
Configuration and users preferences are in multiple places.
We have information about user configuration and preferences stored in:
- Blockstack Core’s configuration directory
- Blockstack Browser’s localStorage
- User’s Gaia storage device
- User’s key delegation file
State is stored in apps’ localStorage
without their knowledge
Our JavaScript libraries storage state in app’s localStorage
without their permission. This leaky abstraction makes it difficult to understand the behavior of our libraries as behavior changes based on cached state that the app developer is not aware of.
Proposal
State
- A user should be able to completely restore their account with their 12 word identity key phrase and no other information. This phrase should be the only state stored by our client apps.
- Apps are responsible for for managing their own state. Our libraries should not create state without app developers’ permission.
Possible implementation steps
- Storage provider information and access tokens are stored encrypted in the key file.
- Information about user’s preferred UTXO provider, search provider, etc, also stored in the key file.
- Information about registration state of a name can be generating either from possible Blockstack transactions in the mempool or state stored by clients in the key file.
Code
- All code that can run on the client should run on the client.
- Business logic code should be written once and not duplicated.
- The majority of functionality provided by the current REST API should be moved to blockstack.js.
- The client should generate its own Blockstack transactions and send them to endpoints for broadcast.
- The browser and CLI should be simply different “dumb” interfaces to system state that is retrieved and rendered by blockstack.js.
Blockstackd
This is what someone who wants to run a full node would run. It includes the indexer and Atlas components of the network.
- No write operations except for publishing zone file to Atlas network.
- Read operations limited to:
- Querying namespace information
- Query name information: highest level return value should be zone file, anything high-level than zone file is out of scope
- Querying information about the virtual blockchain.
- Written in python
Blockstack Gaia Storage
Each user has one or more Gaia storage nodes.
blockstack.js
- All name and namespace-related write transactions are generated and sent from the library. Transactions that need to be sent out at certain times, such as name pregister and register
- Includes a registrar that monitors the blockchain, queues transactions and sends transactions at the right time. This registrar can be run locally or remotely.
- Includes higher level profile resolver code, identity and authentication related tools
- Usable in browser, node.js or wrapped with language specific bindings
Proposed Action Items
- Today: Institute a moratorium on adding additional functionality to Blockstack Core (specifically REST API)
- Today: Deprecate current Blockstack CLI. No longer encourage users to install it.
- Today: Going forward, put new functionality in blockstack.js
- Future: Start migrating existing Blockstack Core REST API functionality to blockstack.js
-
Future:Extract
blockstackd
functionality from Blockstack Core into separate repository - Future: Extract Gaia storage functionality from Blockstack Core into separate repository
- Future: Come up with a plan for moving existing state off of the client (see above for some possible approaches)