Bytom交易說明(UTXO使用者自己管理員模式)

來源:互聯網
上載者:User

比原項目倉庫:

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

Gitee地址:https://gitee.com/BytomBlockc...

該部分主要針對使用者自己管理私密金鑰和地址,並通過utxo來構建和發送交易。

  • 1.建立私密金鑰和公開金鑰
  • 2.根據公開金鑰建立接收對象
  • 3.找到可花費的utxo
  • 4.通過utxo構造交易
  • 5.組合交易的inputoutput構成交易模板
  • 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
  • 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的功能即可

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.