比原项目仓库:

Github地址:https://github.com/Bytom/bytom

Gitee地址:https://gitee.com/BytomBlockchain/bytom

该部分主要针对用户自己管理私钥和地址,并通过utxo来构建和发送交易。

注意事项:

以下步骤以及功能改造仅供参考,具体代码实现需要用户根据实际情况进行调试,具体可以参考单元测试案例代码blockchain/txbuilder/txbuilder_test.go#L255

1.创建私钥和公钥

该部分功能可以参考代码crypto/ed25519/chainkd/util.go#L11,可以通过 NewXKeys(nil) 创建主私钥和主公钥

func NewXKeys(r io.Reader) (xprv XPrv, xpub XPub, err error) {
xprv, err = NewXPrv(r)
if err != nil {
return
}
return xprv, xprv.XPub(), nil
}

2.根据公钥创建接收对象

接收对象包含两种形式:address形式和program形式,两者是一一对应的,任选其一即可。其中创建单签地址参考代码account/accounts.go#L267进行相应改造为:

func (m *Manager) createP2PKH(xpub chainkd.XPub) (*CtrlProgram, error) {
pubKey := xpub.PublicKey()
pubHash := crypto.Ripemd160(pubKey) // TODO: pass different params due to config
address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
if err != nil {
return nil, err
} control, err := vmutil.P2WPKHProgram([]byte(pubHash))
if err != nil {
return nil, err
} return &CtrlProgram{
Address: address.EncodeAddress(),
ControlProgram: control,
}, nil
}

创建多签地址参考代码account/accounts.go#L294进行相应改造为:

func (m *Manager) createP2SH(xpubs []chainkd.XPub) (*CtrlProgram, error) {
derivedPKs := chainkd.XPubKeys(xpubs)
signScript, err := vmutil.P2SPMultiSigProgram(derivedPKs, len(derivedPKs))
if err != nil {
return nil, err
}
scriptHash := crypto.Sha256(signScript) // TODO: pass different params due to config
address, err := common.NewAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams)
if err != nil {
return nil, err
} control, err := vmutil.P2WSHProgram(scriptHash)
if err != nil {
return nil, err
} return &CtrlProgram{
Address: address.EncodeAddress(),
ControlProgram: control,
}, nil
}

3.找到可花费的utxo

找到可花费的utxo,其实就是找到接收地址或接收program是你自己的unspend_output。其中utxo的结构为:(参考代码account/reserve.go#L39

// UTXO describes an individual account utxo.
type UTXO struct {
OutputID bc.Hash
SourceID bc.Hash // Avoiding AssetAmount here so that new(utxo) doesn't produce an
// AssetAmount with a nil AssetId.
AssetID bc.AssetID
Amount uint64 SourcePos uint64
ControlProgram []byte AccountID string
Address string
ControlProgramIndex uint64
ValidHeight uint64
Change bool
}

涉及utxo构造交易的相关字段说明如下:

  • SourceID 前一笔关联交易的mux_id, 根据该ID可以定位到前一笔交易的output
  • AssetID utxo的资产ID
  • Amount utxo的资产数目
  • SourcePos 该utxo在前一笔交易的output的位置
  • ControlProgram utxo的接收program
  • Address utxo的接收地址

上述这些utxo的字段信息可以从get-block接口返回结果的transaction中找到,其相关的结构体如下:(参考代码api/block_retrieve.go#L26

// BlockTx is the tx struct for getBlock func
type BlockTx struct {
ID bc.Hash `json:"id"`
Version uint64 `json:"version"`
Size uint64 `json:"size"`
TimeRange uint64 `json:"time_range"`
Inputs []*query.AnnotatedInput `json:"inputs"`
Outputs []*query.AnnotatedOutput `json:"outputs"`
StatusFail bool `json:"status_fail"`
MuxID bc.Hash `json:"mux_id"`
} //AnnotatedOutput means an annotated transaction output.
type AnnotatedOutput struct {
Type string `json:"type"`
OutputID bc.Hash `json:"id"`
TransactionID *bc.Hash `json:"transaction_id,omitempty"`
Position int `json:"position"`
AssetID bc.AssetID `json:"asset_id"`
AssetAlias string `json:"asset_alias,omitempty"`
AssetDefinition *json.RawMessage `json:"asset_definition,omitempty"`
Amount uint64 `json:"amount"`
AccountID string `json:"account_id,omitempty"`
AccountAlias string `json:"account_alias,omitempty"`
ControlProgram chainjson.HexBytes `json:"control_program"`
Address string `json:"address,omitempty"`
}

utxo跟get-block返回结果的字段对应关系如下:

`SourceID`       - `json:"mux_id"`
`AssetID` - `json:"asset_id"`
`Amount` - `json:"amount"`
`SourcePos` - `json:"position"`
`ControlProgram` - `json:"control_program"`
`Address` - `json:"address,omitempty"`

4.通过utxo构造交易

通过utxo构造交易就是使用spend_account_unspent_output的方式来花费指定的utxo。

第一步,通过utxo构造交易输入TxInput和签名需要的数据信息SigningInstruction,该部分功能可以参考代码account/builder.go#L169进行相应改造为:

// UtxoToInputs convert an utxo to the txinput
func UtxoToInputs(xpubs []chainkd.XPub, u *UTXO) (*types.TxInput, *txbuilder.SigningInstruction, error) {
txInput := types.NewSpendInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram)
sigInst := &txbuilder.SigningInstruction{} if u.Address == "" {
return txInput, sigInst, nil
} address, err := common.DecodeAddress(u.Address, &consensus.ActiveNetParams)
if err != nil {
return nil, nil, err
} switch address.(type) {
case *common.AddressWitnessPubKeyHash:
derivedPK := xpubs[0].PublicKey()
sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness([]byte(derivedPK))) case *common.AddressWitnessScriptHash:
derivedPKs := chainkd.XPubKeys(xpubs)
script, err := vmutil.P2SPMultiSigProgram(derivedPKs, len(derivedPKs))
if err != nil {
return nil, nil, err
}
sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness(script)) default:
return nil, nil, errors.New("unsupport address type")
} return txInput, sigInst, nil
}

第二步,通过utxo构造交易输出TxOutput

该部分功能可以参考代码protocol/bc/types/txoutput.go#L20:

// NewTxOutput create a new output struct
func NewTxOutput(assetID bc.AssetID, amount uint64, controlProgram []byte) *TxOutput {
return &TxOutput{
AssetVersion: 1,
OutputCommitment: OutputCommitment{
AssetAmount: bc.AssetAmount{
AssetId: &assetID,
Amount: amount,
},
VMVersion: 1,
ControlProgram: controlProgram,
},
}
}

5.组合交易的input和output构成交易模板

通过上面已经生成的交易信息构造交易txbuilder.Template,该部分功能可以参考blockchain/txbuilder/builder.go#L92进行改造为:

type InputAndSigInst struct {
input *types.TxInput
sigInst *SigningInstruction
} // Build build transactions with template
func BuildTx(inputs []InputAndSigInst, outputs []*types.TxOutput) (*Template, *types.TxData, error) {
tpl := &Template{}
tx := &types.TxData{}
// Add all the built outputs.
tx.Outputs = append(tx.Outputs, outputs...) // Add all the built inputs and their corresponding signing instructions.
for _, in := range inputs {
// Empty signature arrays should be serialized as empty arrays, not null.
in.sigInst.Position = uint32(len(inputs))
if in.sigInst.WitnessComponents == nil {
in.sigInst.WitnessComponents = []witnessComponent{}
}
tpl.SigningInstructions = append(tpl.SigningInstructions, in.sigInst)
tx.Inputs = append(tx.Inputs, in.input)
} tpl.Transaction = types.NewTx(*tx)
return tpl, tx, nil
}

6.对构造的交易进行签名

账户模型是根据密码找到对应的私钥对交易进行签名,这里用户可以直接使用私钥对交易进行签名,可以参考签名代码blockchain/txbuilder/txbuilder.go#L82进行改造为:(以下改造仅支持单签交易,多签交易用户可以参照该示例进行改造)

// Sign will try to sign all the witness
func Sign(tpl *Template, xprv chainkd.XPrv) error {
for i, sigInst := range tpl.SigningInstructions {
h := tpl.Hash(uint32(i)).Byte32()
sig := xprv.Sign(h[:])
rawTxSig := &RawTxSigWitness{
Quorum: 1,
Sigs: []json.HexBytes{sig},
}
sigInst.WitnessComponents = append([]witnessComponent(rawTxSig), sigInst.WitnessComponents...)
}
return materializeWitnesses(tpl)
}

7.提交交易上链

该步骤无需更改任何内容,直接参照wiki中提交交易的APIsubmit-transaction的功能即可

Bytom交易说明(UTXO用户自己管理模式)的更多相关文章

  1. Windows 2012 R2上搭建IIS管理用户的隔离模式FTP

    Windows 2012 R2上搭建IIS管理用户的隔离模式FTP Windows自带的FTP现在可以提供基于非OS用户的管理,这提高了安全性.即使FTP用户名和密码泄露,也不会对操作系统造成进一步的 ...

  2. Azure 新的管理模式 —— Resource Manager

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  3. Greenplum+Hadoop学习笔记-14-定义数据库对象之创建与管理模式

    6.3.创建与管理模式 概述:DB内组织对象的一种逻辑结构.一个DB内能够有多个模式.在未指定模式时默认放置在public中.能够通过"\dn"方式查看数据库中现有模式: test ...

  4. 理解vuex的状态管理模式架构

    理解vuex的状态管理模式架构 一: 什么是vuex?官方解释如下:vuex是一个专为vue.js应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证以一种可预测的 ...

  5. 比特币交易本质--UTXO(Unspent Transaction Output)

    UTXO 代表 Unspent Transaction Output. Transaction 被简称为 TX,所以上面这个短语缩写为 UTXO. 现在的银行也好.信用卡也好.证券交易系统也好,互联网 ...

  6. PostgreSQL学习之【用户权限管理】说明

    背景 最近在学习PostgreSQL,看了用户权限管理文档,涉及到的知识点比较多,顺便写篇文章进行整理并不定时更新,也方便自己后续进行查阅. 说明 注意:创建好用户(角色)之后需要连接的话,还需要修改 ...

  7. Greenplum中定义数据库对象之创建与管理模式

    创建与管理模式 概述:DB内组织对象的一种逻辑结构.一个DB内能够有多个模式.在未指定模式时默认放置在public中.能够通过"\dn"方式查看数据库中现有模式. testdw=# ...

  8. 了解Vuex状态管理模式的理解强化指南

    1 Vuex是什么呢?它是Vue的状态管理模式,在使用vue的时候,需要在vue中各个组件之间传递值是很痛苦的,在vue中我们可以使用vuex来保存我们需要管理的状态值,值一旦被改变,所有引用该值的地 ...

  9. Vue状态管理模式---Vuex

    1. Vuex是做什么的? 官方解释: Vuex 是一个专为Vue.js 应用程序开发的 状态管理模式 它采用 集中式存储管理 应用的所有组件的状态, 并以相应的规则保证状态以一种可预测的方式发生变化 ...

随机推荐

  1. 【2017-03-20】HTML框架,标题栏插入小图标,锚点,插入音频视频,滚动效果

    一.html框架   iframe 在网页中嵌入一个别的网页 1.格式: <iframe  src="链接地址" width="" height=&quo ...

  2. C#基础知识整理

    年时,北风吹雁雪纷纷,一条秋裤冻上头.冷的连手都懒得动,就随便翻翻书,也没有更新博客,如今年已过,开始投入到正常的工作状态中,趁现在需求还没有来,把C#基础知识梳理一下,其实一直以来就想这样做的,对于 ...

  3. Vim for Windows --ctags

    What is ctags? ctags -- Generate tag files for source code,which is a tool used for facilitating rea ...

  4. python 测试文件或者文件目录是否存在 测试文件类型,获取文件大小,获取修改日期

    ----测试一个文件或目录是否存在 >>> import os >>> os.path.exists('/etc/passwd') True >>> ...

  5. 20165305 苏振龙《Java程序设计》第一周学习总结

    20165305 <Java程序设计>第一周学习总结 教材学习内容总结 我重点学习了jdk安装后面的第一章内容,算是更进一步的的了解了一些Java方面的基础知识. Java平台概论 Jav ...

  6. nodejs typescript怎么发送get、post请求,如何获取网易云通信token

    nodejs typescript怎么发送get.post请求,如何获取网易云通信token yarn add jshashesyarn add superagent检查语法yarn lint==== ...

  7. Python爬虫_Selenium与PhantomJS

    Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动化操作,不同是Selenium可以直接运 ...

  8. Java 线程类的一些常用方法

    线程类的一些常用方法: sleep(): 强迫一个线程睡眠N毫秒.  isAlive(): 判断一个线程是否存活.  join(): 等待线程终止.  activeCount(): 程序中活跃的线程数 ...

  9. vue 实现modal

    本文只是作为练习弹出框,弹框内部的东西需要进行自定义添加,主要对更新,删除,新建 ,提示四种弹框进行实现,例子中只是简单的组件应用 Modal.vue文件 <template> <d ...

  10. LoggerFactory.getLogger用法

    使用指定类初始化日志对象,在日志输出的时候,可以打印出日志信息所在类 如:Logger logger = LoggerFactory.getLogger(com.lz.Test.class);     ...