Blockstack Core API Feedback

Below is a collection of thoughts and feedback from working with the Blockstack API while building the Portal and macOS app.

It is divided into sections that aren’t in any particular order.

Overview

Overall, I think the API is pretty straightforward and intuitive to work with. Kudos to @jude @muneeb and the team for all of their great work up to this point.

Errors

Use error codes/types

Return a human & computer readable error code for each request.

For example instead of:

{
	"error": "Failed to transfer balance: Invalid amount"
}

We could have something like this:

{
	errors: [{
	"code": "invalid_amount",
	"param": "amount",
	"message": "Failed to transfer balance because of invalid amount."
	},
	{
	"code": "invalid_address",
	"param": "address",
	"message": "Provided value is not in a known Bitcoin address format."
	}]
}

"code": (required) is a string constant. Clients of the the API can use this code to determine how they want to handle the error. Often this will be used to look up an error message in the user’s language to display to the user.

"param": (optional) is the name of the parameter that has a problem. This can be used by clients of the API to display error messages next to the appropriate user input field.

"message": (required) is a human readable error message. This is intended to provide clients of the API with additional information as to why their request failed.

The intention would be that this message: field provides helpful information in explaining the problem for developers. It can be displayed to end users in apps that are MVPs and/or okay with English-only error messages targeted at technical users.

For example, in a app targeted towards users familiar with the Bitcoin protocol it might be fine to display the message:

"Cannot withdraw dust." 

For a general consumer app targeted towards a global audience the developer might want to display that message in way more friendly for laymen or localized to a particular language such as:

en_US -> "There's not enough money in your wallet"
zh_CN -> "你钱包的余额不足"

It’s preferable to return all of the errors that the API knows about at once so that the app can prompt the user to fix all of their input problems at once.

HTTP Status Codes

Consistently use HTTP error codes. The API should return 40x error codes when there’s something wrong with information provided by the user. It should return 50x errors only when there’s an unexpected problem with Core. If a user encounters a 50x error, their Core API node is either configured incorrectly or there’s a bug in Core.

For example, the API shouldn’t return 50x errors if there’s not enough money in wallet. This isn’t a problem with Core, it’s a problem with the user’s request.

Example: Stripe’s error codes

Versioning

The Blockstack Core API currently uses a “coarse” versioning system where version 1 is placed in the sub-directory /v1. The thinking is that once the API is stable, we will commit to supporting /v1/.

One of the biggest frustrations as the user of an API is refactoring your code for changes to the API. Along the same lines, one of the biggest frustrations for the developer of the API is being unable to change it for fear of breaking backward compatibility.

We are building in a completely new space. It is pretty safe to say that the first version of our API won’t be the most ideal. As our project grows and the ecosystem grows, we’ll see many ways for the API to improve. It would be sad to be unable to improve the API because we’re worried that our vast decentralized ecosystem of apps can’t easily be updated.

Another approach would be to consider using a more finely grained versioning system uses for our API. Allow apps to request the version of the API for which they were designed. We could use compatibility layers to translate the request from the version of the API the app specifies to the latest API code. We could then transform the latest version of the API response back to the response format of the version of the API the user requested. This would allow us to continually improve the API without breaking backward compatibility for existing apps. There’s a great write up on how Stripe does something similar that is well worth reading.

Authentication

Core API currently expects the API password to be passed in requests with the basic type as follows: Authorization: basic <api-password>

http basic authentication is a specific type of authentication that requires a base64-encoded username and password combination .

APIs typically use the bearer type in the Authorization header to pass a single token secret. An API password (or key or oauth2 token) is passed on each request as follows: Authorization: bearer <token> . See Github’s API authentication section for some examples.

Execution

We need to be able to install and run Core API on machines that don’t have developer tools or a Python toolchain installed.

In the Blockstack macOS app, we are currently building a virtualenv but are unable to relocate it because of native dependencies and the inability to run Core in directories that contain spaces. To work around these issues, we build our Core virtualenv in /tmp/blockstack-venv and deploy in the same location on every machine.

Besides posing a security problem this also makes it impossible to support multiple users. (See this thread for more discussion about multi-user issues).

Configuration

Initial setup

It would be nice to be able to start the API without having to first run the blockstack setup step. It seems like this is something that the API could do automatically for us at start up.

Remote configuration

Users should be able to see how their Core node is configured and modify that configuration via the API.

DRY up config

We use UTXO providers in both Core and Portal. We should consider exposing Core’s UTXO provider through the API so that Portal can use it. This way we can only one UTXO setting.

Working with wallets

When running Core as part of the macOS app, on-boarding of the user happens through the Portal web app, after we’ve already started the Core API. It is during that on-boarding process that users select the password for the wallet built-in to the Portal that currently only holds their identities.

We randomly generate a wallet password for the Core wallet prior to on-boarding the user since on-boarding occurs after the Core API is started.

This makes it difficult for the user to protect their funds. They don’t know the password nor can they easily back up the wallet.

Even if they did, this would mean they have two wallets: an identity wallet and a bitcoin wallet - and would have to back up and restore each separately. From a UX perspective, it makes more sense for the user to only have 1 wallet: 1 password to remember and one backup phrase to keep safe.

I hope we can agree going forward to use either the Core wallet or the Portal wallet for both identity and bitcoin storage.

Using Core wallet via the API

If we go forward with using the Core wallet, it help to have an API that lets users create, delete and otherwise work with wallets. Methods that require the user’s password should require it as a parameter.

Using Portal wallet with the API

If we go forward with using the Portal wallet for both identity and money, we would need methods that need to generate Blockstack transactions to generate and return Bitcoin transactions that can be signed by the Portal wallet.

Test mode

A built in easy to use test mode (ie. not real bitcoin) mode would a HUGE UX improvement for developers. Configuring test environments is a pain point for developers. It isn’t reasonable to expect a developer looking to write an app that uses our API to install a local bitcoind node running on testnet and run our integration test framework.

To see how much of a barrier this is, we need only look at our own Portal team. @guylepage3 , @ryan and I develop the Portal on the live network. This limits the amount of real testing we can do because of cost and time limitations.

Perhaps we could provide a test mode public fleet of testnet bitcoind nodes and build in an easily enabled test mode into Core. Something that we could start with a point and click from the Blockstack for [macOS, Windows, Linux] apps.

Stripe’s Test/Live mode is (again) a best of class example of a developer friendly test mode - developers can switch between test and live mode of the API by switching API keys.

It’s also important provide test input values that let developers replicate the full range of success and error states of the API. In our case, we might want to populate our test mode with a series of test profiles, etc. Again, see Stripe’s test input data.

Summary

Developers LOVE friendly APIs. (Which is why I keep citing Stripe’s API)

Building a product is hard. An API that is a pleasure to work with and makes your life easier lets you focus your energy on solving problems for your customers and building an amazing product.

I think we’re well on our way to an API that developers will fall in love with.

I’d love to hear your thoughts both on what I’ve wrote and things you think I’ve missed.

2 Likes

Larry this is great feedback! I’ll create some Github issues out of the stuff that is straight forward and should just be done. For some other things we can have a discussion either here or on Github. [quote=“larry, post:1, topic:854”]

Developers LOVE friendly APIs. (Which is why I keep citing Stripe’s API)
[/quote]

Agreed 1000x. So it’s very important to get this right.

1 Like

We use UTXO providers in both Core and Portal. We should consider exposing Core’s UTXO provider through the API so that Portal can use it. This way we can only one UTXO setting.

Good idea; let’s add an endpoint. I’ve opened a Github issue for it.

This is what we’re working towards, for this very reason :slight_smile: Just opened an issue for it.

1 Like

Would you agree that it should return 502/503 if it cannot talk to a backend service (like a UTXO provider) for some reason?

This exists: https://github.com/blockstack/blockstack-core/tree/master/integration_tests

Maybe we just don’t announce it wide enough?

Yeah, we haven’t announced it widely. I can take a crack at giving simple instructions for running Blockstack in test mode (maybe that’s what we should call it in the documentation instead of integration tests).

1 Like

Yes. That makes sense to me. If a backend service is broken, my Core node is also broken!

I’d imagine most people aren’t aware of it…I am though. I don’t use it, because it’s already hard enough to configure one working Core node on my computer without having to set up another one that works differently than the mainnet one.

Another problem I encountered in the past is that running bitcoind on my laptop turns my laptop that normally has ~10 hour battery life into a laptop with < 3 hours of battery life. This makes my lap (too) warm and toasty and effectively tethers me to an outlet.

I set up the Blockstack on testnet back when I was in Milan for Scaling Bitcoin.

While it wasn’t terribly hard, it is a lot of work for someone who just wants to develop a web app.

As part of the process you need to install bitcoind - which in and of itself is already a large learning curve for someone who isn’t already experienced with running bitcoin nodes. Developers developing Blockstack Apps shouldn’t need to know about bitcoin nodes or be running them. They shouldn’t have to be running scripts to check out a bunch of libraries.

Compare this to how one develops against the test mode with Stripe:

Their API functions in test mode if you provide a test mode api key. As you can see from the screenshot above, their documentation automatically has my test mode api key there in the docs. As a developer, all I need to do to get started is to copy and paste their code examples.

Unlike a centralized API, developers will have to download our software. Downloading and installing one piece of software is already asking a lot.

It would be great for developers if we could make changing between mainnet and testnet is as simple as using a different API password or a different port. No assembly required.

@jude Is it possible to build what’s necessary for the test mode framework into the Core node we distribute to end users and point them to our own fleet of bitcoind nodes running on testnet? If that was the case, we could take care of the complexity of starting up an testnet API node in the end user software we distribute to users.

Here is how I would envision this looking a web developer’s perspective with the two different approaches:

Mainnet & Testnet Core nodes on different ports:

Mainnet/Testnet switching controlled by API keys:

You’ll notice the View API Documentation option in the pictures above. That would open a locally hosted copy of the docs currently at https://core.blockstack.org customized with the local node’s credentials and/or the proper test node port.

Developers looking to build apps on the decentralized internet could set up their test environment by:

  1. Installing Blockstack (for [Mac | Linux | Windows]))
  2. Clicking “Enable Development Mode”
  3. Writing code.

I agree that we should simply have a fleet of testnet bitcoind nodes. Developers are not going to deploy them.

I started a Github issue: https://github.com/blockstack/blockstack-core/issues/367

Please comment there to add specific tasks. Once we agree on what we need to do, I can break them into separate issues and assign a timeline. My guess is this is not going to get covered in the current sprint. For this sprint we’re focused on improving the UX of the mainnet deployment.

1 Like

Great feedback @larry! And great responses @muneeb and @jude.

Building off of @larry’s feedback, from my perspective the highest priorities are:

  1. Consistent error reporting across the board with both error codes and error messages and consistent http status codes, similar to how Stripe reports errors. This will allow us to properly handle all cases in the Portal and ensure a smooth name registration experience.

  2. Support for instant balance updates via the tracking of zero confirmation transactions. This can be done today using the UTXO provider built in to explorer.blockstack.org. This will allow us to massively improve the user experience for depositing bitcoins and then registering a name. With this upgrade, users will be able to get started with registering a name instantly and the onboarding process can be smooth. Without this, the process is cumbersome at best and the user has to leave and comeback. This could result in a 95% drop off rate or greater.

  3. Support for shuttling name transaction through more quickly. The preorder should be able to be sent using the unconfirmed transactions (the user is paying after all). The register should be able to be sent fewer than 6 blocks after the preorder. I feel like this could be anywhere from 1 to 3 but we might want to go with 3 to at least have some re-org protection. Then, the name update and transfer should be able to be pushed through as soon as possible. I’m not sure what the constraints are on the Blockstack name processing rules, but we should brainstorm how we can get a name registered with a zone file and transferred in as few total blocks as possible.

Everything else I will +1 as well.

Great continued work on everything. And great reporting and feedback. The API is getting better and better and we’re building a pretty awesome combined package.

Agree. Waiting even 1 transaction is a really bad experience.

The explorer is using insight-api which connects to a bitcore node.

We also use this API in the portal to include their unconfirmed Bitcoin transactions in their balance.

This is very important too. Most users will be registering on laptops that aren’t left powered on all the time. It’s a lot to ask someone to keep their computer running continously for 10-12 hours.

1 Like

Some additional thoughts regarding Core installation:

Right now, we have a couple installation methods for Core on each platform:

macOS

  1. Download and run Blockstack for macOS
  2. Install with brew + pypi.

Linux (Debian/Ubuntu)

  1. Install via apt
  2. Install via combination of apt + pypi

Windows

  1. Install via pypi

Compare to Keybase

Compare this to something like Keybase:


On macOS, the only supported method of installation is to download the app and drag it to Applications. (Like most apps on macOS) You get both the GUI and the CLI.


On Linux, they offer packages for Debian/Ubuntu, Redhat/Fedora and Arch Linux.
https://keybase.io/docs/the_app/install_linux Again, it gives you both the GUI and CLI.

On Windows, they have a setup program that gives you the GUI.


Simplifying deployment

I propose we do something similar:

macOS

On macOS, downloading our app and dragging our app to Applications should be the only way we expect developers to deploy. We can symlink blockstack to /usr/local/bin so that it is available for those that would like to use it from the command line. This is what keybase does:

I can’t really think of an instance on macOS where we’d want developers to install only Core by itself without Portal. We don’t need to support running public API instances on macOS.

Currently, it’s confusing having to ask people who have problems how they installed Core. If they ran pip install blockstack outside of a virtualenv, inside of a virtualenv or via the mac app. Depending on how they installed it, troubleshooting steps are different and files are in different places. When people install things outside of the macOS app bundle system, which cleanly encapsulates everything to do with our application in a single, relocatable directory tree, there’s the potential to conflict with other things they have on this system.

Linux

We should only support installation through operating system package systems. Most of the problems we see from people trying to set up blockstack are related to managing python dependencies, particularly those that have native dependencies.

On Linux, it should definitely be possible to install Core with the CLI without Portal or a future GUI. Having said that, users looking to run a API endpoint or develop a Blockstack app on Linux still shouldn’t need to deal with a build toolchain or be exposed to dependencies.

Windows

We should have a setup program that installs everything that’s needed - GUI + Core + Portal.

Repo README instructions

Our READMEs could say something like:

If you are looking to build an app on Blockstack, please visit https://blockstack.org/download to install Blockstack on your computer.

If you would like to contribute features to this package, please follow the instructions below to clone this repository and set up your development environment.

This way, only people looking to hack on a particular package (as opposed to use it to build their own app or deploy their own service), would be forced to create virtualenvs, clone repos, install/use homebrew, deal with building dependencies, etc.

1 Like

I agree with simplifying installation paths and options.

On macOS, we can just have 1 build.

For Linux, the build should also ship the Flask interface and docs i.e., after a user is done installing they can see an interface like http://core.blockstack.org. That’ll push everyone to use the same interface when talking to Blockstack.

Windows we can deal with later on.

1 Like

Woah woah woah. Something has been severely mis-communicated. This has been available for ages.

You do NOT need to set up a testnet bitcoind node to run the test framework. You do NOT need to go through all that pain.

Once you have bitcoind installed, literally the only thing you have to do to run an interactive test environment for Blockstack is this:

$ # install the test framework
$ cd integration-tests/
$ ./setup.py build && sudo ./setup.py install
$ 
$ # run one of the scenarios in "interactive" mode to populate the blockchain, 
$ # with 10-second block times once it finishes
$ blockstack-test-scenario --interactive 10 blockstack_integration_tests.scenarios.rpc_register

The blockstack-test-scenario command takes care of starting a Core node in test mode, starting an API server in test mode, starting a bitcoind node in regtest mode, setting up and filling regtest wallets, and advancing the blockchain. It works offline (no network access required), and it works even if you have a regular bitcoind node, a regular API server, and a regular Core node co-located and running on your machine.

You can use the blockstack tool and all Blockstack libraries and ancillary software unmodified with the test environment. You just need to set a few environment variables first (documented in that README).

This is available at http://packages.blockstack.com for Debian/Ubuntu. We don’t ship Portal as a package yet, but we do ship all the Python libraries and Blockstack Core as .debs.

Oh wow! I guess there was a misunderstanding. Thank you for clearing that up.

It sounds like we should be able to package this functionality (including bitcoind) in our distribution package and make it one-click runnable for devs.

Sure, that’s fine. We can make a statically-linked bitcoind binary for i386/amd64.

1 Like

It sounds like we should be able to package this functionality (including bitcoind) in our distribution package and make it one-click runnable for devs.

I support that but typical desktop users should not have their own bitcoind running. I think you mean for developers who want their own local bitcoind but I’m just clarifying.

You mean typical desktop users should not have their own bitcoind running, right?

Ha yes I just edited the post.

Ideally, depending on size, we could ship everything that’s needed to start a core node in test mode…including the bitcoind executable, but only enable it if user enables development mode.

1 Like