Bytom的链式交易和花费未确认的交易

栏目: IOS · 发布时间: 6年前

内容简介:当我们基于比原做应用的时候,在构建交易过程中会遇到以下两种情况。多个地址向一个地址转账,还有一种就是从一个地址分批次向多个地址转账。那我们今天就来介绍一下这两种交易构建的具体流程,以及贴出具体实现的代码。当我们从多个钱包地址一次性转到一个地址的时候,为了提高用户体验。我们可以选择链式交易,把多笔交易一次性打包。那我们下面就来看一下链式交易的流程。

当我们基于比原做应用的时候,在构建交易过程中会遇到以下两种情况。多个地址向一个地址转账,还有一种就是从一个地址分批次向多个地址转账。那我们今天就来介绍一下这两种交易构建的具体流程,以及贴出具体实现的代码。

链式交易

当我们从多个钱包地址一次性转到一个地址的时候,为了提高用户体验。我们可以选择链式交易,把多笔交易一次性打包。那我们下面就来看一下链式交易的流程。

Bytom的链式交易和花费未确认的交易

接下来我们来看一下build-transaction接口的代码实现过程,代码如下:

// POST /build-chain-transactions
func (a *API) buildChainTxs(ctx context.Context, buildReqs *BuildRequest) Response {
    //验证请求id
    subctx := reqid.NewSubContext(ctx, reqid.New())
    //构建交易,方法的具体过程在下面
    tmpls, err := a.buildTxs(subctx, buildReqs)
    if err != nil {
       return NewErrorResponse(err)
     }
     return NewSuccessResponse(tmpls)
}

核心的实现方法,buildTxs方法的实现如下:

func (a *API) buildTxs(ctx context.Context, req *BuildRequest) ([]*txbuilder.Template, error) {
//验证参数的合法性
if err := a.checkRequestValidity(ctx, req); err != nil {
    return nil, err
}
//合并处理交易输入输出的类型组合
actions, err := a.mergeSpendActions(req)
if err != nil {
    return nil, err
}
//构建一笔新的交易模板
builder := txbuilder.NewBuilder(time.Now().Add(req.TTL.Duration))
//声明交易模板
tpls := []*txbuilder.Template{}
//遍历交易的输入输出类型组合
for _, action := range actions {
    //类型组合的输入为apend_account
    if action.ActionType() == "spend_account" {
       //构建花费的输入输出类型组合并且自动合并UTXO
        tpls, err = account.SpendAccountChain(ctx, builder, action)
    } else {
       //构建交易输入输出类型组合
        err = action.Build(ctx, builder)
    }

    if err != nil {
       //回滚
        builder.Rollback()
        return nil, err
    }
}
//构建交易
tpl, _, err := builder.Build()
if err != nil {
   //回滚
    builder.Rollback()
    return nil, err
}

tpls = append(tpls, tpl)
return tpls, nil
}

build方法的实现过程:

// Build build transactions with template
func (b *TemplateBuilder) Build() (*Template, *types.TxData, error) {
// Run any building callbacks.
for _, cb := range b.callbacks {
    err := cb()
    if err != nil {
        return nil, nil, err
    }
}

tpl := &Template{}
tx := b.base
if tx == nil {
    tx = &types.TxData{
        Version: 1,
    }
}

if b.timeRange != 0 {
    tx.TimeRange = b.timeRange
}

// Add all the built outputs.
tx.Outputs = append(tx.Outputs, b.outputs...)

// Add all the built inputs and their corresponding signing instructions.
for i, in := range b.inputs {
    instruction := b.signingInstructions[i]
    instruction.Position = uint32(len(tx.Inputs))

    // Empty signature arrays should be serialized as empty arrays, not null.
    if instruction.WitnessComponents == nil {
        instruction.WitnessComponents = []witnessComponent{}
    }
    tpl.SigningInstructions = append(tpl.SigningInstructions, instruction)
    tx.Inputs = append(tx.Inputs, in)
}

tpl.Transaction = types.NewTx(*tx)
tpl.Fee = CalculateTxFee(tpl.Transaction)
return tpl, tx, nil
}

到此,我们的链式交易的代码到此就讲解到这儿。如果感兴趣想仔细阅读源码,点击源码地址: https://git.io/fhAsr

花费未确认的交易

下面我们来介绍一下花费未确认的交易,我们首先介绍一下什么是花费未确认的交易。我们知道UTXO模型在交易的过程中,如果交易未打包确认。再进行第二笔转账就会存在“双花”问题,就不能再发起交易或者需要等一段时间才能再发起一笔交易。如果使用花费未确认的交易就可以避免这个问题。

那么花费未确认的交易实现机制是什么样的呢?我们在创建第一笔交易的时候,会找零,此时交易是未确认的状态。找零存在交易池中,我们发第二笔交易的时候就直接使用在交易池中找零地址里面的资产。

那我们来看一下花费未确认交易的代码实现过程,花费过程结构体如下:

type spendAction struct {
   accounts *Manager  //存储账户及其相关的控制程序参数
   bc.AssetAmount     //资产id和资产数量的结构体
   AccountID      string `json:"account_id"`  //账户id
   UseUnconfirmed bool   `json:"use_unconfirmed"`  //是否未确认
}

方法如下:

// MergeSpendAction merge common assetID and accountID spend action
func MergeSpendAction(actions []txbuilder.Action) []txbuilder.Action {
   //声明变量,map
   resultActions := []txbuilder.Action{}
   spendActionMap := make(map[string]*spendAction)
   //遍历交易的输入输出类型组合
   for _, act := range actions {
       switch act := act.(type) {
       case *spendAction:
          //actionKey字符串拼接
           actionKey := act.AssetId.String() + act.AccountID
           //遍历spendActionMap
           if tmpAct, ok := spendActionMap[actionKey]; ok {
               tmpAct.Amount += act.Amount
               tmpAct.UseUnconfirmed = tmpAct.UseUnconfirmed || act.UseUnconfirmed
            } else {
               spendActionMap[actionKey] = act
               resultActions = append(resultActions, act)
        }
      default:
        resultActions = append(resultActions, act)
      }
   }
   return resultActions
}

上面只是简单的贴出了核心的实现代码,如果感兴趣想仔细阅读源码,点击地址: https://git.io/fhAsw

这一期的内容我们到此就结束了,如果你感兴趣可以加入我们的社区一起讨论。如果在阅读的过程中有什么疑问可以在下方给我们留言,我们将第一时间为你解答。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java技术手册(第6版)

Java技术手册(第6版)

Benjamin J Evans、David Flanagan / 安道 / 人民邮电出版社 / 2015-12-1 / 79.00

《Java技术手册 第6版》为《Java 技术手册》的升级版,涵盖全新的Java 7 和Java 8。第1部分介绍Java 编程语言和Java 平台,主要内容有Java 环境、Java 基本句法、Java 面向对象编程、Java 类型系统、Java的面向对象设计、Java 实现内存管理和并发编程的方式。第2部分通过大量示例来阐述如何在Java 环境中完成实际的编程任务,主要内容有编程和文档约定,使......一起来看看 《Java技术手册(第6版)》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具