Introducing Perigord: Golang Tools for Ethereum DApp Development

Truffle, but with standalone Go binaries instead of Node.js

PolySwarm
Decentralize.Today
5 min readSep 12, 2017

--

Hey there! We’re building PolySwarm — the first decentralized threat intelligence market. PolySwarm is made possible by blockchain-based smart contracts that enable new forms of market design. Read more about why we’re building PolySwarm, or take a deep dive into the full details in our white paper. PolySwarm is fortunate to be advised by world-renowned information security experts.

Perigord

Figure A: The least-gross image of a Perigord truffle on Shutterstock

Do you like what Truffle has to offer but don’t particularly enjoy a Node.js development environment? Us too! There’s literally dozens of us!

Today we’re introducing Perigord: a Truffle-like framework for developing Ethereum DApps in Go that should make these instructions a little less painful.

The impatient can grab the source code here.

Pull requests welcome!

Exploring Perigord

Follow Perigord’s install instructions and make sure you have a working perigord install:

$ perigord
A golang development environment for Ethereum
Usage:
perigord [command]
...

Start a New Perigord DApp

This should be familiar to anyone who has used Truffle.

$ perigord init perigordexplore
$ pushd $GOPATH/src/perigordexplore

perigord init started a DApp project for us:

$ tree .
.
├── contracts
│ ├── Foo.sol
│ └── Migrations.sol
├── generate.go
├── main.go
├── migrations
│ ├── 1_Migrations.go
│ └── 2_Foo.go
├── perigord.yaml
├── stub
│ ├── main.go
│ └── README.md
├── stub_test.go
└── tests
└── Foo.go

A sample contract (contract/Foo.sol) is provided. This contract does nothing other than return 1337. This behavior is tested in tests/Foo.go.

See Truffle’s documentation for discussion on the migrations folder and Migrations.sol.

The bindings directory is empty until we perigord build our Solidity contracts and use their ABI to produce Go bindings. Let’s do that now.

Build Go Bindings

perigord uses solcto compile Solidity contracts into EVM bytecode and ABI specifications and then usesabigento generate Go bindings based on these ABIs.

Let’s build Foo.sol's Go bindings:

$ perigord build

This caused Perigord to call out to solc and compile our contracts (Foo.sol & Migrations.sol) into Ethereum EVM bytecode and an ABI specification (in JSON):

$ tree build/
build/
├── Foo.abi
├── Foo.bin
├── Migrations.abi
└── Migrations.bin

Next, Perigord fed the ABI into abigen to produce .go files that define the Go bindings for our Solidity contracts.

$ tree bindings/
bindings/
├── Foo.go
└── Migrations.go

These files define all the structs and functions from the Solidity contracts in a manner that can be easily imported into a Golang DApp. Neat!

Enough fun, let’s get down to business.

Build a Perigord DApp that Interfaces with a Token

In this section, we will build borrow the official Ethereum TokenERC20 contract, build bindings for it, and call into the contract using a standalone Golang DApp. We’ll do of all this with the help of Perigord.

Create a New DApp

$ perigord init tokendapp
$ pushd $GOPATH/src/tokendapp

Add the TokenERC20 Contract to our DApp

$ perigord add contract TokenERC20

Copy the contents of the TokenERC20 contract from the official Ethereum documentation into contracts/TokenERC20.sol. Make sure to copy from THE CODE section, not MINIMUM VIABLE TOKEN section.

Build TokenERC20 Bindings

Invoke perigord to build Go bindings for the TokenERC20 contract:

$ perigord build

Add a Migration

Let’s tell Perigord how to deploy the TokenERC20 contract:

$ perigord add migration TokenERC20

This will add a new file at migrations/3_TokenERC20.go. We need to make a few simple modifications to this file.

Configure the Migration to exercise TokenERC20’s Constructor

The TokenERC20 contract has a constructor that takes several arguments, so we need to alter the migration such that it provides the correct parameters to the DeployTokenERC20 function.

Recall the TokenERC20 constructor:

/* Initializes contract with initial supply tokens to the creator of the contract */
function TokenERC20(
uint256 initialSupply,
string tokenName,
string tokenSymbol
) {
...
}

Our token will have an initial supply of 1337. We’re going to call our Token "FOO" and its symbol will be "BAR".

In the Deploy function of the generated TokenERC20Deployer struct, change the first line from:

address, transaction, contract, err := bindings.DeployTokenERC20(auth, backend)

to:

address, transaction, contract, err := bindings.DeployTokenERC20(auth, backend, big.NewInt(1337), "FOO", "BAR")

Pretty simple, but we need to do one more thing: add math/big to our list of imports. Once you’ve made these two changes, save 3_TokenERC20.go.

Write Tests for Our Contract

It’s always good practice to verify the functionality of your contracts.

Add a new test with:

$ perigord add test TokenERC20

This will create a new file in tests/TokenERC20.go.

Let’s test that the name of our token is properly set. Add the following test function to the file:

func (s *TokenERC20Suite) TestName(c *C) {
session := contract.Session("TokenERC20")
c.Assert(session, NotNil)
token_session, ok := session.(*bindings.TokenERC20Session)
c.Assert(ok, Equals, true)
c.Assert(token_session, NotNil)
ret, _ := token_session.Name()
c.Assert(ret, Equals, "FOO")
}

This test function will look up our deployed contract and call its Name() function to ensure that the name we set in our migration’s DeployTokenERC20 function is correctly set.

Before each test is run, each contract is re-deployed onto our go-ethereum
private blockchain via the migration we configured in the previous step.

Let’s set up our private testnet. We include a script to set up a simple testnet in the scripts directory in the Perigord repository. Run it in a separate terminal to start up our test network.

$ $GOPATH/src/github.com/polyswarm/perigord/scripts/launch_geth_testnet.sh

Now we can test our contract(s) with:

$ perigord test

Interacting with Our Contract

Our DApp code will go in main.go. Let’s add some code that interacts with our new "FOO" token:

package mainimport (
"context"
"fmt"
"log"
"github.com/polyswarm/perigord/contract"
"github.com/polyswarm/perigord/migration"
"github.com/polyswarm/perigord/network"
"tokendapp/bindings"
_ "tokendapp/migrations"
)
func main() {
network.InitNetworks()
nw, err := network.Dial("dev")
if err != nil {
log.Fatalln("could not connect to dev network: ", err)
}
// Run our migrations
if err := migration.RunMigrations(context.Background(), nw); err != nil {
log.Fatalln("error running migrations: ", err)
}
session, ok := contract.Session("TokenERC20").(*bindings.TokenERC20Session)
if !ok {
log.Fatalln("error retrieving session")
}
name, _ := session.Name()
totalSupply, _ := session.TotalSupply()
symbol, _ := session.Symbol()
fmt.Printf("Let's spend some %s\n", name)
fmt.Printf("There are %d %s in total\n", totalSupply, symbol)
}

If all went according to plan, we can now run our native DApp and see our results:

$ go build main.go 
$ ./main
Running migration 1
Running migration 2
Running migration 3
Let's spend some FOO
There are 1337 BAR in total

Hooray! Our standalone, token-interacting, Golang-awesome binary works!

Cheat ;)

Feel free to check out the complete example here.

Connect with PolySwarm

That’s all for now; please stay in touch! Join the conversation on Telegram, connect with us on Twitter, send us an email or sign up for notifications concerning PolySwarm’s upcoming Nectar (NCT) token sale and open source release of PolySwarm’s contract code.

~Paul Makowski, PolySwarm CTO

--

--

PolySwarm
Decentralize.Today

The world’s first decentralized threat intelligence market. Learn more @ https://polyswarm.io