Bytom交易说明(UTXO用户自己管理模式)
2018-08-29 14:18
447 查看
比原项目仓库:
Github地址:https://github.com/Bytom/bytom
Gitee地址:https://gitee.com/BytomBlockchain/bytom
该部分主要针对用户自己管理私钥和地址,并通过utxo来构建和发送交易。
1.创建私钥和公钥
2.根据公钥创建接收对象
3.找到可花费的
4.通过
5.组合交易的
6.对构造的交易进行签名
7.提交交易上链
注意事项:
以下步骤以及功能改造仅供参考,具体代码实现需要用户根据实际情况进行调试,具体可以参考单元测试案例代码blockchain/txbuilder/txbuilder_test.go#L255
创建多签地址参考代码account/accounts.go#L294进行相应改造为:
涉及utxo构造交易的相关字段说明如下:
上述这些utxo的字段信息可以从
utxo跟get-block返回结果的字段对应关系如下:
4.通过
通过utxo构造交易就是使用spend_account_unspent_output的方式来花费指定的utxo。
第一步,通过
第二步,通过
该部分功能可以参考代码protocol/bc/types/txoutput.go#L20:
Github地址:https://github.com/Bytom/bytom
Gitee地址:https://gitee.com/BytomBlockchain/bytom
该部分主要针对用户自己管理私钥和地址,并通过utxo来构建和发送交易。
1.创建私钥和公钥
2.根据公钥创建接收对象
3.找到可花费的
utxo
4.通过
utxo构造交易
5.组合交易的
input和
output构成交易模板
6.对构造的交易进行签名
7.提交交易上链
注意事项:
以下步骤以及功能改造仅供参考,具体代码实现需要用户根据实际情况进行调试,具体可以参考单元测试案例代码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
AssetIDutxo的资产ID
Amountutxo的资产数目
SourcePos该utxo在前一笔交易的output的位置
ControlProgramutxo的接收program
Addressutxo的接收地址
上述这些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交易说明(账户管理模式)
- linux用户和用户组管理(添加、删除、修改)及说明
- 一、ElasticSearch5.6.3下载安装步骤 说明:ElasticSearch的运行不能用root执行,自己用useradd命令新建一个用户如下所示: sueradd chen passw
- 在CuteEditor中如何让用户来管理自己的文件夹
- oracle用户管理的完全恢复4:在ARCHIVELOG 模式(恢复打开的数据库--数据库最初是关闭的)
- ARCHIVELOG模式下用户管理恢复联机重做日志文件—当前活动组所有成员全部损坏
- 产品管理精华:第十二,把自己变成一个用户
- 用户权限管理 设计模式
- Windows 2012 R2上搭建IIS管理用户的隔离模式FTP
- 自我管理心得、个人商业模式(自己的客户是谁?)
- 用户管理页面禁止删除自己
- ARCHIVELOG模式下用户管理恢复联机重做日志文件(1)——非活动组所有成员全部损坏!
- 开源 免费 java CMS - FreeCMS-功能说明-用户管理
- 这台服务器的配置是远程管理的默认远程桌面模式,这允许最多两个用户同时进行远程
- Java之------单机版书店管理系统(设计思想和设计模式系列二)用户模块
- oracle用户管理的完全恢复2:在NOARCHIVELOG 模式下执行恢复(无联机日志的备份)
- 一个自己写的自动格式化,开机挂载,创建用户和管理ACL权限的shell脚本
- oracle用户管理的完全恢复3:在ARCHIVELOG 模式(恢复关闭的数据库)
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(21)-用户角色权限基本的实现说明