Bytom 用户自己管理UTXO

语言 go,参照bytom git 上项目改造

https://github.com/Bytom/bytom

https://github.com/Bytom-Community/Bytom-Mobile-Wallet-SDK

1、创建key:

func (a *API) PseudohsmCreateRootKey(seed string) Response {
   seedByte, error := hex.DecodeString(seed)
   if error != nil {
      return NewErrorResponse(error)
   }
   xprv := chainkd.RootXPrv(seedByte)
   xpub := xprv.XPub()
   rootKey := &chainkd.RootKey{Xpriv: xprv[:], Xpub: xpub[:]}
   return NewSuccessResponse(rootKey)
}

2、创建 P2PKH 地址

func (a *API) PseudohsmCreateP2PKH(xpub string) Response {
   xpubByte, error := hex.DecodeString(xpub)
   if error != nil {
      return NewErrorResponse(error)
   }
   address, err := account.CreateP2PKHByPub(xpubByte)
   if err != nil {
      return NewErrorResponse(error)
   }
   return NewSuccessResponse(&txbuilder.Receiver{
      ControlProgram: address.ControlProgram,
      Address:        address.Address,
   })
}

3、构建交易:

func Build(utxos []account.UTXO, outpus []account.Output, pubs []chainkd.XPub) (*Template, error) {

   maxTime := time.Now().Add(5 * time.Minute)
   builder := TemplateBuilder{
      maxTime: maxTime,
   }
   // Build all of the actions, updating the builder.
   for _, utxo := range utxos {
      txInput := types.NewSpendInput(nil, utxo.SourceID, utxo.AssetID, utxo.Amount, utxo.SourcePos, utxo.ControlProgram)
      sigInst := &SigningInstruction{}
      if utxo.Address == "" {
         log.Errorf("utxo address can not null ")
         return nil, nil
      }
      address, err := common.DecodeAddress(utxo.Address, &consensus.ActiveNetParams)
      if err != nil {
         log.Error("decode address error")
         return nil, err
      }
      switch address.(type) {
      case *common.AddressWitnessPubKeyHash:
         derivedPK := pubs[0].PublicKey()
         sigInst.WitnessComponents = append(sigInst.WitnessComponents, DataWitness([]byte(derivedPK)))
      case *common.AddressWitnessScriptHash:
         derivedPKs := chainkd.XPubKeys(pubs)
         script, err := vmutil.P2SPMultiSigProgram(derivedPKs, len(derivedPKs))
         if err != nil {
            return nil, err
         }
         sigInst.WitnessComponents = append(sigInst.WitnessComponents, DataWitness(script))
      }
      builder.AddInput(txInput, sigInst)
   }

   for _, output := range outpus {
      address, err := common.DecodeAddress(output.Address, &consensus.ActiveNetParams)
      if err != nil {
         return nil, err
      }
      redeemContract := address.ScriptAddress()
      program := []byte{}
      switch address.(type) {
      case *common.AddressWitnessPubKeyHash:
         program, err = vmutil.P2WPKHProgram(redeemContract)
      case *common.AddressWitnessScriptHash:
         program, err = vmutil.P2WSHProgram(redeemContract)
      default:
         return nil, errors.New("un support address type")
      }
      out := types.NewTxOutput(output.AssetID, output.Amount, program)
      builder.AddOutput(out)
   }

   // Build the transaction template.
   tpl, _, err := builder.Build()
   if err != nil {
      builder.rollback()
      return nil, err
   }

   //if tpl.SigningInstructions == nil {
   // tpl.SigningInstructions = []*txbuilder.SigningInstruction{}
   //}

   /*TODO: This part is use for check the balance, but now we are using btm as gas fee
   the rule need to be rewrite when we have time
   err = checkBlankCheck(tx)
   if err != nil {
      builder.rollback()
      return nil, err
   }*/

   return tpl, nil
}

4、签名:

func SignTx(tpl *Template, xprv chainkd.XPrv) error {

   for i, sigInst := range tpl.SigningInstructions {
      h := tpl.Hash(uint32(i)).Byte32()
      sig := xprv.Sign(h[:])
      pub := xprv.XPub()
      log.Errorf("tiger current pub : %v ",pub)
      ret := pub.Verify(h[:],sig)
      log.Errorf("tiger verify ret : %v ",ret)
      rawTxSig := &RawTxSigWitness{
         Quorum: 1,
         Sigs:   []json.HexBytes{sig},
      }
      var data []witnessComponent
      data = append(data,rawTxSig)
      sigInst.WitnessComponents = append(data, sigInst.WitnessComponents...)
   }
   return materializeWitnesses(tpl)
}

5、解析交易:

func (a *API) PseudohsmDecodeTx(raw types.RawTx) Response {

   tx := &RawTx{
      Version:   raw.Raw.Version,
      Size:      raw.Raw.SerializedSize,
      TimeRange: raw.Raw.TimeRange,
      Inputs:    []*query.AnnotatedInput{},
      Outputs:   []*query.AnnotatedOutput{},
   }
   for i := range raw.Raw.Inputs {
      tx.Inputs = append(tx.Inputs, a.WalletInfo.BuildAnnotatedInput(&raw.Raw, uint32(i)))
   }
   for i := range raw.Raw.Outputs {
      tx.Outputs = append(tx.Outputs, a.WalletInfo.BuildAnnotatedOutput(&raw.Raw, i))
   }

   totalInputBtm := uint64(0)
   totalOutputBtm := uint64(0)
   for _, input := range tx.Inputs {
      if input.AssetID.String() == consensus.BTMAssetID.String() {
         totalInputBtm += input.Amount
      }
   }

   for _, output := range tx.Outputs {
      if output.AssetID.String() == consensus.BTMAssetID.String() {
         totalOutputBtm += output.Amount
      }
   }

   tx.Fee = int64(totalInputBtm) - int64(totalOutputBtm)
   return NewSuccessResponse(tx)
}

 

 

 

你可能感兴趣的:(区块链钱包)