Go-Ethereum

如何通過 IPC 將 Go 自動生成的程式碼綁定到智能合約?

  • April 12, 2020

我希望為我的智能合約創建一個綁定,該合約是在私有區塊鏈上探勘的。

我看過 Native Dapps:Go binding to Ethereum contract 教程(位於:https ://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts ) ,這是一個自動生成 go 函式的教程,它將呼叫/互動智能合約。

據我了解,這允許您在區塊鏈上呼叫您為其生成程式碼的智能合約的任何功能,而無需對您的方法簽名和參數進行編碼,所有這些都通過 IPC 連接進行。

我猜另一種解決方案是對您的方法簽名和參數進行編碼並手動發送交易?

  • 我想要的是

我希望我的私有區塊鏈成為綁定的後端,以便呼叫自動生成的方法將作用於我的實際區塊鏈。

  • 我第一次做的

根據官方 go-ethereum 項目(上面的連結)編寫的教程,這是通過創建 IPC 客戶端,然後使用該 IPC 客戶端生成綁定的後端來完成的。

  • 問題

該方法涉及go-ethereum項目中兩個包的兩個功能,分別是NewIPCClient()來自rpc包和NewRPCBackend()來自backends包。第一個已更改為DialIPC(),並且是大約 4 個月前這裡的一個問題的主題。

我正在成功使用rpc.DialIPC(),但該backends.NewRPCBackend() 方法被抑制,我似乎無法解決它。

我的程式碼如下所示:

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,
   },
}

我得到的錯誤

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

正如我所說,這是因為該功能被抑制


總而言之,我檢查了backends包裹的內容,就像今天一樣。它只包含一個 NewSimulatedBackend() 方法,該方法從頭開始創建區塊鏈。我正在考慮一個解決方案,其中包括重新編碼 SimulatedBackend 類型以創建指向我自己的區塊鏈的連結,但我放棄了它,因為這將重新創建我的區塊鏈的另一個實例(至少據我所知)。

我沒有找到關於這個問題的文件(不是在 github 上也不是在這裡),所以我很樂意並期待任何類型的輸入,以便如何完成。

您現在需要使用 ethClient

我正在綁定一個名為 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)
}

保持簡短,因為您看起來好像擁有大部分內容。如果您需要它會回答更多。

我將向您介紹如何將智能合約編譯為 Go 包,在您的 Go 應用程序中載入智能合約,然後從 Go 向智能合約發送交易。

首先安裝abigen然後將智能合約編譯成一個 Go 包(我們將使用一個名為 的範例合約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);
 }
}

現在我們將導入我們的合約,載入我們的私鑰,並呼叫寫入區塊鏈的智能合約方法。

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"
}

有關更多範例,請查看使用 Go 進行乙太坊開發一書

引用自:https://ethereum.stackexchange.com/questions/10339