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

链式交易

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

接下来我们来看一下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. 当离开浏览器窗口,提示语title更改

    head里面插入一下代码 <script> document.addEventListener('visibilitychange',function(){if(document.visi ...

  2. 学号20175313 《Arrays和String单元测试》第八周

    目录 Arrays和String单元测试 一.String类相关方法的单元测试 二.Arrays类相关方法的单元测试 三.测试过程中遇到的问题及其解决方法 四.码云链接 五.参考资料 Arrays和S ...

  3. weblogic的基础安装

    安装java环境 不能使用centos自带的openjdk  必须使用源码安装 把下载的jdk-8u181-linux-x64.tar 解压到 /usr/src目录下      tar zxvf jd ...

  4. mac pro换屏指南

    https://www.ifixit.com/ 该网站提供了 换屏的详细操作步骤.

  5. mysql-5.7.25 源码 安装

    mysql-5.7.25 源码 安装 编译 export INSTALL_PREFIX="/data/services" export MYSQL_INSTALL_PATH=&qu ...

  6. 自己写的一些公共js方法

    /* 说明文件:这里用的都是es6的语法 导入导出,拿vue举个栗子,你只需要在用到的地方,按需要导入就行了,然后在mounted中直接可以拿来用 比如下面的手机****方法,在需要用到的地方impo ...

  7. TCP 数据传输工具类

    package com.ivchat.test.propertysystem.util; import java.io.BufferedReader;import java.io.ByteArrayO ...

  8. 关于Linux目录结构的理解

    dUI与刚接触Linux的学习者来说,那么多的根下目录足够让我们头疼不已,如下图: 那么对于初学者来说,我们首要了解的是哪些目录呢?  就是这个标黄绿色的tmp目录,此目录是一个存放临时文件夹的目录( ...

  9. HDU 1556 BIT区间修改+单点查询(fread读入优化)

    BIT区间修改+单点查询 [题目链接]BIT区间修改+单点查询 &题解: BIT区间修改+单点查询和求和的bit是一模一样的(包括add,sum) 只不过是你使用函数的方式不一样: 使用区间的 ...

  10. jq元素拖拽

    <div id="a1"></div> js <script type="text/javascript"> $(funct ...