说实话对以太坊还不太熟,这几个月研究并基于以太坊搭建联盟链平台,主要是围绕CA认证、国密兼容和共识算法展开,最近需要整一个go的sdk,于是翻了各种资料如何部署和调用智能合约。
以hello合约作为示例:
// SPDX-License-Identifier: SimPL-2.0
pragma solidity >=0.4.0 <=0.7.0;
contract HelloWorld {
function Hello() pure public returns(string){
return "hello world!";
}
}
说实话,单单安装solc我都费了一番功夫,老是报版本错误,我装的是0.6.12版本,这里要说一点就是:pure 要写在public前面,不然会报错。。。(刚接触solidity,还不知道为什么,如果你知道可以评论指出,先行感谢)
接下来就是编译:
solc --bin hello.sol -o hello.abi solc --abi hello.sol -o hello.bin abigen --bin=hello.bin --abi=hello.abi --pkg=contract --out=hello.go
这样就得到了可用的hello.go文件,后续需要导入并使用。
接着是部署和调用:
package ethclient
import(
"github.com/ethereum/go-ethereum/ethclient/contract" //hello.go放在该文件夹下
"github.com/ethereum/go-ethereum/accounts/abi/bind"
//其他包懒得写,主要是两个
)
func TestDeployContract(t *testing.T) {
ethclient, err := Dial("http://localhost:8545")
if err != nil {
t.Error(err)
}
keyJson, err := ioutil.ReadFile("../build/bin/data/keystore/UTC--2020-08-17T03-35-30.955610100Z--520613668132f205d5ee27246098c72bbb793896")
if err != nil {
t.Error(err)
}
key, err := keystore.DecryptKey(keyJson, "")
if err != nil {
t.Error(err)
}
publicKey := key.PrivateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
t.Error("error casting public key to ECDSA")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
nonce, err := ethclient.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
t.Error(err)
}
gasPrice, err := ethclient.SuggestGasPrice(context.Background())
if err != nil {
t.Error(err)
}
auth := bind.NewKeyedTransactor(key.PrivateKey)
auth.Nonce = big.NewInt(int64(nonce))
auth.Value = big.NewInt(0) // in wei
auth.GasLimit = uint64(300000) // in units
auth.GasPrice = gasPrice
address, tx, _, err := contract.DeployHello(auth, ethclient) // 部署合约
if err != nil {
t.Error(err)
}
fmt.Println(address.Hex()) // 0x80bec2b5FbFC19Bc06c3423b6b1De65156528929
fmt.Println(tx.Hash().Hex()) // 0x414d211952688a35c9a08619823e40ef6c2dd6b288c89375c269bb7946e1aa9b
// 调用合约,建议部署和调用不要写在同一个函数中,我这里为了简便所以合到了一起
nonce1, err := ethclient.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
t.Error(err)
}
auth.Nonce = big.NewInt(int64(nonce1))
hello, err := contract.NewHello(address, ethclient)
helloRaw := contract.HelloRaw{hello}
helloTx, err := helloRaw.Transact(auth, "Hello") // 这是hello.go中已经封装好的方法,也可以自己组装交易然后Send
if err != nil {
t.Error(err)
}
fmt.Printf("txid : %v\n", helloTx.Hash().String())
}
细节就不描述了,主要是就两个函数,DeployHello和Transact;其实,在Dial的时候是需要传入一个证书(毕竟是联盟链),但是,这里被我省掉了。