Public | Automated Build

Last pushed: a year ago
Short Description
Stratumn agent
Full Description

Agent

This repository contains:

  • A lightweight Express.js server to run a Chainscript agent
  • A Dockerfile file to build a base Docker image stratumn/agent, meant to be
    extended in order to build a Docker container for an agent

It does not, and is not meant to, add meta data specific to Stratumn to a
Chainscript. While this repository is currently private, it is technically
possible for a user to see the compiled source code because it is embedded in
a agent's container.

Usage

Prerequisites

You need node.js to run a server, and Docker if you want to build the Docker
image.

Running

Install dependencies:

$ npm install

Build:

$ npm run build:lib

Install on your machine:

$ npm link

Launch an agent without Docker:

$ stratumn-agent /path/to/agent/directory

Test:

$ npm test

Test coverage:

$ npm run test:coverage
$ open coverage/lcov-report/index.html

Lint:

$ npm run lint

Lint and test:

$ npm run check

Build the base Docker image:

$ npm run docker:build

Chainscript

The source code implements the Chainscript Segment spec without any fossilization:

{
  "link": {
    "state": { "message": "test" },
    "meta": {
      "mapId": "abc",
      "prevLinkHash": "ed6a96158161df71c6ccb2e6c25086790fac9fe7f3621a7d6bc33aea8a04ec30",
      "stateHash": "4144005e3e781532fa967b3a15d3ccf5881c1da5ff6be0dc0db4a399631d187a",
      "agentHash": "6206d20d5ded8974d10fb7cc984e8606b3fed8d7d048243bb8e892cf9990c225"
    }
  },
  "meta": {
    "linkHash": "f63805499c7beebe8afb8538115795308084bb327eda1e2fc4963bfedcfb1ee5",
    "errorMessage": "Expected the first argument to be a string"
  }
}

A Chainscript Segment wraps a link and meta data. A link contains everything that is
meant to be timestamped an a blockmap. The meta data contains relevant
information about the link, such as:

  • linkHash: the cyptographic hash of the link
  • errorMessage: an error message if one occured
  • possibly evidence that the link hash was inserted in a blockmap via a Merkle
    tree (though this part is implemented in a separate component)

A link contains a state, which is user defined data meant to be auditable. It
also contains meta data, such as:

  • mapId: an ID common to all links in an auditable map
  • prevLinkHash: the cryptographic hash of the previous link, or null if none
  • stateHash: the cryptographic hash of the state
  • agentHash: a cryptographic hash of the agent, by default a hash of the
    agent script, but it could also be the hash of a tarball for example

Agent spec

It expects an agent to be a folder containing:

  • an agent script
  • a package.json file with main specifying the location of the agent script

An agent script looks like this:

module.exports = {

  /**
   * You can override the initializer. If not, the default implementation will
   * just set the state to the first given argument.
   */
  init: function(message) {
    this.state.message = message;
    this.append();
  },

  /**
   * You can define transition functions to append links.
   */
  send: function(message) {
    this.state.message = message;
    this.append();
  },

  /**
   * They can have multiple arguments.
   */
  sendWithAuthor: function(message, author) {
    this.state.message = message;
    this.state.author = author;
    this.append();
  },

  /**
   * You can also pass a state to Agent#append()
   */
  appendWithState: function(message) {
    this.append({ message: message });
  },

  /**
   * You can add or read link meta data.
   */
  sendWithMeta: function(message) {
      this.state.message = message;

      if (!this.meta.version) {
          this.meta.version = '0.1.0';
      }

    this.append();
  },

  /**
   * You can also pass meta to Agent#append()
   */
  appendWithMeta: function(message) {
    this.append({ message: message }, { version: '0.1.0' });
  },

  /**
   * You can reject with a string.
   */
  rejectWithString: function() {
    this.reject('Failed');
  },

  /**
   * You can reject with an error.
   */
  rejectWithError: function() {
    this.reject(new Error('Failed'));
  },

  /**
   * You can also use Agent#error instead.
   */
  rejectWithoutArg: function() {
    this.error = 'Failed';
    this.reject();
  },

  /**
   * You can also specify a function that will catch all unhandled methods. The
   * first argument is the name of the function, followed by the rest of
   * the arguments.
   */
  catchAll(func, arg1, arg2) {
    this.state.func = func;
    this.state.arg1 = arg1;
    this.state.arg2 = arg2;
  }

};

API

This not the Agent API. This the API exposed by the server in this repository
used by Demux to communicate with agents.

POST /

Creates the initial link of a map and returns its Segment.

Expected payload:

{
  "mapId": "abc", // The ID of the map
  "args": []        // Optionally, arguments passed to Agent#init (array or single value) 
}

If query parameter debug is set, the error stack will be added to the meta data
if an error occures (meta.errorStack).

POST /:func

Executes the transition function specified by :func and returns its Segment.

Expected payload:

{
  "link": {},       // Current link
  "meta": {},       // Current meta
  "args": []        // Optionally, arguments passed to Agent#:func (array or single value) 
}

If query parameter debug is set, the error stack will be added to the meta data
if an error occures (meta.errorStack).

Creating a Docker image for an agent

Make sure you either ran npm docker:build or pulled the latest image using
docker pull stratumn/agent.

Then create a Dockerfile in the agent's folder with the following content:

FROM stratumn/agent

Build the image:

$ docker build -t my-agent .

Launch a container for your agent:

$ docker run -p 3000:3000 -d my-agent

By default, the agent hash is the hash of the agent script. You can specify
a custom one:

$ docker run -p 3000:3000 -d my-agent -h custom_hash

License

Copyright 2016 Stratumn

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Docker Pull Command
Owner
stratumn
Source Repository