区块链技术 blockchainGolang区块链大学

No.3-区块链ETH之golang调用实践

2019-03-29  本文已影响45人  太白菜Rennbon

前言

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 币种概念

  1. eth 有主链币和代币之分,主链币用于支付交易手续费等
  2. 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团队的开源项目,其中包含了详细的文档。

上一篇下一篇

猜你喜欢

热点阅读