Using Sawtooth with PoET-SGX

Note

PoET-SGX is currently not compatible with Sawtooth 1.1 or later. Users looking to leverage PoET-SGX should remain on Sawtooth 1.0.

This procedure describes how to install, configure, and run Hyperledger Sawtooth with PoET simulator consensus on a system with Intel® Software Guard Extensions (SGX).

For the procedure to configure a Sawtooth node with a different consensus algorithm, such as PoET, see Setting Up a Sawtooth Network.

Note

These instructions have been tested with Sawtooth 1.0 on Ubuntu 16.04 only.

Prerequisites

BIOS Update

Important

You may need to update your BIOS with a security fix before running Hyperledger Sawtooth with PoET. Affected versions and instructions for updating can be found on Intel’s website. If you’re running an affected version, you must update the BIOS to ensure that these installation instructions work correctly.

You can verify the BIOS version after the machine has booted by running:

$ sudo lshw| grep -A5 *-firmware
     *-firmware
          description: BIOS
          vendor: Intel Corp.
          physical id: 0
          version: BNKBL357.86A.0050.2017.0816.2002
          date: 08/16/2017

Install SGX and PSW

Install the prerequisites for SGX and the Intel SGX Platform Software (PSW).

$ sudo apt-get update &&
  sudo apt-get install -y \
      alien \
      autoconf \
      automake \
      build-essential \
      cmake \
      libcurl4-openssl-dev \
      libprotobuf-dev \
      libssl-dev \
      libtool \
      libxml2-dev \
      ocaml \
      pkg-config \
      protobuf-compiler \
      python \
      unzip \
      uuid-dev \
      wget

Download and install the SGX driver:

$ mkdir ~/sgx && cd ~/sgx
$ wget https://download.01.org/intel-sgx/linux-2.0/sgx_linux_x64_driver_eb61a95.bin
$ chmod +x sgx_linux_x64_driver_eb61a95.bin
$ sudo ./sgx_linux_x64_driver_eb61a95.bin

Download and install the Intel Capability Licensing Client. This is presently available only as an .rpm, so you must convert it to a .deb package with alien:

$ wget http://registrationcenter-download.intel.com/akdlm/irc_nas/11414/iclsClient-1.45.449.12-1.x86_64.rpm
$ sudo alien --scripts iclsClient-1.45.449.12-1.x86_64.rpm
$ sudo dpkg -i iclsclient_1.45.449.12-2_amd64.deb

Download and install the Dynamic Application Loader Host Interface (JHI):

$ wget https://github.com/01org/dynamic-application-loader-host-interface/archive/master.zip -O jhi-master.zip
$ unzip jhi-master.zip && cd dynamic-application-loader-host-interface-master
$ cmake .
$ make
$ sudo make install
$ sudo systemctl enable jhi

Download and install the Intel SGX Platform Software (PSW):

$ cd ~/sgx
$ wget https://download.01.org/intel-sgx/linux-2.0/sgx_linux_ubuntu16.04.1_x64_psw_2.0.100.40950.bin
$ chmod +x sgx_linux_ubuntu16.04.1_x64_psw_2.0.100.40950.bin
$ sudo ./sgx_linux_ubuntu16.04.1_x64_psw_2.0.100.40950.bin

Check to make sure the kernel module is loaded:

$ lsmod | grep sgx
isgx                   36864  2

If the output does not show the isgx module, make sure that SGX is set to “Enabled” in the BIOS.

If you’re still having trouble, the SGX software may need to be reinstalled:

$ sudo /opt/intel/sgxpsw/uninstall.sh
$ cd ~/sgx
$ sudo ./sgx_linux_x64_driver_eb61a95.bin
$ sudo ./sgx_linux_ubuntu16.04.1_x64_psw_2.0.100.40950.bin

After ensuring that the SGX kernel module is loaded, go to the next section to install and configure Sawtooth.

Configuring Sawtooth to Use PoET-SGX

This section describes the Sawtooth steps to configure PoET-SGX consensus.

Install Sawtooth

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 8AA7AF1F1091A5FD
$ sudo add-apt-repository 'deb [arch=amd64] http://repo.sawtooth.me/ubuntu/chime/stable bionic universe'
$ sudo apt-get update
$ sudo apt-get install -y \
  sawtooth \
  python3-sawtooth-poet-engine \
  python3-sawtooth-poet-families \
  python3-sawtooth-poet-sgx

Certificate File

The configuration process requires an SGX certificate file in PEM format (.pem), which you will need before continuing.

Instructions for creating your own service provider certificate can be found here.

After your certificate is created, you’ll need to register it with the attestation service. Click here for the registration form.

Configure the Validator for PoET-SGX

After installing Sawtooth, add config settings so PoET-SGX will work properly.

Create the file /etc/sawtooth/poet_enclave_sgx.toml with your favorite editor (such as vi):

$ sudo vi /etc/sawtooth/poet_enclave_sgx.toml

Add the following lines, replacing [example] with the spid value provided by Intel:

# Service Provider ID. It is linked to the key pair used to authenticate with
# the attestation service.

spid = '[example]'

# ias_url is the URL of the Intel Attestation Service (IAS) server.

ias_url = 'https://test-as.sgx.trustedservices.intel.com:443'

# spid_cert_file is the full path to the PEM-encoded certificate file that was
# submitted to Intel in order to obtain a SPID

spid_cert_file = '/etc/sawtooth/sgx-certificate.pem'

Next, install the .pem certificate file that you downloaded earlier. Replace [example] in the path below with the path to the certificate file on your local system:

$ sudo install -o root -g sawtooth -m 640 \
/[example]/sgx-certificate.pem /etc/sawtooth/sgx-certificate.pem

Create validator keys:

$ sudo sawadm keygen

Note

If you’re configuring multiple Sawtooth nodes, the following steps are required for the first node only. For the other nodes, you can skip the rest of this procedure; continue with Change the Validator Config File.

Become the sawtooth user and change to /tmp. In the following commands, the prompt [sawtooth@system] shows the commands that must be executed as the sawtooth user.

$ sudo -u sawtooth -s
[sawtooth@system]$ cd /tmp

Create a genesis batch:

[sawtooth@system]$ sawset genesis --key /etc/sawtooth/keys/validator.priv -o config-genesis.batch

Create and submit a proposal:

[sawtooth@system]$ sawset proposal create -k /etc/sawtooth/keys/validator.priv \
sawtooth.consensus.algorithm.name=PoET \
sawtooth.consensus.algorithm.version=0.1 \
sawtooth.poet.report_public_key_pem="$(cat /etc/sawtooth/ias_rk_pub.pem)" \
sawtooth.poet.valid_enclave_measurements=$(poet enclave --enclave-module sgx measurement) \
sawtooth.poet.valid_enclave_basenames=$(poet enclave --enclave-module sgx basename) \
sawtooth.poet.enclave_module_name=sawtooth_poet_sgx.poet_enclave_sgx.poet_enclave \
-o config.batch

When the sawset proposal command runs, you should see several lines of output showing that the SGX enclave has been initialized:

[12:03:58 WARNING poet_enclave] SGX PoET enclave initialized.
[12:03:59 WARNING poet_enclave] SGX PoET enclave initialized.

Note

There’s quite a bit going on in the previous sawset proposal command, so let’s take a closer look at what it accomplishes:

sawtooth.consensus.algorithm.name=PoET

Changes the consensus algorithm to PoET.

sawtooth.consensus.algorithm.version=0.1

Changes the version of the consensus algorithm to 0.1.

sawtooth.poet.report_public_key_pem="$(cat /etc/sawtooth/ias_rk_pub.pem)"

Adds the public key that the PoET Validator Registry transaction processor uses to verify attestation reports.

sawtooth.poet.valid_enclave_measurements=$(poet enclave --enclave-module sgx measurement)

Adds the enclave measurement for your enclave to the blockchain for the PoET Validator Registry transaction processor to use to check signup information.

sawtooth.poet.valid_enclave_basenames=$(poet enclave --enclave-module sgx basename)

Adds the enclave basename for your enclave to the blockchain for the PoET Validator Registry transaction processor to use to check signup information.

sawtooth.poet.enclave_module_name

Specifies the name of the Python module that implements the PoET enclave. In this case, sawtooth_poet_sgx.poet_enclave_sgx.poet_enclave is the SGX version of the enclave; it includes the Python code as well as the Python extension.

Create a poet-genesis batch:

[sawtooth@system]$ poet registration create -k /etc/sawtooth/keys/validator.priv \
  --enclave-module sgx -o poet_genesis.batch
Writing key state for PoET public key: 0387a451...9932a998
Generating poet_genesis.batch

Create a genesis block:

[sawtooth@system]$ sawadm genesis config-genesis.batch config.batch poet_genesis.batch

You’ll see some output indicating success:

Processing config-genesis.batch...
Processing config.batch...
Processing poet_genesis.batch...
Generating /var/lib/sawtooth/genesis.batch

Genesis configuration is complete! Log out of the sawtooth account:

[sawtooth@system]$ exit
$

Change the Validator Config File

You must specify some networking information so that the validator advertises itself properly and knows where to search for peers. Create the file /etc/sawtooth/validator.toml:

$ sudo vi /etc/sawtooth/validator.toml

Add the following content to the file:

#
# Hyperledger Sawtooth -- Validator Configuration
#

# This file should exist in the defined config directory and allows
# validators to be configured without the need for command line options.

# The following is a possible example.

# Bind is used to set the network and component endpoints. It should be a list
# of strings in the format "option:endpoint", where the options are currently
# network and component.
bind = [
  "network:tcp://eno1:8800",
  "component:tcp://127.0.0.1:4004",
  "consensus:tcp://127.0.0.1:5050"
]

# The type of peering approach the validator should take. Choices are 'static'
# which only attempts to peer with candidates provided with the peers option,
# and 'dynamic' which will do topology buildouts. If 'dynamic' is provided,
# any static peers will be processed first, prior to the topology buildout
# starting.
peering = "dynamic"

# Advertised network endpoint URL.
endpoint = "tcp://[external interface]:[port]"

# URI(s) to connect to in order to initially connect to the Sawtooth network,
# in the format tcp://hostname:port. This is not needed in static peering mode
# and defaults to None.
seeds = ["tcp://[seed address 1]:[port]",
         "tcp://[seed address 2]:[port]"]

# A list of peers to attempt to connect to in the format tcp://hostname:port.
# It defaults to None.
peers = []

# The type of scheduler to use. The choices are 'serial' or 'parallel'.
scheduler = 'parallel'

# A Curve ZMQ key pair are used to create a secured network based on side-band
# sharing of a single network key pair to all participating nodes.
# Note if the config file does not exist or these are not set, the network
# will default to being insecure.
#network_public_key = ''
#network_private_key = ''

Next, locate the endpoint section in this file. Replace the external interface and port values with either the publicly addressable IP address and port or the NAT values for your validator.

endpoint = "tcp://[external interface]:[port]"

Find the seeds section in the config file. Replace the seed address and port values with either the publicly addressable IP address and port or the NAT values for the other nodes in your network.

seeds = ["tcp://[seed address 1]:[port]",
         "tcp://[seed address 2]:[port]"]

If necessary, change the network, component, and consensus bind interface in the bind section.

bind = [
  "network:tcp://eno1:8800",
  "component:tcp://127.0.0.1:4004",
  "consensus:tcp://127.0.0.1:5050"
]

The default network bind interface is “eno1”. If this device doesn’t exist on your machine, change the network definition to specify the correct bind interface.

Tip

Make sure that all values in this setting are valid for your network. If the bind interface doesn’t exist, you may see a ZMQ error in the sawtooth-validator systemd logs when attempting to start the validator, as in this example:

Jun 02 14:50:37 ubuntu validator[15461]:   File "/usr/lib/python3.5/threading.py", line 862, in run
...
Jun 02 14:50:37 ubuntu validator[15461]:   File "zmq/backend/cython/socket.pyx", line 487, in zmq.backend.cython.socket.Socket.bind (zmq/backend/cython/socket.c:5156)
Jun 02 14:50:37 ubuntu validator[15461]:   File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:7535)
Jun 02 14:50:37 ubuntu validator[15461]: zmq.error.ZMQError: No such device
Jun 02 14:50:37 ubuntu systemd[1]: sawtooth-validator.service: Main process exited, code=exited, status=1/FAILURE
Jun 02 14:50:37 ubuntu systemd[1]: sawtooth-validator.service: Unit entered failed state.
Jun 02 14:50:37 ubuntu systemd[1]: sawtooth-validator.service: Failed with result 'exit-code'.

(Optional) Change the network keys to specify secured network communication between nodes in the network. By default, the network is unsecured.

Locate the network_public_key and network_private_key settings. These items specify the curve ZMQ key pair used to create a secured network based on side-band sharing of a single network key pair to all participating nodes.

Next, generate your network keys.

  • This example shows how to use Python to generate these keys:

    python
     ...
    >>> import zmq
    >>> (public, secret) = zmq.curve_keypair()
    >>> print public
    wFMwoOt>yFqI/ek.G[tfMMILHWw#vXB[Sv}>l>i)
    >>> print secret
    r&oJ5aQDj4+V]p2:Lz70Eu0x#m%IwzBdP(}&hWM*
    
  • Or you could use the following steps to compile and run curve_keygen to generate the keys:

    $ sudo apt-get install g++ libzmq3-dev
      ...
    $ wget https://raw.githubusercontent.com/zeromq/libzmq/master/tools/curve_keygen.cpp
     ...
    $ g++ curve_keygen.cpp -o curve_keygen -lzmq
    
    $./curve_keygen
    == CURVE PUBLIC KEY ==
    -so<iWpS=5uINn*eV$=J)F%lEFd=@g:g@GqmL2C]
    == CURVE SECRET KEY ==
    G1.mNaJLnJxb6BWsY=P[K3D({+uww!T&LC3(Xq:B
    

Finally, replace the example values in the validator config file with your unique network keys.

network_public_key = '{nw-public-key}'
network_private_key = '{nw-private-key}'

After saving your changes, restrict permissions on validator.toml to protect the network private key.

$ sudo chown root:sawtooth /etc/sawtooth/validator.toml
$ sudo chmod 640 /etc/sawtooth/validator.toml

Change the REST API Config File

Create the REST API configuration file, /etc/sawtooth/rest_api.toml by copying the example file from /etc/sawtooth/rest_api.toml.example.

$ sudo cp -a /etc/sawtooth/rest_api.toml.example /etc/sawtooth/rest_api.toml

Use sudo to edit this file.

$ sudo vi /etc/sawtooth/rest_api.toml

If necessary, change the bind setting to specify where the REST API listens for incoming communication. Be sure to remove the # comment character to activate this setting.

bind = ["127.0.0.1:8008"]

If necessary, change the connect setting, which specifies where the REST API can find this node’s validator on the network. Be sure to remove the # comment character to activate this setting.

connect = "tcp://localhost:4004"

Note

To learn how to put the REST API behind a proxy server, see Using a Proxy Server to Authorize the REST API.

Start the Sawtooth Services

Use these commands to start the Sawtooth services:

$ sudo systemctl start sawtooth-rest-api.service
$ sudo systemctl start sawtooth-poet-validator-registry-tp.service
$ sudo systemctl start sawtooth-poet-engine.service
$ sudo systemctl start sawtooth-validator.service
$ sudo systemctl start sawtooth-settings-tp.service
$ sudo systemctl start sawtooth-intkey-tp-python.service
$ sudo systemctl start sawtooth-identity-tp.service

You can follow the logs by running:

$ sudo journalctl -f \
-u sawtooth-validator \
-u sawtooth-settings-tp \
-u sawtooth-poet-validator-registry-tp \
-u sawtooth-poet-engine \
-u sawtooth-rest-api \
-u sawtooth-intkey-tp-python \
-u sawtooth-identity-tp

Additional logging output can be found in /var/log/sawtooth/. For more information, see Log Configuration File.

To verify that the services are running:

$ sudo systemctl status sawtooth-rest-api.service
$ sudo systemctl status sawtooth-poet-validator-registry-tp.service
$ sudo systemctl status sawtooth-poet-engine.service
$ sudo systemctl status sawtooth-validator.service
$ sudo systemctl status sawtooth-settings-tp.service
$ sudo systemctl status sawtooth-intkey-tp-python.service
$ sudo systemctl status sawtooth-identity-tp.service

Stop or Restart the Sawtooth Services

If you need to stop or restart the Sawtooth services for any reason, use the following commands:

Stop Sawtooth services:

$ sudo systemctl stop sawtooth-rest-api.service
$ sudo systemctl stop sawtooth-poet-validator-registry-tp.service
$ sudo systemctl stop sawtooth-poet-engine.service
$ sudo systemctl stop sawtooth-validator.service
$ sudo systemctl stop sawtooth-settings-tp.service
$ sudo systemctl stop sawtooth-intkey-tp-python.service
$ sudo systemctl stop sawtooth-identity-tp.service

Restart Sawtooth services:

$ sudo systemctl restart sawtooth-rest-api.service
$ sudo systemctl restart sawtooth-poet-validator-registry-tp.service
$ sudo systemctl restart sawtooth-poet-engine.service
$ sudo systemctl restart sawtooth-validator.service
$ sudo systemctl restart sawtooth-settings-tp.service
$ sudo systemctl restart sawtooth-intkey-tp-python.service
$ sudo systemctl restart sawtooth-identity-tp.service