
本节,将具体记录使用go语言,在以太坊搭建的私链环境下,进行区块操作和智能合约的交互、开发等等
前提阅读需要下载依赖:
$ go get -d github.com/ethereum/go-ethereum/...安装abigen
go直接和智能合约交互,有很多琐碎的细节需要照顾到,比较麻烦.以太坊专门为我们提供了一个abigen的工具,他可以根据sol或者abi文件生成特定语言的封装,方便进行交互,支持golang,objc,java三种语言。
一般的,我们安装solc和安装abigen工具是一起进行的。
安装solc:
直接在官网https://github.com/ethereum/solidity/releases 下载二进制文件即可
安装abigen
对源文件进行编译: $ cd $GOPATH/src/github.com/ethereum/go-ethereum $ make abigen 就可以形成以下的二进制文件: root@cchui-virtual-machine:~/eth/go-ethereum/build/bin# ls abidump abigen bootnode checkpoint-admin clef devp2p ethkey evm faucet geth
其中,abigen和geth就是我们想要的了。
之后,配置到环境变量中。
使用命令:
abigen -sol ./Hello.sol -pkg contract -out ./Hello.go
即可编译成go代码的智能合约。
部署合约 启动启动以如下命令启动,开启http,rpc,wc等服务:
geth --identity "test Chain" --datadir ./datachain --rpc --rpcport 8547 --ws --ws.port=8546 --http.port=8548 --rpccorsdomain "*" --port 1718 --nodiscover --nat "any" --networkid 10 --rpcapi "eth,net,web3,personal" console --allow-insecure-unlock
之后,可能在解锁账户的时候报错:
error:account unlock with HTTP access is forbidden
这是由于新版本geth,出于安全考虑,默认禁止了HTTP通道解锁账户
解决方式:启动节点命令添加--allow-insecure-unlock。
编写智能合约:
pragma solidity >=0.8.6;
contract Hello {
string name = "hello CC";
function set(string memory _name) public{
name = _name;
}
function get() public view returns(string memory){
return name;
}
}
这里需要注意,我使用的版本abigen,只支持soldity 在0.8.6+版本上编译。
部署合约根据官网:
// const key = "account/UTC--2021-07-26T12-39-54.784952954Z--471144a5fec2d48450d6e14438a448be839dcd04"
const key = `
{
"address": "471144a5fec2d48450d6e14438a448be839dcd04",
"crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "df39a477f35ecbd138c78da5d4968e69388b287bbddba9403fb4298b1a3a156a",
"cipherparams": {
"iv": "2e57aeb78f37fd7dd3f127c483d6c457"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "8581cd5b79c791866d3707444b5d8e5fd3fed29da9b20e7409be8d1fc41603b4"
},
"mac": "036e4d384c714a0ffdfc418f5703bc00c731b5134e339356a3a7ebc38022fec3"
},
"id": "f69bdc60-d5d5-4ec9-a9d2-b2f30be8de1a",
"version": 3
}
`
func Deploy() {
// 连接到以太坊智能合约
conn, err := ethclient.Dial("http://127.0.0.1:8548")
if err != nil {
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
}
auth, err := bind.NewTransactorWithChainID(strings.NewReader(key),
"123456", big.NewInt(15))
if err != nil {
log.Fatalf("Failed to create authorized transactor: %v", err)
}
// 部署一个合约
address, tx, hello, err := contract.DeployHello(auth, conn)
if err != nil {
log.Fatalf("Failed to deploy new token contract: %v", err)
}
fmt.Printf("Contract pending deploy: 0x%xn", address)
fmt.Printf("Transaction waiting to be mined: 0x%xnn", tx.Hash())
time.Sleep(250 * time.Millisecond)
}
这里需要注意:NewTransactor方法已经弃用了,详情参考:bind · pkg.go.dev
这里,我遇到了一个问题:
error "invalid character 'a' looking for beginning of value” from json.Unmarsh
这是由于不能正确解析json导致的,尝试了很多办法都不行,最后只能把json 里的数据,写到变量里去了。
还可能遇到一个问题:
Returned error: invalid sender
这是由于初始化链的chainId和启动参数networkId,或者与NewTransactorWithChainID参数输入的ChainID不一致导致的。
改变好chainId一致即可。
最后,终于是部署成功了:
> miner.start(1) INFO [07-30|20:08:46.709] Updated mining threads threads=1 INFO [07-30|20:08:46.709] Transaction pool price threshold updated price=1,000,000,000 INFO [07-30|20:08:46.710] Commit new mining work number=76 sealhash=114b38..8ef0ab uncles=0 txs=0 gas=0 fees=0 elapsed="93.219µs" INFO [07-30|20:08:51.192] Setting new local account address=0x471144A5FEC2d48450d6e14438a448Be839DCd04 INFO [07-30|20:08:51.192] Submitted contract creation hash=0xce9b306e0749d5607da00f62fa04157df489f8c450b437150ca380a1ffc50ce0 from=0x471144A5FEC2d48450d6e14438a448Be839DCd04 nonce=0 contract=0xd9D695DecfC653A4F48D6910bA653De1B777d936 value=0 INFO [07-30|20:08:52.711] Commit new mining work number=76 sealhash=c62671..ee1882 uncles=0 txs=1 gas=257,245 fees=0.000257245 elapsed="331.346µs" INFO [07-30|20:08:53.314] Successfully sealed new block number=76 sealhash=c62671..ee1882 hash=a49383..bdadae elapsed=603.333ms INFO [07-30|20:08:53.314] mined potential block number=76 hash=a49383..bdadae INFO [07-30|20:08:53.315] Commit new mining work number=77 sealhash=f85627..c5b5af uncles=0 txs=0 gas=0 fees=0 elapsed="191.813µs" 得到合约地址: Contract pending deploy: 0xd9d695decfc653a4f48d6910ba653de1b777d936 Transaction waiting to be mined: 0xce9b306e0749d5607da00f62fa04157df489f8c450b437150ca380a1ffc50ce0查询
测试查询:
func GetName() {
// 连接到以太坊节点
conn, err := ethclient.Dial("http://127.0.0.1:8548")
if err != nil {
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
}
// 初始化合约,输入地址
token, err := contract.NewHello(common.HexToAddress("0xd9d695decfc653a4f48d6910ba653de1b777d936"), conn)
if err != nil {
log.Fatalf("Failed to instantiate a Token contract: %v", err)
}
name, err := token.Get(nil)
if err != nil {
log.Fatalf("Failed to retrieve token name: %v", err)
}
fmt.Println("name is:", name)
}
参考
Go API | Go Ethereum
安装Solidity编译器