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

链式交易

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

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

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

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

  1. func (a *API) buildTxs(ctx context.Context, req *BuildRequest) ([]*txbuilder.Template, error) {
  2. //验证参数的合法性
  3. if err := a.checkRequestValidity(ctx, req); err != nil {
  4. return nil, err
  5. }
  6. //合并处理交易输入输出的类型组合
  7. actions, err := a.mergeSpendActions(req)
  8. if err != nil {
  9. return nil, err
  10. }
  11. //构建一笔新的交易模板
  12. builder := txbuilder.NewBuilder(time.Now().Add(req.TTL.Duration))
  13. //声明交易模板
  14. tpls := []*txbuilder.Template{}
  15. //遍历交易的输入输出类型组合
  16. for _, action := range actions {
  17. //类型组合的输入为apend_account
  18. if action.ActionType() == "spend_account" {
  19. //构建花费的输入输出类型组合并且自动合并UTXO
  20. tpls, err = account.SpendAccountChain(ctx, builder, action)
  21. } else {
  22. //构建交易输入输出类型组合
  23. err = action.Build(ctx, builder)
  24. }
  25. if err != nil {
  26. //回滚
  27. builder.Rollback()
  28. return nil, err
  29. }
  30. }
  31. //构建交易
  32. tpl, _, err := builder.Build()
  33. if err != nil {
  34. //回滚
  35. builder.Rollback()
  36. return nil, err
  37. }
  38. tpls = append(tpls, tpl)
  39. return tpls, nil
  40. }

build方法的实现过程:

  1. // Build build transactions with template
  2. func (b *TemplateBuilder) Build() (*Template, *types.TxData, error) {
  3. // Run any building callbacks.
  4. for _, cb := range b.callbacks {
  5. err := cb()
  6. if err != nil {
  7. return nil, nil, err
  8. }
  9. }
  10. tpl := &Template{}
  11. tx := b.base
  12. if tx == nil {
  13. tx = &types.TxData{
  14. Version: 1,
  15. }
  16. }
  17. if b.timeRange != 0 {
  18. tx.TimeRange = b.timeRange
  19. }
  20. // Add all the built outputs.
  21. tx.Outputs = append(tx.Outputs, b.outputs...)
  22. // Add all the built inputs and their corresponding signing instructions.
  23. for i, in := range b.inputs {
  24. instruction := b.signingInstructions[i]
  25. instruction.Position = uint32(len(tx.Inputs))
  26. // Empty signature arrays should be serialized as empty arrays, not null.
  27. if instruction.WitnessComponents == nil {
  28. instruction.WitnessComponents = []witnessComponent{}
  29. }
  30. tpl.SigningInstructions = append(tpl.SigningInstructions, instruction)
  31. tx.Inputs = append(tx.Inputs, in)
  32. }
  33. tpl.Transaction = types.NewTx(*tx)
  34. tpl.Fee = CalculateTxFee(tpl.Transaction)
  35. return tpl, tx, nil
  36. }

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

花费未确认的交易

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

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

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

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

方法如下:

  1. // MergeSpendAction merge common assetID and accountID spend action
  2. func MergeSpendAction(actions []txbuilder.Action) []txbuilder.Action {
  3. //声明变量,map
  4. resultActions := []txbuilder.Action{}
  5. spendActionMap := make(map[string]*spendAction)
  6. //遍历交易的输入输出类型组合
  7. for _, act := range actions {
  8. switch act := act.(type) {
  9. case *spendAction:
  10. //actionKey字符串拼接
  11. actionKey := act.AssetId.String() + act.AccountID
  12. //遍历spendActionMap
  13. if tmpAct, ok := spendActionMap[actionKey]; ok {
  14. tmpAct.Amount += act.Amount
  15. tmpAct.UseUnconfirmed = tmpAct.UseUnconfirmed || act.UseUnconfirmed
  16. } else {
  17. spendActionMap[actionKey] = act
  18. resultActions = append(resultActions, act)
  19. }
  20. default:
  21. resultActions = append(resultActions, act)
  22. }
  23. }
  24. return resultActions
  25. }

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

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

Bytom的链式交易和花费未确认的交易的更多相关文章

  1. MySQL中间件之ProxySQL(11):链式规则( flagIN 和 flagOUT )

    返回ProxySQL系列文章:http://www.cnblogs.com/f-ck-need-u/p/7586194.html 1.理解链式规则 在mysql_query_rules表中,有两个特殊 ...

  2. ProxySQL(11):链式规则( flagIN 和 flagOUT )

    文章转载自:https://www.cnblogs.com/f-ck-need-u/p/9350631.html 理解链式规则 在mysql_query_rules表中,有两个特殊字段"fl ...

  3. 04.UTXO:未使用的交易输出,比特币核心概念之一

    在比特币系统上其实并不存在“账户”,而只有“地址”.只要你愿意,你就可以在比特币区块链上开设无限多个钱包地址,你拥有的比特币数量是你所有的钱包地址中比特币的总和.比特币系统并不会帮你把这些地址汇总起来 ...

  4. 由表单验证说起,关于在C#中尝试链式编程的实践

    在web开发中必不可少的会遇到表单验证的问题,为避免数据在写入到数据库时出现异常,一般比较安全的做法是前端会先做一次验证,通过后把数据提交到后端再验证一次,因为仅仅靠前端验证是不安全的,有太多的htt ...

  5. jQuery插件编写及链式编程模型小结

    JQuery极大的提高了我们编写JavaScript的效率,让我们可以愉快的编写代码,做出各种特效.大多数情况下,我们都是使用别人开发的JQuery插件,今天我们就来看看如何把我们常用的功能做出JQu ...

  6. jQuery链式操作[转]

    用过jQuery的朋友都知道他强大的链式操作,方便,简洁,易于理解,如下 $("has_children").click(function(){ $(this).addClass( ...

  7. Objective-C 链式语法的实现

    对于 Objective-C 的语法,喜欢的人会觉得它是如此的优雅,代码可读性强,接近自然语言,开发者在调用大多数方法时不需要去查看注释或文档,通常只凭借方法名就可以大致知道这个方法的作用,可以理解为 ...

  8. jQuery的XX如何实现?——2.show与链式调用

    往期回顾: jQuery的XX如何实现?——1.框架 -------------------------- 源码链接:内附实例代码 jQuery使用许久了,但是有一些API的实现实在想不通.于是抽空看 ...

  9. 数据结构Java实现05----栈:顺序栈和链式堆栈

    一.堆栈的基本概念: 堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除 ...

随机推荐

  1. 常见查找算法(Java代码实现)

    一,顺序查找 查找算法中顺序查找算是最简单的了,无论是有序的还是无序的都可以,只需要一个个对比即可,但其实效率很低.我们来看下代码 public static int search(int[] a, ...

  2. ADB——连接手机的三种方式

    有USB连接 硬件状态正常. 包括 Android 设备处于正常开机状态,USB 连接线和各种接口完好. Android 设备的开发者选项和 USB 调试模式已开启. 可以到「设置」-「开发者选项」- ...

  3. 下载安装Git

    1.下载地址:https://git-scm.com/download/win  这里是下载64位的 2.安装步骤 (1)下载完成得到一个exe文件,双击傻瓜式安装 (2)开始安装 (3)选择安装的工 ...

  4. Python request 在linux上持续并发发送HTTP请求遇到 Failed to establish a new connection: [Errno 11] Resource temporarily unavailable

    并发数被限制 vim /etc/sysctl.conf 添加 net.ipv4.ip_local_port_range = 1024 65535   保存 /sbin/sysctl -p 让修改生效 ...

  5. 【JVM】-NO.113.JVM.1 -【JDK11 HashMap详解-4-resize()】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  6. 文件中间修改内容遇到OSEerror

    for i in f: 实际上是一直在调用 f.next() .(表明在交互模式下不能使用f.tell())从报错来看,是说 f.next() 方法被调用的时候,f.tell() 方法不可以被调用.

  7. EF性能检测工具MiniProfilerEF6的使用

    一.在VS项目中分别安装包MiniProfiler.MiniProfiler.EF6.MiniProfiler.MVC4 二.在Global.asax文件的Application_BeginReque ...

  8. java的冒泡排序

    public interface Sorter{ public <T extends Comparable<T>> void sort(T[] list); //定义两个待排序 ...

  9. 对于Java Bean的类型转换问题()使用 org.apache.commons.beanutils.ConvertUtils)

    在进行与数据库的交互过程中,由数据库查询到的数据放在 map 中,由 map 到 JavaBean 的过程中可以使用 BeanUtils.populate(map,bean)来进行转换 这里要处理的问 ...

  10. 用友畅捷通T6数据升级到T+的步骤图解

    1.打开升级工具,输入各项目: 2.点击下一步并确认---“是”: 3.输入目的账套信息(主要是系统管理员密码): 4.升级开始: 5.退出原账套登录的确认----“是”: 6.升级进度: 7.升级成 ...