说实话对以太坊还不太熟,这几个月研究并基于以太坊搭建联盟链平台,主要是围绕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的时候是需要传入一个证书(毕竟是联盟链),但是,这里被我省掉了。