博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Bytom交易说明(UTXO用户自己管理模式)
阅读量:6983 次
发布时间:2019-06-27

本文共 7412 字,大约阅读时间需要 24 分钟。

比原项目仓库:

Github地址:

Gitee地址:

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

注意事项:

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

1.创建私钥和公钥

该部分功能可以参考代码,可以通过 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形式,两者是一一对应的,任选其一即可。其中创建单签地址参考代码进行相应改造为:

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}

创建多签地址参考代码进行相应改造为:

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的结构为:(参考代码)

// 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中找到,其相关的结构体如下:(参考代码)

// BlockTx is the tx struct for getBlock functype 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,该部分功能可以参考代码进行相应改造为:

// UtxoToInputs convert an utxo to the txinputfunc 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

该部分功能可以参考代码:

// NewTxOutput create a new output structfunc 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,该部分功能可以参考进行改造为:

type InputAndSigInst struct {    input *types.TxInput    sigInst *SigningInstruction}// Build build transactions with templatefunc 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.对构造的交易进行签名

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

// Sign will try to sign all the witnessfunc 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中提交交易的API的功能即可

转载地址:http://jotpl.baihongyu.com/

你可能感兴趣的文章
ICS—CERT官网公示匡恩网络新发现四工控漏洞
查看>>
英国电价与光伏容量占比关系分析
查看>>
浅谈对5G核心网演进方向的几点展望
查看>>
明智地选择数据中心的五个注意事项
查看>>
开启物联网的真正潜力需要在更大程度上克服数据挑战
查看>>
张小龙公布微信小程序进展 可直接从桌面进入
查看>>
手机芯片三国杀:高通、联发科、展讯都想成霸主
查看>>
六大技巧提升员工信息安全意识
查看>>
保利协鑫多晶硅产量再创历史记录
查看>>
爱屋及乌 年轻投资者因喜爱Snapchat亏钱也买Snap股票
查看>>
物联网产品背后潜藏着危机
查看>>
阿里云将增设马来西亚数据中心 中国技术获赞
查看>>
与Netflix合作 美电视运营商推出4K频道
查看>>
Struts2中的Action
查看>>
Balluff推出刀具识别系统
查看>>
美国支付巨头Verifone遭遇网络攻击
查看>>
开平推进智慧城市等领域信息化建设及公共数据资源共享
查看>>
宜兴电信成功跨界合作开拓农村物联网市场
查看>>
Oracle业务适合用PostgreSQL去O的一些评判标准
查看>>
多个常见代码设计缺陷
查看>>