Using Circuit Templates
This guide explains how to use the
circuit-template feature of Splinter,
including explaining the concept and format of a circuit template file and
how to use the
circuit-template feature when developing an application.
A circuit template contains a set of rules which partially define a new circuit. Templates make circuit creation substantially easier, as only a minimal amount of information needs be provided–the remainder is defined in the circuit template.
Circuit templates can be used via the Splinter CLI. The
splinter-circuit-template-* commands list, show, and display further information
about selected templates. The
option utilizes a template to create a circuit proposal. Aside from the Splinter
CLI, templates may also be used to create a circuit within an application.
Splinter’s Gameroom example utilizes the
circuit-template feature within the
Gameroom daemon. This document will cover examples of both scenarios.
YAML is currently the only supported format for template files. The following is an example circuit template YAML file used by the Gameroom application:
version: v1 args: - name: ADMIN_KEYS required: false default: $(SIGNER_PUB_KEY) description: >- Public keys used to verify transactions in the scabbard service - name: NODES required: true description: "List of node IDs" - name: SIGNER_PUB_KEY required: false description: "Public key of the signer" - name: GAMEROOM_NAME required: true description: "Name of the gameroom" rules: set-management-type: management-type: "gameroom" create-services: service-type: 'scabbard' service-args: - key: 'admin_keys' value: [$(ADMIN_KEYS)] - key: 'peer_services' value: '$(ALL_OTHER_SERVICES)' first-service: 'a000' set-metadata: encoding: json metadata: - key: "scabbard_admin_keys" value: ["$(ADMIN_KEYS)"] - key: "alias" value: "$(GAMEROOM_NAME)"
There are three main sections in a circuit template:
This describes the version of the template being used. The template’s version
determines the available
rules. The template rules are explained below.
args section of the template shows the arguments used by the template’s
rules. Each argument shows a description of the information that is required by
the circuit template’s rules to fill in the circuit definition. A rule can
name, The following argument definition is from the example YAML
- name: SIGNER_PUB_KEY required: false description: "Public key of the signer"
This shows the definition of the
SIGNER_PUB_KEY argument, which includes a
short description string and an indicator of whether or not the argument is
required. This argument will be assigned a value when the circuit is being
The value of an argument may be used to fill in other necessary information
within the template. The value of an argument can be referred to using the
command substitution syntax, for example the
SIGNER_PUB_KEY argument would
$(SIGNER_PUB_KEY). This syntax may be used when assigning the
default value of an argument. The following shows the definition of the
ADMIN_KEYS argument which uses the
SIGNER_PUB_KEY argument as its default
- name: ADMIN_KEYS required: false default: $(SIGNER_PUB_KEY) description: >- Public keys used to verify transactions in the scabbard service
Rules use the argument values for defining the circuit. The rules, therefore, reflect the format of the circuit the template is intended for. The version of a template determines the available rules.
Version 1.0 Available Rules
set-management-type: This rule takes a single argument,
management-type, and sets the circuit’s management type.
create-services: This rule takes a
first-servicewhich are used to build the services included in a circuit.
set-metadata: This rule takes a
JSON. The template uses this rule to set the circuit’s metadata, using the encoding specified.
Rules within the template are backed by specific functions. These functions use the argument values explained above. When writing a template, think of a rule as a function signature. Rules show the function, in kebab case, along with their required arguments. See the following:
set-metadata: encoding: json metadata: - key: "scabbard_admin_keys" value: ["$(ADMIN_KEYS)"] - key: "alias" value: "$(GAMEROOM_NAME)"
This rule is associated with a function used to set the
metadata field of the
CreateCircuitBuilder. The rule’s options allow for specifying the details
necessary for the function associated with the template rule to assign that
builder value. The
scabbard_admin_keys key’s value is
which refers to the value assigned to the ADMIN_KEYS
argument inserted into a
list. Similarly, the alias
key would be assigned the value assigned to the
argument value. This example also shows the encoding` option,
which determines the encoding of the metadata being assigned to the builder.
Currently, the only supported option is JSON.
SPLINTER_CIRCUIT_TEMPLATE_PATH environment variable can be used to specify
directories which contain template files, either while using the Splinter CLI or
developing an application. Regardless of whether
is set, the default directory,
checked when retrieving template files. The environment variable allows for
control over the template files being used.
Multiple directories may be specified in
paths delineated by
:. If multiple storage directories are specified, the
directories are given the precedence as determined by their position in the list
of paths. For example, set the
SPLINTER_CIRCUIT_TEMPLATE_PATH using the
$ export SPLINTER_CIRCUIT_TEMPLATE_PATH='foo:bar'
This affects the
splinter-circuit-template-list and the rest of the
splinter-circuit-template commands. The list command will print out all YAML
files within the directories specified. However, when selecting a specific
template file in a command, unless the full path to the file is specified, the
first template file matching the name passed into the argument will be used in
the command. For example, there is a template file
$ export SPLINTER_CIRCUIT_TEMPLATE_PATH='foo:bar' $ splinter circuit template show bar
The following command will show the template found in the
foo/bar.yaml. The full path to the template file must be specified if multiple
template files with the same name exist and the
variable is set.
- Verify the file paths for circuit template files and the value, if any,
assigned to the
SPLINTER_CIRCUIT_TEMPLATE_PATHenvironment variable. If this value is set, the directories specified will be searched in the order provided. Set the environment variable, or clear it to ensure the default circuit template storage directory,
/usr/share/splinter/circuit-templates, is used.
Using circuit templates in the Splinter CLI
The Splinter CLI offers the
splinter-circuit-template-* commands that can be
used to list and display further information about circuit templates. The
splinter-circuit-template-* commands solely provide information about the
circuit templates found or specified. For example, the
splinter-circuit-template-show command displays a specific template.
Additionally, all of the template
arguments may be displayed using the
splinter-circuit-template-arguments command. More information about the
splinter-circuit-template-* commands can be found in the circuit template
The template is put into action using the
template option. The
template option takes the template name and then uses
the template rules and arguments to create the circuit proposal. The following
example illustrates how to use a simple circuit template to propose a circuit.
Below is an example of a simple circuit template. This template only requires
SIGNER_PUB_KEY argument and has rules to set the circuit’s management type
version: v1 args: - name: NODES required: false description: "List of node IDs" - name: SIGNER_PUB_KEY required: true description: "Public key of the signer" rules: set-management-type: management-type: "simple" create-services: service-type: ‘simple’ first-service: ‘AA01’ service-args: - key: 'admin_keys' value: [$(SIGNER_PUB_KEY)]
This template can be specified using the
template option of the
command. The template arguments are set using the corresponding
option. If any required arguments are not set, the circuit proposal will not be
created and an error will be returned specifying the missing argument. While the
circuit template will complete the circuit proposal based on its rules and
arguments, any custom-set arguments using the
propose command’s other options
will take precedence over the default template values. Any additional information
for the circuit proposal may also be included using the command’s other options.
More information on this command can be found in the circuit propose CLI
NOTE: Template files within Splinter are stored by default in
/usr/share/splinter/circuit-templates unless the
environment variable is set. If using a template file outside of the paths
specified by this environment variable or the default directory, use the full
path when specifying the
template option to ensure the correct template file
is used when proposing the circuit.
This command proposes a simple circuit with one other node using the
- The proposing node has ID alpha001 and endpoint tcps://splinterd-node-acme001:8044.
- The other node has ID beta001 and endpoint tcps://splinterd-node-beta001:8044.
$ splinter circuit propose \ --node alpha001::tcps://splinterd-node-alpha001:8044 \ --node beta001::tcps://splinterd-node-beta001:8044 \ --template simple.yaml \ --template-arg SIGNER_PUB_KEY=PRIVATE-KEY-FILE \ --url URL-of-splinterd-REST-API
If successful, this command will create a simple circuit proposal based on the
information gathered by the circuit template and the
node arguments provided.
Using circuit templates in Splinter applications
This example uses the circuit template file used in the Splinter Gameroom application. The same concepts and procedures may be applied to any type of circuit. The following example guides developers through the process of using a circuit template file in an application.
First the template must be loaded, usually from a YAML file, to create a
CircuitCreateTemplateobject. All existing circuit template files use the YAML format. The following line shows how a template is loaded from the circuit template directory:
let template = CircuitCreateTemplate::from_yaml_file("gameroom.yaml")?;
NOTE: All available circuit templates are packaged in the default circuit template directory,
/usr/share/splinter/circuit-templates. Unless the
SPLINTER_CIRCUIT_TEMPLATE_PATHis set, in which case all directories specified using this environment variable are searched for the template files.
The args of the
CircuitCreateTemplateobject created in the step above must be set. Each entry in the args section of the circuit template holds further information on how the argument is used. For example, the
NODESargument is described as follows in the circuit template:
name: NODES required: true description: "List of node IDs"
This entry shows that the
NODESargument is required and a short description. Therefore, if this argument is not set in the circuit template, the circuit template will not successfully create the builder objects. Some arguments have default values, this is shown in the
ADMIN_KEYSargument entry in the circuit template file.
name: ADMIN_KEYS required: false default: SIGNER_PUB_KEY description: >- Public keys used to verify transactions in the scabbard service
As this argument is not required, there is a default value applied if it is not provided. This default value is the value of the
signer_pub_keyargument. For the Gameroom circuit template, the
gameroom_nameare required to be set. To set these values:
template.set_argument_value("nodes", &list_of_nodes)?; template.set_argument_value("gameroom_name", gameroom_alias)?;
list_of_nodesis a string with all circuit participants’ node ID separated by a comma. Similarly, the
gameroom_aliasvalue is also a string. The other arguments available to be set for the Gameroom circuit template are the
signer_pub_key, which is the public key of the transaction signer represented by a string, and the
admin_keys, are the admin keys used by the Scabbard service represented by a list of strings. These values are set similarly to the required values:
template.set_argument_value("signer_pub_key", signer_public_key)?; template.set_argument_value("admin_keys", admin_key_list)?;
Once all of the required arguments have been set, the circuit template object may be turned into builder objects that are converted to the finalized object once all of the necessary circuit information is gathered. This is done as follows:
let (create_circuit_builder, service_builders) = template.into_builders()?;
This method will return an error if any of the required arguments have not been set. The
CreateCircuitBuilderobject while the
service_buildersis a list of
SplinterServiceBuilderobjects. Both of these types of builder objects are used to compile the necessary information to propose a circuit.
At this point, all of the rules are applied to the circuit template. This means that the builders are assigned values based on the rules using the values from the arguments. In the gameroom circuit template, this includes the
set-metadatarules. rules are predefined functions that use the values set for the template’s args that produce information necessary to fill in the blanks of the builder objects. The full functions used for these rules can be found within the
circuit::template::rulesmodule. The template entry for each rule also gives some information as to what the rule is actually doing.
For example, the
set-metadatarule sets the
metadatafield of the
CreateCircuitBuilder. From the template:
set-metadata: encoding: json metadata: - key: "scabbard_admin_keys" value: ["$(ADMIN_KEYS)"] - key: "alias" value: "$(GAMEROOM_NAME)"
From the template entry, we can see the encoding for the
metadatais JSON. The value of the
metadatafield is represented by a map, a set of keys and values, as shown in the template. One key is
scabbard_admin_keyswhich takes the value of the
admin_keystemplate argument. The
gameroom_nameargument is assigned to the
create_servicesrule generates a
SplinterServiceBuilderfor each service involved in the circuit. For a circuit with two participating nodes, this rule would generate two
SplinterServiceBuilderobjects. A different type of service, besides Scabbard, may also be added to the circuit template YAML file by adding an entry under the
create_servicesrule on the Gameroom template generates Scabbard
scabbardis specified for the
service-type. Similar to the
set-metadatarule, this rule also creates a map to hold the
service-argsused to initialize the Scabbard instance.
This rule includes the
service-argsentry and a
peer_serviceskey has a value,
$(ALL_OTHER_SERVICES), meaning this key is assigned the definition of the
create-services: service-type: 'scabbard' service-args: - key: 'admin_keys' value: [$(ADMIN_KEYS)] - key: 'peer_services' value: '$(ALL_OTHER_SERVICES)' first-service: 'a000'
After the builder objects have been generated from the
CircuitCreateTemplate, any remaining information may be added to any of the builders. The Gameroom example includes filling in the
membersfield of the
Once a list of the members has been created, represented by a list of
node_idfield and an
endpointsfield. Assuming the list of
SplinterNodeobjects has been created, and is called
members, setting this value in the builder looks like the following line:
Additionally, the list of services must be added to the
rosterfield takes a list of
SplinterServiceobjects. In an earlier step, we generated a list of
SplinterServiceBuilderobjects. Each of these can be turned into a
SplinterServiceobject using the
buildmethod and do not require any additional information to successfully build.
SplinterServiceBuilderhas been built, the list can be added to the
services_listis the list of
SplinterServiceobjects created previously.
At this point, all necessary information has been added to the
CreateCircuitBuilderand it is ready to be turned into the
let create_circuit = create_circuit_builder.build()?;
This will result in a
CreateCircuit object which holds all of the information
submitted to the circuit template and the builder objects.