Tutorial

Introduction

In this tutorial, you will learn how to quickly access the internet when running code on the Golem network. You will get familiar with the concept of Golem manifest, outbound, and some security policies that are in place to protect the providers from malicious code.

Prerequisites

  • Yagna service installed and running with the try_golem app-key configured (see instructions).

Overview

In this tutorial, you will create a requestor script that will download a code from the ipfs.io site to a provider. To achieve the goal you will use the outbound feature.

The ipfs.io URL was selected as a target URL for the example, as it is included in the default provider’s whitelist. You can check here for other entries. Please note that a provider can choose to add, remove, or completely wipe the whitelist.

As the requestor needs to list all URLs they want to access in a manifest file, you need to create one and provide it when creating a new TaskExecutor. There is a CLI tool that we will use to create this manifest.

You can read more about outbound feature here.

Let’s code.

Initialize the project

First, create a project directory and navigate there:

mkdir outbound-example
cd outbound-example

Then initialise the project and install JS SDK.

npm init
npm install @golem-sdk/task-executor

Next, install Golem SDK CLI - a companion tool that will facilitate manifest creation.

npm install -g @golem-sdk/cli

Manifest creation

Once you have the project, open a terminal and run:

golem-sdk manifest create golem/examples-outbound:latest

This will create a basic manifest.json file. You will use it to inform the provider what GVMI image we will be using. The manifest contains also your application version, application name, and description, all read from your package.json file (you can edit this information if you want).

Adding outbound configuration

The next step is to configure our manifest, so you can access a public URL. The CLI also has a handy command that will take care of that for you:

golem-sdk manifest net add-outbound https://ipfs.io

This has added https://ipfs.io as the URL you want to access from the provider node. The command can be run multiple times to add more URLs or you can pass them all at once.

Now our manifest is ready, you can start coding the application.

Requestor script

The application will be very simple. It will use curl to download an example image from IPFS to demonstrate how to enable and access the internet from the Golem SDK.

Let’s start with a simple boilerplate, copy the following code to a javascript file:

import { TaskExecutor } from '@golem-sdk/task-executor'
import { readFile } from 'fs/promises'
;(async function main() {
  const executor = await TaskExecutor.create({})

  try {
    // Your code goes here
  } catch (err) {
    console.error('The task failed due to', err)
  } finally {
    await executor.shutdown()
  }
})()

The snippet above is using async/await to synchronize asynchronous calls, for simplicity and compatibility, we wrap all the code into an asynchronous main function. The next thing to do is to correctly initialize the `TaskExecutor``. For this purpose, let's use the manifest file we’ve just created.

At the top of the main function replace the executor initialization with the following:

// Load the manifest file.
const manifest = await readFile(`./manifest.json`)

// Create and configure a TaskExecutor instance.
const executor = await TaskExecutor.create({
  capabilities: ['inet', 'manifest-support'],
  yagnaOptions: { apiKey: 'try_golem' },
  manifest: manifest.toString('base64'),
})

This is the most important part. First, it is specifying additional requirements to the demand:

  • 'inet' - indicates the script requires outbound service
  • 'manifest-support' - informs, that it will use manifest to specify a demand.

Instead of providing an image tag or hash, it uses a manifest file that describes what will be run on providers.

Please note the loaded manifest is encoded to base64.

yagnaOptions: { apiKey: 'try_golem' } - defined the api key, to get access to the Yagna service. This particular key is available if you start the yagna according to the procedure provided in the installation example, you can also configure your unique keys. See here for instructions.

In this example, you will simply fetch an example file from IPFS using the curl command, available in our GVMI image. So first let’s save the URL near the top of the file (just after the imports):

import { TaskExecutor } from '@golem-sdk/task-executor'
import { readFile } from 'fs/promises'

const url =
  'https://ipfs.io/ipfs/bafybeihkoviema7g3gxyt6la7vd5ho32ictqbilu3wnlo3rs7ewhnp7lly'

And finally, let’s execute some code on the provider. You will run a single task on the provider, using the TaskExecutor.run() function. To make this work, put the following code in the try/catch block:

await executor.run(async (ctx) => {
  const result = await ctx.run(`curl ${url} -o /golem/work/example.jpg`)

  console.log((await ctx.run('ls -l')).stdout)
  if (result.result === 'Ok') {
    console.log('File downloaded!')
  } else {
    console.error('Failed to download the file!', result.stderr)
  }
})

And that’s it! Now, make sure your yagna service is running and you can start this script.

This is how the entire file should look like:

import { TaskExecutor } from '@golem-sdk/task-executor'
import { readFile } from 'fs/promises'

const url =
  'https://ipfs.io/ipfs/bafybeihkoviema7g3gxyt6la7vd5ho32ictqbilu3wnlo3rs7ewhnp7lly'

;(async function main() {
  // Load the manifest.
  const manifest = await readFile(`./manifest.json`)

  // Create and configure a TaskExecutor instance.
  const executor = await TaskExecutor.create({
    capabilities: ['inet', 'manifest-support'],
    yagnaOptions: { apiKey: 'try_golem' },
    manifest: manifest.toString('base64'),
  })

  try {
    await executor.run(async (ctx) => {
      const result = await ctx.run(`curl ${url} -o /golem/work/example.jpg`)

      console.log((await ctx.run('ls -l')).stdout)
      if (result.result === 'Ok') {
        console.log('File downloaded!')
      } else {
        console.error('Failed to download the file!', result.stderr)
      }
    })
  } catch (err) {
    console.error('The task failed due to', err)
  } finally {
    await executor.shutdown()
  }
})()

You can run it now. In the output, you should see “File downloaded!” between log lines and the output of the ls -l command showing th size of the fole downloaded . That means the code works.

Next steps
See also