Contract Development Sample

tags: “go-sdk” “contract development”


Non-state secret sample

This development example uses the standard single-group four-node blockchain network structure, please refer to: Installation

When you use the SDK to develop a project, you need to use the ‘abigen’ tool of go-sdk to convert the Solidity smart contract into ‘Go’ file code to automatically generate the interface for event listening in the contract。The whole mainly contains six processes:

  • Prepare smart contracts that need to be compiled

  • Configure the appropriate version of the solc compiler -build the contract compilation tool abigen for go-sdk

  • compile to generate go file

  • prepare the certificate required to establish an ssl connection

  • Use the generated go file for contract deployment, invocation

HelloWorld Sample

Prepare the HelloWorld.sol contract file

# The instruction is executed in the go-sdk directory
mkdir helloworld && cd helloworld

Create a new helloworld folder in the go-sdk home directory and create the HelloWorld.sol contract in this folder。The contract provides two interfaces, get()and set()to get / set the contract variable name。The contract is as follows

// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.6.10 <0.8.20;

contract HelloWorld {
    string value;
    event setValue(string v, address indexed from, address indexed to, int256 value);
    int public version;

    constructor(string memory initValue) {
        value = initValue;
        version = 0;
    }

    function get() public view returns (string memory) {
        return value;
    }

    function set(string calldata v) public returns (string memory) {
        string memory old = value;
        value = v;
        version = version + 1;
        emit setValue(v, tx.origin, msg.sender, version);
        return old;
    }
}

Installing the solc compiler

This compiler is used to compile sol contract files into abi and bin files. Currently, the ‘solc’ compiler provided by FISCO BCOS is 0.8.11 / 0.6.10。

# The instruction is executed in the helloworld folder
bash ../tools/download_solc.sh -v 0.8.11

Build code generation tool abigen for go-sdk

This tool is used to convert abi and bin files to go files

# This instruction is executed in the helloworld folder to compile and generate the abigen tool
go build ../cmd/abigen

compile to generate go file

First, use solc to compile the contract file HelloWorld.sol to generate abi and bin files

# The instruction is executed in the helloworld folder
./solc-0.8.11 --bin --abi -o ./ ./HelloWorld.sol

HelloWorld.bin and HelloWorld.abi are generated under the helloworld directory。Use the abigen tool to convert HelloWorld.bin and HelloWorld.abi into HelloWorld.go:

# The instruction is executed in the helloworld folder
./abigen --bin ./HelloWorld.bin --abi ./HelloWorld.abi --pkg helloworld --type HelloWorld --out ./HelloWorld.go

Finally the following six files exist under the helloworld folder:

HelloWorld.abi、HelloWorld.bin、HelloWorld.go、HelloWorld.sol、solc-0.8.11、abigen

prepare the certificate required to establish an ssl connection

When you use the build _ chain.sh script to build a blockchain, the sdk certificate, private key, and ca certificate are generated in the. / nodes / 127.0.0.1 / sdk folder. You need to copy these three files to the location specified by the parameter, for example, in the following。

Deployment contract

Create the cmd folder in the helloworld folder and create the main.go file in the cmd folder. The content of main.go is as follows

package main

import (
    "context"
    "encoding/hex"
    "fmt"
    "log"

    "github.com/FISCO-BCOS/go-sdk/client"
    "github.com/FISCO-BCOS/go-sdk/core/types"
    "github.com/FISCO-BCOS/go-sdk/hello"
)

func main() {
    privateKey, _ := hex.DecodeString("145e247e170ba3afd6ae97e88f00dbc976c2345d511b0f6713355d19d8b80b58")
    config := &client.Config{IsSMCrypto: false, GroupID: "group0",
        PrivateKey: privateKey, Host: "127.0.0.1", Port: 20200, TLSCaFile: "./ca.crt", TLSKeyFile: "./sdk.key", TLSCertFile: "./sdk.crt"}
    client, err := client.DialContext(context.Background(), config)
    if err != nil {
        log.Fatal(err)
    }
    input := "HelloWorld deployment 1.0"
    fmt.Println("=================DeployHelloWorld===============")
    address, receipt, instance, err := helloworld.DeployHelloWorld(client.GetTransactOpts(), client, input)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("contract address: ", address.Hex()) // the address should be saved, will use in next example
    fmt.Println("transaction hash: ", receipt.TransactionHash)

    // load the contract
    // contractAddress := common.HexToAddress("contract address in hex String")
    // instance, err := helloworld.NewStore(contractAddress, client)
    // if err != nil {
    //     log.Fatal(err)
    // }

    fmt.Println("================================")
    helloSession := &helloworld.HelloWorldSession{Contract: instance, CallOpts: *client.GetCallOpts(), TransactOpts: *client.GetTransactOpts()}

    version, err := helloSession.Version()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("version :", version) // "HelloWorld deployment 1.0"

    ret, err := helloSession.Get() / / Call the contract Get method
    if err != nil {
        fmt.Printf("helloworld.Get() failed: %v", err)
        return
    }
    done := make(chan bool)
    / / Listen to the contract set event
    _, err = helloSession.WatchAllSetValue(nil, func(ret int, logs []types.Log) {
        fmt.Printf("WatchAllSetValue receive statud: %d, logs: %v\n", ret, logs)
        setValue, err := helloSession.ParseSetValue(logs[0])
        if err != nil {
            fmt.Printf("helloworld.WatchAllSetValue() failed: %v", err)
            panic("WatchAllSetValue helloworld.WatchAllSetValue() failed")
        }
        fmt.Printf("receive setValue: %+v\n", *setValue)
        done <- true
    })
    if err != nil {
        fmt.Printf("helloworld.WatchAllSetValue() failed: %v", err)
        return
    }
    fmt.Printf("Get: %s\n", ret)
    fmt.Println("================================")

    oldValue, _, receipt, err := helloSession.Set("hello fisco")
    fmt.Println("old value is: ", oldValue)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("transaction hash of receipt: %s\n", receipt.GetTransactionHash())

    ret, err = helloSession.Get()
    if err != nil {
        fmt.Printf("helloworld.Get() failed: %v", err)
        return
    }
    fmt.Printf("Get: %s\n", ret)
    <-done
}

Build and execute。

# The instruction is executed in the go-sdk directory
go run helloworld/cmd/main.go

Note

  • The contract address needs to be saved manually, which is used when calling the contract interface

-If the dynamic library of c-sdk is placed in a custom directory, you need ‘go run-ldflags =”-r Path to custom directory”`

Asynchronous deployment, invoking HelloWorld contract

package main

import (
    "fmt"
    "log"

    "github.com/FISCO-BCOS/go-sdk/client"
    "github.com/FISCO-BCOS/go-sdk/conf"
    "github.com/FISCO-BCOS/go-sdk/helloworld"
    "github.com/ethereum/go-ethereum/common"
    "github.com/FISCO-BCOS/go-sdk/core/types"
)

func main() {
    configs, err := conf.ParseConfigFile("config.toml")
    if err != nil {
        log.Fatalf("ParseConfigFile failed, err: %v", err)
    }
    client, err := client.Dial(&configs[0])
    if err != nil {
        fmt.Printf("Dial Client failed, err:%v", err)
        return
    }
    var contractAddress common.Address
    var channel = make(chan int, 0)
    tx, err := helloworld.AsyncDeployHelloWorld(client.GetTransactOpts(), func(receipt *types.Receipt, err error) {
        if err != nil {
            fmt.Printf("%v\n", err)
            return
        }
        fmt.Println("contract address: ", receipt.ContractAddress.Hex()) // the address should be saved
        contractAddress = receipt.ContractAddress
        channel <- 0
    }, client)
    fmt.Println("transaction hash: ", tx.Hash().Hex())
    <-channel
    instance, err := helloworld.NewHelloWorld(contractAddress, client)
    if err != nil {
        log.Fatal(err)
    }
    if err != nil {
        fmt.Printf("Deploy failed, err:%v", err)
        return
    }
    hello := &helloworld.HelloWorldSession{Contract: instance, CallOpts: *client.GetCallOpts(), TransactOpts: *client.GetTransactOpts()}
    ret, err := helloworld.Get()
    if err != nil {
        fmt.Printf("helloworld.Get() failed: %v", err)
        return
    }
    fmt.Printf("Get: %s\n", ret)
    tx, err = helloworld.AsyncSet(func(receipt *types.Receipt, err error) {
        if err != nil {
            fmt.Printf("helloworld.AsyncSet failed: %v\n", err)
            return
        }
        if receipt.Status != 0 {
            fmt.Printf("helloworld.AsyncSet failed: %v\n", receipt.GetErrorMessage())
        }
        channel <- 0
    }, "fisco")
    <-channel
    ret, err = helloworld.Get()
    if err != nil {
        fmt.Printf("helloworld.Get() failed: %v", err)
        return
    }
    fmt.Printf("Get: %s\n", ret)
}

State Secret Sample

The development process for using the state secret feature is roughly the same as for non-state secrets, with the following differences

  • The FISCO BCOS blockchain network needs to turn on the national secret feature

  • You need to replace the non-state secret private key with the state secret private key

  • TLS certificate and private key need to be prepared

  • need to add when installing solc compiler**-g** option, replace with the State Secret version -When using the abigen tool to convert bin and abi to go files, you need to add parameters**–smcrypto=true**

HelloWorld Sample

Prepare the HelloWorld.sol contract file

Create a new helloworld folder in the go-sdk home directory and create the HelloWorld.sol contract in this folder。The contract provides two interfaces, get()and set()to get / set the contract variable name。The contract is as follows

pragma solidity >=0.6.10 <0.8.20;

contract HelloWorld {
    string name;

    constructor() public {
        name = "Hello, World!";
    }

    function get() public view returns (string memory) {
        return name;
    }

    function set(string memory n) public {
        name = n;
    }
}

install the state secret solc compiler

The compiler is used to compile the sol contract file into abi and bin files

# The instruction is executed in the helloworld folder
bash ../tools/download_solc.sh -v 0.8.11 -g

Build code generation tool abigen for go-sdk

This tool is used to convert abi and bin files to go files

# This instruction is executed in the helloworld folder to compile and generate the abigen tool
go build ../cmd/abigen

compile to generate go file

First, use solc to compile the contract file HelloWorld.sol to generate abi and bin files

# The instruction is executed in the helloworld folder
./solc-0.8.11-gm --bin --abi -o ./ ./HelloWorld.sol

HelloWorld.bin and HelloWorld.abi are generated under the helloworld directory。Use the abigen tool to convert HelloWorld.bin and HelloWorld.abi into HelloWorld.go:

# The instruction is executed in the helloworld folder
./abigen --bin ./HelloWorld.bin --abi ./HelloWorld.abi --pkg helloworld --type HelloWorld --out ./HelloWorld.go --smcrypto=true

-The next steps are the same as those of non-state secrets and do not take up extra space