In many ways building a web app as a client to a Sawtooth blockchain is not much different than building a web app for any server. You will create some React components that will display the data you GET from a REST API. Users will fill out forms and you will take that information and POST it. Of course, everything you GET will be a base64 encoded binary file, and all of your POSTs will be cryptographically signed transactions. But that's where the fun is!
This component uses npm to manage dependencies, so the first thing you should do is install them:
cd client/
npm install
Once that's done, you will need to build your front-end code with webpack.
This will use source/index.jsx as an entry point, and pull
in all of your other modules from there to create a bundle saved at
public/bundle.js
. Anything in the public/ directory will be served
at localhost:3000
, so when you run docker-compose up
(see Using
Docker), you should be able to view it from your
browser. In order to run the build, there are a few commands you can use.
You can build the production code:
npm run build:prod
However, most of the time you will probably what to build your code in dev-mode. It builds faster, includes more debugging information, and will even automatically rebuild every time you save changes:
npm run build:dev
And you can go a step further and serve the dev code from a live-reload server
at localhost:3001
. Good news, you won't have to refresh your page! Bad news,
you won't be able to make any API calls or interact with the blockchain at all:
npm run watch
Like other components, the front-end uses Mocha/Chai for testing. Unlike other components, there is a pretty sweet browser-based test runner. To pull it up, simply run:
npm test
Before you start in on this part of the project make sure you have reviewed the Sawtooth Curriculum, in particular the sections on build and submitting transactions, as well as Signing from part one.
Module: source/services/signing.js
If you completed part one, this section should be pretty much done. Both Sawtooth and your DIY blockchain use Secp256k1 for signing, so you will be able to copy over most of your code.
There is one slight difference to keep in mind. While you signed strings in
part one, you will be signing encoded transactions in part two (i.e. Buffers).
This probably won't make much of a difference, but depending on how you
implemented sign
the first time, it may require some changes.
Module: source/services/encoding.js
Next you will want to build a module to encode/decode transactions and state data. Remember from the design, that we are using sorted JSON strings encoded in a Node Buffer. Webpack will allow you to use Buffers in the browser just fine, but you could also use UInt8Arrays if you prefer.
Module: source/services/transactions.js
Useful APIs:
This is the first really Sawtooth specific module. You will need to take your encoded payloads, and wrap them in a transaction. Then one or more transactions get wrapped in a batch, and one or more batches get wrapped in a batch list, which is finally serialized as bytes so it can be sent to the REST API. All of these data structures are Google Protobufs, which are a somewhat complex, but very efficient way of serializing data. You don't need to become a protobuf expert to use Sawtooth, but you should probably familarize yourself with the, Protobuf.js API, which is what the Sawtooth SDK uses under the hood.
In particular, be ready to use:
TransactionHeader.encode(headerData).finish()
Transaction.create(transactionData)
BatchHeader.encode(batchHeaderData).finish()
Batch.create(batchData)
BatchList.encode(batchListData).finish()
Module: source/services/addressing.js
The last module you will complete stub functions for is one to generate addresses for entities in state. You will need these in order to fetch any data from the REST API.
Module: None Useful APIs:
The design and execution of the rest of the client is entirely up to you. There are no more tests. One thing you will definitely need to do though is send GET/POST requests to the blockchain. If you like, you could incorporate this functionality throughout the rest of your app. However, it will likely make sense for you to create another services module to encapsulate interactions with the REST API.
Either way, one perk of the docker setup for serving this client, is that the
Sawtooth REST API has been proxied under the api/
path, so you can access
every REST API route using a relative path. There are three routes/queries you
are likely to be concerned with.
This fetches a base64 encoded entity from state. Sawtooth puts your data in a
JSON envelope under the data
key, which axios automatically decodes for you,
and stores under the . . . data
key. This means the data you want will be
in response.data.data
.
The merkle tree that Sawtooth data is stored in allows you to fetch multiple
entities at once if they are under the same address prefix. So for example,
you could fetch /api/state?address=5f4d76
to get every entity in state, or
/api/state?address=5f4d7600
to get every collection. These entities will be
in a JSON array with this format:
[
{
"address": "<string, full address>",
"data": "<base64 string, encoded entity>"
}
]
And yes, that means the base64 string you want to decode is at
response.data.data[i].data
.
¯\_(ツ)_/¯
This is the endpoint to which you will actually post your serialized batch
lists. Include them directly in the body of your request, and don't forget to
set the Content-Type
header to application/octet-stream
.
Module: source/index.jsx
Requirements:
- Allow users to generate new private keys and create collections
- Allow users to "sign in" by copying/pasting in their private key
- Allow users to View all cryptomoji in state
- Allow users to view just their own cryptomoji
- Allow users to select a sire from their collection
- Allow users to view all available sires
- Allow users to breed one of their cryptomoji with a sire
There are no tests for the UI. It is up to you to design and build an interface you are happy with that satisfies all of these requirements. Have fun!
Note that a parseDna method is provided, which will convert a DNA string into a real kaomoji for display. Make sure you use it!
Requirements:
- Allow users to create/cancel offers from their cryptomoji
- Allow users to view all available offers
- Allow users to add/cancel responses to outstanding offers
- Allow users to accept responses, executing a trade
- Allow users to view detailed information on a cryptomoji, like their family
tree and "tags" (generated by
parseDna
) - Dynamically alter the way a cryptomoji is styled based on its tags
- Allow users to filter/sort lists of cryptomoji by tags and/or other factors (e.g. "number of times sired")
Also don't forget to remove the .skip
from Line 96 of
tests/04-Addressing.js!