主页 > imtoken安卓版版本下载 > 使用 Go 与以太坊智能合约交互

使用 Go 与以太坊智能合约交互

imtoken安卓版版本下载 2023-07-06 05:19:21

尽管最近遇到了麻烦,以太坊仍然是区块链领域智能合约的最大参与者,而且这种情况似乎不会很快改变。

在我看来,该技术本身具有巨大的潜力,从学术角度来看也很有趣,但正如上面提到的问题和之前的许多问题都是关于区块链技术、智能合约,尤其是与 Solidity 和以太坊生态系统还不成熟和还没有为黄金时段和生产用例做好准备。

然而,这是学习和理解该技术的好时机,并在它达到严肃应用程序可接受的成熟度水平时为它做好准备。

在我之前关于 Solidity 的帖子中,我创建了一个带有简单的赢家通吃众筹合约的小型应用程序。 在本文中,我们将使用 contract.sol 来查看是否可以使用 Go 对其进行部署和交互。

为什么去? 好问题,go 语言很棒,使用最广泛的以太坊客户端是用 go 编写的,这意味着有一个很好的使用生态系统,它已经变成了代码生成和可再现性等强大功能用于与智能交互的助手共享库合同。

在这个例子中,我们不会使用真实的区块链作为部署目标,而是使用 go-ethereum 提供的 SimulatedBackend,这样我们就可以安全地测试和实验,而无需花费任何钱。

智能合约本身非常简单:我不会详细介绍它的作用或工作原理,因为已经介绍过了。 可以说合约部署有3个参数:

然后,在第一阶段,项目可以使用名称和至少包含最低交易费用的 URL 提交。 在第二阶段,可以通过向合约中的地址发送以太币来支持该项目。

但是,在本文中,我们将重点关注:

我们将使用 Go 和 70 行代码来完成这一切。 开始吧!

代码示例

为了能够跟踪,您需要一些东西。 首先,您需要 solc Solidity 编译器。

然后,只需抓住 go-ethereum 并构建它:

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

好吧,使用 solc 和 geth devtools,我们可以从生成包含智能合约的 contract.sol 文件的 Go 版本开始:

abigen --sol=Contract.sol --pkg=main --out=contract.go

生成的代码可以在这里看到。

如您所见,我们有部署和实例化合约的方法,以及所有公共合约方法到 Go 的映射。

下一步是将合约部署到模拟后端。

为此,需要进行一些设置。 如上所述,为简单起见,我们将使用 SimulatedBackend 作为我们的目标区块链,但在这篇文章的末尾将有一个简短的部分介绍如何使用测试网甚至真实的以太坊区块链来做到这一点。

有了一些对 go-ethereum 的依赖,我们就可以开始设置了:

import(
    "fmt"
    "log"
    "math/big"
    "time"
    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
    "github.com/ethereum/go-ethereum/core"
    "github.com/ethereum/go-ethereum/crypto"
)
func main() {
    key, _ := crypto.GenerateKey()
    auth := bind.NewKeyedTransactor(key)
    alloc := make(core.GenesisAlloc)
    alloc[auth.From] = core.GenesisAccount{Balance: big.NewInt(133700000)}
    sim := backends.NewSimulatedBackend(alloc)

我们只是创建一个密钥,用一堆以太币创建一个 Genesis 帐户并启动模拟后端,它返回一个 bind.ContractBackend。

现在我们可以使用生成的 DeployWinnerTakesAll 方法部署合约:

addr, _, contract, err := DeployWinnerTakesAll(auth, sim, big.NewInt(10), big.NewInt(time.Now().Add(2*time.Minute).Unix()), big.NewInt(time.Now().Add(5*time.Minute).Unix()))
if err != nil {
    log.Fatalf("could not deploy contract: %v", err)
}

我们使用 bigInt 传递一个 auth 对象,它代表我们的身份、后端 sim 和最低入场费、项目截止日期和活动截止日期的值。 此方法返回将部署合约的地址以及合约的句柄和错误。 还有一个返回的交易对象,这里不做处理。

现在合约已部署,我们应该能够与其进行交互。 例如,我们可以检查我们发送的截止日期是否在合约中设置正确:

deadlineCampaign, _ := contract.DeadlineCampaign(nil)
fmt.Printf("Pre-mining Campaign Deadline: %s\n", deadlineCampaign)

但如果我们这样做,我们将在截止日期前回来。 也就是说Go以太坊开发详解,因为我们的合约还没有被开采。 如果我们使用真实网络作为我们的后端,我们将不得不等到这发生,但是使用我们的模拟后端,我们可以简单地这样做:

fmt.Println("Mining...")
sim.Commit()
postDeadlineCampaign, _ := contract.DeadlineCampaign(nil)
fmt.Printf("Post-mining Campaign Deadline: %s\n", time.Unix(postDeadlineCampaign.Int64(), 0))

我们回到部署期间设置的日期:

Post-mining Campaign Deadline: 2017-07-23 20:37:22 +0200 CEST

行。 因此,我们可以读取合约暴露的数据。 现在我们想和它互动。 在这种情况下,最简单的做法是我们通过发送带有名称和项目 url 的交易来提议一个新项目,至少以最低费用作为价值:

numOfProjects, _ := contract.NumberOfProjects(nil)
fmt.Printf("Number of Projects before: %d\n", numOfProjects)
fmt.Println("Adding new project...")
contract.SubmitProject(&bind.TransactOpts{
    From:     auth.From,
    Signer:   auth.Signer,
    GasLimit: big.NewInt(2381623),
    Value:    big.NewInt(10),
}, "test project", "http://www.example.com")

当然还需要继续挖矿:

fmt.Println("Mining...")
sim.Commit()
numOfProjects, _ = contract.NumberOfProjects(nil)
fmt.Printf("Number of Projects after: %d\n", numOfProjects)
info, _ := contract.GetProjectInfo(nil, auth.From)
fmt.Printf("Project Info: %v\n", info)

...但我们得到以下输出:

Number of Projects before: 0
Adding new project...
Mining...
Number of Projects after: 1
Project Info: {test project http://www.example.com 0}

太好了,这意味着我们的项目已经创建。 因此,我们能够部署合约,对其进行读取和写入。

但是,如果合约已经部署并且我们只想与之交互怎么办? 幸运的是,生成的代码包含一个 NewWinnerTakesAll 方法,它只获取已部署合约的地址,允许我们实例化合约:

instContract, err := NewWinnerTakesAll(addr, sim)
if err != nil {
    log.Fatalf("could not instantiate contract: %v", err)
}
numOfProjects, _ = instContract.NumberOfProjects(nil)
fmt.Printf("Number of Projects of instantiated Contract: %d\n", numOfProjects)

我们获得与已部署合约相同的返回值,并且可以与此版本完全相同的方式进行交互,后者由地址实例化。

好的,我们已经完成了与合约进行有意义交互所需的所有步骤,但仅限于模拟后端。 为了使用测试网或真正的以太坊区块链,我们只需要调整几件事:

const key = "your key json"
conn, err := rpc.NewIPCClient("/path/to/your/.ethereum/testnet/geth.ipc")
if err != nil {
    log.Fatalf("could not create ipc client: %v", err)
}
auth, err := bind.NewTransactor(strings.NewReader(key), "your password")
if err != nil {
    log.Fatalf("could not create auth: %v", err)
}

这会生成我们自己创建的 auth 对象。 当然,请不要在您的代码中使用纯文本密钥和/或密码Go以太坊开发详解,而是以安全的方式加载它们。 :)

如果合约已经部署,我们不需要创建NewIPCClient,只需要拨一个节点:

conn, err := ethclient.Dial("/path/to/your/.ethereum/testnet/geth.ipc")
if err != nil {
    log.Fatalf("could not connect to remote node: %v", err)
}

这就对了! 可以在此处找到此示例的完整代码。

综上所述

正如我在本文开头所述,在我看来,现在依赖 Solidity 智能合约进行正式应用还为时过早,但这种和其他几种基于区块链的智能合约方法的潜力是巨大的,所以了解周围的技术是必须的,是值得的。

Go 非常适合与基于以太坊的智能合约交互的任务,因为有很多来自 geth 的可重用代码,甚至还有一些关于如何入门的文档。 这当然可以用任何其他语言实现(例如:使用 web3),但如果你喜欢 Go,这似乎是一个可靠的选择。 :)

================================================ == =====================

分享一些与比特币、以太坊、EOS、Fabric等区块链相关的交互式在线编程实战教程: