千家信息网

Bytom的UTXO用户管理模式怎么创建

发表于:2024-11-19 作者:千家信息网编辑
千家信息网最后更新 2024年11月19日,这篇文章主要讲解了"Bytom的UTXO用户管理模式怎么创建",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Bytom的UTXO用户管理模式怎么创建"吧
千家信息网最后更新 2024年11月19日Bytom的UTXO用户管理模式怎么创建

这篇文章主要讲解了"Bytom的UTXO用户管理模式怎么创建",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Bytom的UTXO用户管理模式怎么创建"吧!

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 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,该部分功能可以参考代码account/builder.go#L169进行相应改造为:

// 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 该部分功能可以参考代码protocol/bc/types/txoutput.go#L20:

// 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,该部分功能可以参考blockchain/txbuilder/builder.go#L92进行改造为:

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.对构造的交易进行签名

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

// 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中提交交易的APIsubmit-transaction的功能即可

感谢各位的阅读,以上就是"Bytom的UTXO用户管理模式怎么创建"的内容了,经过本文的学习后,相信大家对Bytom的UTXO用户管理模式怎么创建这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0