7

I wish to create a go-binding to my smart contract which was mined on a private blockchain.

I've looked at the Native Dapps : Go binding to Ethereum contracts tutorial (located here : https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts), which is a tutorial for auto-generating go functions which will call/interact on/with the smart contract.

From what I understand, this allows you to call any function of the smart contract for which you generate code, on your blockchain, without having to encode your method signature and parameters, all this over an IPC connection.

I guess the other solution would be to encode your method signature and parameters and send transactions manually?

  • What I want

I want my private blockchain to be the backend of the binding, so that calling an auto-generated method will act on my actual blockchain.

  • What I first did

According to the tutorial written by the official go-ethereum project (link above) this is done by creating an IPC client, and then using that IPC Client to generate the backend of the binding.

  • The problem

This method involved two functions of two packages from the go-ethereum project, which are NewIPCClient() from the rpc package and NewRPCBackend() from the backends package. The first was changed to DialIPC(), and was the subject of an issue here about 4 months ago.

I'm successfully using rpc.DialIPC() but the backends.NewRPCBackend() method was suppressed and I can't seem to work around it.

My code looks like that :

import (
"log"
"strings"

"golang.org/x/net/context"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"

"github.com/gorilla/mux"
)

ctx := context.TODO();

//Create an IPC based RPC connection
conn, errConn := rpc.DialIPC(ctx, "/home/geth/datadir/geth.ipc")
if errConn != nil {
    log.Fatalf("Failed to connect to the node : %v", errConn)
}

//Creates the transactor : account that will be used to send transaction on the blockchain. Specific of the node the binary will be generated on.
auth, errAuth := bind.NewTransactor(strings.NewReader(key), "test")
if errAuth != nil {
    log.Fatalf("Failed to create new transactor : %v", errAuth)
}

//Establish the binding. Takes the adress of the contract and the blockchain in parameter
service, errServ := NewDataPublishingService(common.HexToAddress("0x5217502dac0c987d65a3325a4ea95bedc3c2a6aa"), backends.NewRPCBackend())
if errServ != nil {
    log.Fatalf("Failed to instantiate a Token contract : %v", errServ)
}

//Open a session in the binding. This session will be used to send transactions on the blockchain or launch calls.
session := &DataPublishingServiceSession{
    Contract : service,
    CallOpts : bind.CallOpts{},
    TransactOpts : bind.TransactOpts{
        From : auth.From,
        Signer : auth.Signer,
    },
}

The error I'm getting

./server.go:91: undefined: backends.NewRPCBackend

This is, as I said, because the function was suppressed


To sum up, I checked the contents of the backends package as it is today. All it contains is a NewSimulatedBackend() method which creates a blockchain from scratch. I was thinking of a solution which consisted of recoding the type SimulatedBackend to create a link to my own blockchain, but I gave it up because this will instead recreate another instance of my blockchain (at least from what I understand).

I didn't find documentation on this issue (not on github nor here), so I would love and look forward to any kind of input so how this would be done.

1

You need to use ethClient now

I am binding an object called NewMaths...

import "github.com/ethereum/go-ethereum/ethclient"
...

func getClient() (client *ethclient.Client, err error) {
    endPoint := "/Users/daveappleton/Library/Ethereum/geth.ipc"
    client, err = ethclient.Dial(endPoint)
    return
}
...
client, err := getClient()
if err != nil {
    fmt.Println(err)
    return
}
nnm, err = NewNewMaths(common.HexToAddress(address), client) 
if err != nil {
    log.Fatalf("Failed to instantiate the NewMaths contract: %v", err)
}

ownerTx, err = bind.NewTransactor(strings.NewReader(mon_key), ",password")
if err != nil {
    log.Fatalf("Failed to create authorized transactor: %v", err)
}

Keeping it brief as you look as if you have most of it. Will answer more if you need it.

0

I'll walk you through how to compile a smart contract to a Go package, load the smart contract in your Go app, and then send a transaction to the smart contract from Go.

First install abigen and then compile the smart contract to a Go package (we'll use a sample contract called Store.sol)

go get -u github.com/ethereum/go-ethereum
cd $GOPATH/src/github.com/ethereum/go-ethereum/
make
make devtools

solc --abi Store.sol | awk '/JSON ABI/{x=1;next}x' > Store.abi
solc --bin Store.sol | awk '/Binary:/{x=1;next}x' > Store.bin
abigen --bin=Store.bin --abi=Store.abi --pkg=store --out=Store.go

Store.abi

pragma solidity ^0.4.24;

contract Store {
  event ItemSet(bytes32 key, bytes32 value);

  string public version;
  mapping (bytes32 => bytes32) public items;

  constructor(string _version) public {
    version = _version;
  }

  function setItem(bytes32 key, bytes32 value) external {
    items[key] = value;
    emit ItemSet(key, value);
  }
}

Now we'll import our contract, load our private key, and invoke the smart contract method which writes to the blockchain.

package main

import (
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"

    store "./contracts" // for demo
)

func main() {
    client, err := ethclient.Dial("https://rinkeby.infura.io")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
    if !ok {
        log.Fatal("error casting public key to ECDSA")
    }

    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    auth := bind.NewKeyedTransactor(privateKey)
    auth.Nonce = big.NewInt(int64(nonce))
    auth.Value = big.NewInt(0)     // in wei
    auth.GasLimit = uint64(300000) // in units
    auth.GasPrice = gasPrice

    address := common.HexToAddress("0x147B8eb97fD247D06C4006D269c90C1908Fb5D54")
    instance, err := store.NewStore(address, client)
    if err != nil {
        log.Fatal(err)
    }

    key := [32]byte{}
    value := [32]byte{}
    copy(key[:], []byte("foo"))
    copy(value[:], []byte("bar"))

    tx, err := instance.SetItem(auth, key, value)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("tx sent: %s", tx.Hash().Hex()) // tx sent: 0x8d490e535678e9a24360e955d75b27ad307bdfb97a1dca51d0f3035dcee3e870

    result, err := instance.Items(nil, key)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(string(result[:])) // "bar"
}

For more examples, check out the Ethereum Development with Go book.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.