No.3-区块链ETH之golang调用实践
前言
eth身为区块链的老二哥,对于技术人而言也是一个必须了解的项目,这里就对geth如何使用二次开发做一个技术性的介绍
私链部署
首先,如果要开发一个钱包功能,那么必不可少的,得有一个测试环境能够供自己使用,eth也有官方测试链,但是凡事总是自己的才是最方便的,所以这里我们自己部署一个私链。
ububtu 安装
apt-get install software-properties-common
add-apt-repository -y ppa:ethereum/ethereum
apt-get update
apt-get install ethereum
mac安装
brew tap ethereum/ethereum
brew install ethereum
配置文件
genesis.json
{
"config": {
"chainId": 999,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x40000",
"extraData" : "",
"gasLimit" : "0xffffffff",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"alloc": { }
}
启动私链
#创建私链
geth --datadir mychain init genesis.json
#登录私链
geth --datadir mychain --networkid 999 --rpc console
#创建用户
personal.newAccount()
#启动挖矿(x是启动几个核心来挖矿)
miner.start(x)
以上是基本的操作,具体详细的内容可以网上翻看别人的帖子,这里不做介绍,当然为了开发方便,我们需要结合eth钱包的界面化工具,这样可以让我的操作性大大提升
eth钱包
https://github.com/ethereum/mist
钱包关联私链
"/Applications/Ethereum Wallet.app/Contents/MacOS/Ethereum Wallet" --rpc /指自定义路径/geth/mychain/geth.ipc
注意路径,以上命令执行成功后,那么eth私链的可视化界面工具就完成了,可以愉快的开发个性功能了
eth 币种概念
- eth 有主链币和代币之分,主链币用于支付交易手续费等
- erc20代币,智能合约功能的副产品,是ico更加容易,这也是eth能流行起来的一个依据
geth 概念分析
首先我们需要能够区分主链币和代币的概念,对于erc20代币,我们需要根据abi来完成一系列的操作,虽然geth库有提供很完善的token封装,但是对于需要多链集成的框架而言,他太全面了,太强大了,太有个性了反而不能容于集体,所以这里我是直接用abi来完成一些列的操作,
同时也将eth主链币和erc20代币区分为2种币种,这样能更好的抽象我们自己的框架。
代币和主链币单位如何维护
因为代币的单位可以自定义,所以不同的代币他们之间的精确度都会不一样,这也给共同的框架带来了复杂度,我们需要增加一个币种单位管理包来解耦币种单位的差异
代币转账及离线签名
对于代币而言,我们能更全面的控制到他的生成及签名的解耦,那就可以更好的做到定制化,以下是boxwallet钱包库代码
//创建erc20交易
func (c *Erc20Client) CreateTx(addrsFrom []string, token string, addrsTo []*bccoin.AddressAmount, feeCeo float64) (txu signature.TxUtil, err error) {
if len(addrsTo) != 1 || len(addrsFrom) != 1 {
return nil, errors.ERR_PARAM_NOT_VALID
}
local, err := c.ChooseClientNode()
if err != nil {
return nil, err
}
ctx := context.TODO()
contract := common.HexToAddress(token)
if err != nil {
return nil, err
}
to := addrsTo[0]
toAddress := common.HexToAddress(to.Address)
fromAccDef := accounts.Account{
Address: common.HexToAddress(addrsFrom[0]),
}
//获取erc20代币余额
tbalance, err := c.GetBalance(addrsFrom[0], token, local)
if err != nil {
return nil, err
}
cmp, err := tbalance.Cmp(to.Amount)
if err != nil {
return nil, err
}
if cmp < 0 {
return nil, errors.ERR_NOT_ENOUGH_COIN
}
gasprice, err := c.nmap[local].C.SuggestGasPrice(ctx)
if err != nil {
gasprice = c.DefGasPrice
}
//contract/abi
//获取即时Nonce值
nonce, _ := c.nmap[local].C.NonceAt(ctx, fromAccDef.Address, nil)
//构建代币data需要的input
input, err := c.ABI.Pack("transfer", toAddress, to.Amount.Val())
if err != nil {
return nil, err
}
msg := ethereum.CallMsg{From: fromAccDef.Address, To: &contract, Value: big.NewInt(0), Data: input}
gasLimit, err := c.nmap[local].C.EstimateGas(ctx, msg)
if err != nil {
gasLimit = c.DefGasLimit
}
excessCeo := (feeCeo - 1) * 100
if excessCeo != 0 {
prec, _ := big.NewFloat(excessCeo).Int64()
excess := big.NewInt(0).Quo(gasprice, big.NewInt(prec))
gasprice.Add(gasprice, excess)
}
tx := types.NewTransaction(nonce, contract, big.NewInt(0), gasLimit, gasprice, input)
cost := tx.Cost()
balance, _ := c.nmap[local].C.BalanceAt(context.TODO(), fromAccDef.Address, nil)
if balance.Cmp(cost) < 0 {
return nil, errors.ERR_NOT_ENOUGH_COIN
}
return signature.NewEthTx(nonce, fromAccDef.Address, contract, big.NewInt(0), gasLimit, gasprice, input, local), nil
}
//签名
func (tx *EthTx) Sign(prvKeys []string) error {
prvkey, err := tx.stringToEthPrvKey(prvKeys[0])
if err != nil {
return err
}
signTx, err := types.SignTx(tx.T, types.HomesteadSigner{}, prvkey)
if err != nil {
return err
}
tx.T = signTx
tx.Signed = true
return nil
}
boxvault项目wallet库地址,该库集成了eth,eth-erc20,btc,ltc,usdt,解决了各币种单位精度问题,实现了hd钱包功能,一个私钥多币种私钥衍生(该功能为boxvault的安全设计方可如此使用),解耦了签名功能,实现离线签名,同时可继续接入其他币种,为box团队的开源项目,其中包含了详细的文档。