作者:freewind
比原项目仓库:
Github地址:https://github.com/Bytom/bytom
Gitee地址:https://gitee.com/BytomBlockchain/bytom
在比原的dashboard中,我们可以为一个帐户创建地址(address),这样就可以在两个地址之间转帐了。在本文,我们将结合代码先研究一下,比原是如何创建一个地址的。
首先看看我们在dashboard中的是如何操作的。
我们可以点击左侧的"Accounts",在右边显示我的帐户信息。注意右上角有一个“Create Address”链接: 点击后,比原会为我当前选择的这个帐户生成一个地址,马上就可以使用了:
本文我们就要研究一下这个过程是怎么实现的,分成了两个小问题:
- 前端是如何向后台接口发送请求的?
- 比原后台是如何创建地址的?
前端是如何向后台接口发送请求的?
在前一篇文章中,我们也是先从前端开始,在React组件中一步步找到了使用了接口,以前发送的数据。由于这些过程比较相似,在本文我们就简化了,直接给出找到的代码。
首先是页面中的"Create Address"对应的React组件:
class AccountShow extends BaseShow { // ... // 2. createAddress() { // ... // 3. this.props.createAddress({ account_alias: this.props.item.alias }).then(({data}) => { this.listAddress() this.props.showModal(<div> <p>{lang === 'zh' ? '拷贝这个地址以用于交易中:' : 'Copy this address to use in a transaction:'}</p> <CopyableBlock value={data.address} lang={lang}/> </div>) }) } render() { // ... view = <PageTitle title={title} actions={[ // 1. <button className='btn btn-link' onClick={this.createAddress}> {lang === 'zh' ? '新建地址' : 'Create address'} </button>, ]} /> // ... } // ... } }
上面的第1处就是"Create Address"链接对应的代码,它实际上是一个Button,当点击后,会调用createAddress
方法。而第2处就是这个createAddress
方法,在它里面的第3处,又将调用this.props.createAddress
,也就是由外部传进来的createAddress
函数。同时,它还要发送一个参数account_alias
,它对应就是当前帐户的alias。
继续可以找到createAddress
的定义:
const accountsAPI = (client) => { return { // ... createAddress: (params, cb) => shared.create(client, '/create-account-receiver', params, {cb, skipArray: true}), // ... } }
可以看到,它调用的比原接口是/create-account-receiver
。
然后我们就将进入比原后台。
比原后台是如何创建地址的?
在比原的代码中,我们可以找到接口/create-account-receiver
对应的handler:
func (a *API) buildHandler() { // ... if a.wallet != nil { // ... m.Handle("/create-account-receiver", jsonHandler(a.createAccountReceiver))
原来是a.createAccountReceiver
。我们继续进去:
// 1. func (a *API) createAccountReceiver(ctx context.Context, ins struct { AccountID string `json:"account_id"` AccountAlias string `json:"account_alias"` }) Response { // 2. accountID := ins.AccountID if ins.AccountAlias != "" { account, err := a.wallet.AccountMgr.FindByAlias(ctx, ins.AccountAlias) if err != nil { return NewErrorResponse(err) } accountID = account.ID } // 3. program, err := a.wallet.AccountMgr.CreateAddress(ctx, accountID, false) if err != nil { return NewErrorResponse(err) } // 4. return NewSuccessResponse(&txbuilder.Receiver{ ControlProgram: program.ControlProgram, Address: program.Address, }) }
方法中的代码可以分成4块,看起来还是比较清楚:
- 第1块的关注点主要在参数这块。可以看到,这个接口可以接收2个参数
account_id
和account_alias
,但是刚才的前端代码中传过来了account_alias
这一个,怎么回事? - 从第2块这里可以看出,如果传了
account_alias
这个参数,则会以它为准,用它去查找相应的account,再拿到相应的id。否则的话,才使用account_id
当作account的id - 第3块是为
accountID
相应的account创建一个地址 - 第4块返