OSDN Git Service

new repo
[bytom/vapor.git] / api / transact.go
1 package api
2
3 import (
4         "bytes"
5         "context"
6         "crypto/hmac"
7         "crypto/sha256"
8         "encoding/json"
9         "math"
10         "strconv"
11         "strings"
12         "time"
13
14         log "github.com/sirupsen/logrus"
15
16         "github.com/vapor/account"
17         "github.com/vapor/blockchain/signers"
18         "github.com/vapor/blockchain/txbuilder"
19         "github.com/vapor/blockchain/txbuilder/mainchain"
20         "github.com/vapor/common"
21         "github.com/vapor/consensus"
22         "github.com/vapor/consensus/segwit"
23         "github.com/vapor/crypto/ed25519/chainkd"
24         "github.com/vapor/crypto/sha3pool"
25         chainjson "github.com/vapor/encoding/json"
26         "github.com/vapor/errors"
27         "github.com/vapor/math/checked"
28         "github.com/vapor/net/http/reqid"
29         "github.com/vapor/protocol/bc"
30         "github.com/vapor/protocol/bc/types"
31         "github.com/vapor/protocol/bc/types/bytom"
32         bytomtypes "github.com/vapor/protocol/bc/types/bytom/types"
33         "github.com/vapor/protocol/vm/vmutil"
34         "github.com/vapor/util"
35 )
36
37 var (
38         defaultTxTTL    = 5 * time.Minute
39         defaultBaseRate = float64(100000)
40         flexibleGas     = int64(1800)
41 )
42
43 func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, error), bool) {
44         decoders := map[string]func([]byte) (txbuilder.Action, error){
45                 "control_address":              txbuilder.DecodeControlAddressAction,
46                 "control_program":              txbuilder.DecodeControlProgramAction,
47                 "issue":                        a.wallet.AssetReg.DecodeIssueAction,
48                 "retire":                       txbuilder.DecodeRetireAction,
49                 "spend_account":                a.wallet.AccountMgr.DecodeSpendAction,
50                 "spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction,
51         }
52         decoder, ok := decoders[action]
53         return decoder, ok
54 }
55
56 func onlyHaveInputActions(req *BuildRequest) (bool, error) {
57         count := 0
58         for i, act := range req.Actions {
59                 actionType, ok := act["type"].(string)
60                 if !ok {
61                         return false, errors.WithDetailf(ErrBadActionType, "no action type provided on action %d", i)
62                 }
63
64                 if strings.HasPrefix(actionType, "spend") || actionType == "issue" {
65                         count++
66                 }
67         }
68
69         return count == len(req.Actions), nil
70 }
71
72 func (a *API) buildSingle(ctx context.Context, req *BuildRequest) (*txbuilder.Template, error) {
73         if err := a.checkRequestValidity(ctx, req); err != nil {
74                 return nil, err
75         }
76         actions, err := a.mergeSpendActions(req)
77         if err != nil {
78                 return nil, err
79         }
80
81         maxTime := time.Now().Add(req.TTL.Duration)
82         tpl, err := txbuilder.Build(ctx, req.Tx, actions, maxTime, req.TimeRange)
83         if errors.Root(err) == txbuilder.ErrAction {
84                 // append each of the inner errors contained in the data.
85                 var Errs string
86                 var rootErr error
87                 for i, innerErr := range errors.Data(err)["actions"].([]error) {
88                         if i == 0 {
89                                 rootErr = errors.Root(innerErr)
90                         }
91                         Errs = Errs + innerErr.Error()
92                 }
93                 err = errors.WithDetail(rootErr, Errs)
94         }
95         if err != nil {
96                 return nil, err
97         }
98
99         // ensure null is never returned for signing instructions
100         if tpl.SigningInstructions == nil {
101                 tpl.SigningInstructions = []*txbuilder.SigningInstruction{}
102         }
103         return tpl, nil
104 }
105
106 // POST /build-transaction
107 func (a *API) build(ctx context.Context, buildReqs *BuildRequest) Response {
108         subctx := reqid.NewSubContext(ctx, reqid.New())
109         tmpl, err := a.buildSingle(subctx, buildReqs)
110         if err != nil {
111                 return NewErrorResponse(err)
112         }
113
114         return NewSuccessResponse(tmpl)
115 }
116 func (a *API) checkRequestValidity(ctx context.Context, req *BuildRequest) error {
117         if err := a.completeMissingIDs(ctx, req); err != nil {
118                 return err
119         }
120
121         if req.TTL.Duration == 0 {
122                 req.TTL.Duration = defaultTxTTL
123         }
124
125         if ok, err := onlyHaveInputActions(req); err != nil {
126                 return err
127         } else if ok {
128                 return errors.WithDetail(ErrBadActionConstruction, "transaction contains only input actions and no output actions")
129         }
130         return nil
131 }
132
133 func (a *API) mergeSpendActions(req *BuildRequest) ([]txbuilder.Action, error) {
134         actions := make([]txbuilder.Action, 0, len(req.Actions))
135         for i, act := range req.Actions {
136                 typ, ok := act["type"].(string)
137                 if !ok {
138                         return nil, errors.WithDetailf(ErrBadActionType, "no action type provided on action %d", i)
139                 }
140                 decoder, ok := a.actionDecoder(typ)
141                 if !ok {
142                         return nil, errors.WithDetailf(ErrBadActionType, "unknown action type %q on action %d", typ, i)
143                 }
144
145                 // Remarshal to JSON, the action may have been modified when we
146                 // filtered aliases.
147                 b, err := json.Marshal(act)
148                 if err != nil {
149                         return nil, err
150                 }
151                 action, err := decoder(b)
152                 if err != nil {
153                         return nil, errors.WithDetailf(ErrBadAction, "%s on action %d", err.Error(), i)
154                 }
155                 actions = append(actions, action)
156         }
157         actions = account.MergeSpendAction(actions)
158         return actions, nil
159 }
160
161 func (a *API) buildTxs(ctx context.Context, req *BuildRequest) ([]*txbuilder.Template, error) {
162         if err := a.checkRequestValidity(ctx, req); err != nil {
163                 return nil, err
164         }
165         actions, err := a.mergeSpendActions(req)
166         if err != nil {
167                 return nil, err
168         }
169
170         builder := txbuilder.NewBuilder(time.Now().Add(req.TTL.Duration))
171         tpls := []*txbuilder.Template{}
172         for _, action := range actions {
173                 if action.ActionType() == "spend_account" {
174                         tpls, err = account.SpendAccountChain(ctx, builder, action)
175                 } else {
176                         err = action.Build(ctx, builder)
177                 }
178
179                 if err != nil {
180                         builder.Rollback()
181                         return nil, err
182                 }
183         }
184
185         tpl, _, err := builder.Build()
186         if err != nil {
187                 builder.Rollback()
188                 return nil, err
189         }
190
191         tpls = append(tpls, tpl)
192         return tpls, nil
193 }
194
195 // POST /build-chain-transactions
196 func (a *API) buildChainTxs(ctx context.Context, buildReqs *BuildRequest) Response {
197         subctx := reqid.NewSubContext(ctx, reqid.New())
198         tmpls, err := a.buildTxs(subctx, buildReqs)
199         if err != nil {
200                 return NewErrorResponse(err)
201         }
202         return NewSuccessResponse(tmpls)
203 }
204
205 type submitTxResp struct {
206         TxID *bc.Hash `json:"tx_id"`
207 }
208
209 // POST /submit-transaction
210 func (a *API) submit(ctx context.Context, ins struct {
211         Tx types.Tx `json:"raw_transaction"`
212 }) Response {
213         if err := txbuilder.FinalizeTx(ctx, a.chain, &ins.Tx); err != nil {
214                 return NewErrorResponse(err)
215         }
216
217         log.WithField("tx_id", ins.Tx.ID.String()).Info("submit single tx")
218         return NewSuccessResponse(&submitTxResp{TxID: &ins.Tx.ID})
219 }
220
221 type submitTxsResp struct {
222         TxID []*bc.Hash `json:"tx_id"`
223 }
224
225 // POST /submit-transactions
226 func (a *API) submitTxs(ctx context.Context, ins struct {
227         Tx []types.Tx `json:"raw_transactions"`
228 }) Response {
229         txHashs := []*bc.Hash{}
230         for i := range ins.Tx {
231                 if err := txbuilder.FinalizeTx(ctx, a.chain, &ins.Tx[i]); err != nil {
232                         return NewErrorResponse(err)
233                 }
234                 log.WithField("tx_id", ins.Tx[i].ID.String()).Info("submit single tx")
235                 txHashs = append(txHashs, &ins.Tx[i].ID)
236         }
237         return NewSuccessResponse(&submitTxsResp{TxID: txHashs})
238 }
239
240 // EstimateTxGasResp estimate transaction consumed gas
241 type EstimateTxGasResp struct {
242         TotalNeu   int64 `json:"total_neu"`
243         StorageNeu int64 `json:"storage_neu"`
244         VMNeu      int64 `json:"vm_neu"`
245 }
246
247 // EstimateTxGas estimate consumed neu for transaction
248 func EstimateTxGas(template txbuilder.Template) (*EstimateTxGasResp, error) {
249         // base tx size and not include sign
250         data, err := template.Transaction.TxData.MarshalText()
251         if err != nil {
252                 return nil, err
253         }
254         baseTxSize := int64(len(data))
255
256         // extra tx size for sign witness parts
257         signSize := estimateSignSize(template.SigningInstructions)
258
259         // total gas for tx storage
260         totalTxSizeGas, ok := checked.MulInt64(baseTxSize+signSize, consensus.StorageGasRate)
261         if !ok {
262                 return nil, errors.New("calculate txsize gas got a math error")
263         }
264
265         // consume gas for run VM
266         totalP2WPKHGas := int64(0)
267         totalP2WSHGas := int64(0)
268         baseP2WPKHGas := int64(1419)
269         // flexible Gas is used for handle need extra utxo situation
270
271         for pos, inpID := range template.Transaction.Tx.InputIDs {
272                 sp, err := template.Transaction.Spend(inpID)
273                 if err != nil {
274                         continue
275                 }
276
277                 resOut, err := template.Transaction.Output(*sp.SpentOutputId)
278                 if err != nil {
279                         continue
280                 }
281
282                 if segwit.IsP2WPKHScript(resOut.ControlProgram.Code) {
283                         totalP2WPKHGas += baseP2WPKHGas
284                 } else if segwit.IsP2WSHScript(resOut.ControlProgram.Code) {
285                         sigInst := template.SigningInstructions[pos]
286                         totalP2WSHGas += estimateP2WSHGas(sigInst)
287                 }
288         }
289
290         // total estimate gas
291         totalGas := totalTxSizeGas + totalP2WPKHGas + totalP2WSHGas + flexibleGas
292
293         // rounding totalNeu with base rate 100000
294         totalNeu := float64(totalGas*consensus.VMGasRate) / defaultBaseRate
295         roundingNeu := math.Ceil(totalNeu)
296         estimateNeu := int64(roundingNeu) * int64(defaultBaseRate)
297
298         // TODO add priority
299
300         return &EstimateTxGasResp{
301                 TotalNeu:   estimateNeu,
302                 StorageNeu: totalTxSizeGas * consensus.VMGasRate,
303                 VMNeu:      (totalP2WPKHGas + totalP2WSHGas) * consensus.VMGasRate,
304         }, nil
305 }
306
307 // estimate p2wsh gas.
308 // OP_CHECKMULTISIG consume (984 * a - 72 * b - 63) gas,
309 // where a represent the num of public keys, and b represent the num of quorum.
310 func estimateP2WSHGas(sigInst *txbuilder.SigningInstruction) int64 {
311         P2WSHGas := int64(0)
312         baseP2WSHGas := int64(738)
313
314         for _, witness := range sigInst.WitnessComponents {
315                 switch t := witness.(type) {
316                 case *txbuilder.SignatureWitness:
317                         P2WSHGas += baseP2WSHGas + (984*int64(len(t.Keys)) - 72*int64(t.Quorum) - 63)
318                 case *txbuilder.RawTxSigWitness:
319                         P2WSHGas += baseP2WSHGas + (984*int64(len(t.Keys)) - 72*int64(t.Quorum) - 63)
320                 }
321         }
322         return P2WSHGas
323 }
324
325 // estimate signature part size.
326 // if need multi-sign, calculate the size according to the length of keys.
327 func estimateSignSize(signingInstructions []*txbuilder.SigningInstruction) int64 {
328         signSize := int64(0)
329         baseWitnessSize := int64(300)
330
331         for _, sigInst := range signingInstructions {
332                 for _, witness := range sigInst.WitnessComponents {
333                         switch t := witness.(type) {
334                         case *txbuilder.SignatureWitness:
335                                 signSize += int64(t.Quorum) * baseWitnessSize
336                         case *txbuilder.RawTxSigWitness:
337                                 signSize += int64(t.Quorum) * baseWitnessSize
338                         }
339                 }
340         }
341         return signSize
342 }
343
344 // POST /estimate-transaction-gas
345 func (a *API) estimateTxGas(ctx context.Context, in struct {
346         TxTemplate txbuilder.Template `json:"transaction_template"`
347 }) Response {
348         txGasResp, err := EstimateTxGas(in.TxTemplate)
349         if err != nil {
350                 return NewErrorResponse(err)
351         }
352         return NewSuccessResponse(txGasResp)
353 }
354
355 func getPeginTxnOutputIndex(rawTx bytomtypes.Tx, controlProg []byte) int {
356         for index, output := range rawTx.Outputs {
357                 if bytes.Equal(output.ControlProgram, controlProg) {
358                         return index
359                 }
360         }
361         return 0
362 }
363
364 func toHash(hexBytes []chainjson.HexBytes) (hashs []*bytom.Hash) {
365         for _, data := range hexBytes {
366                 b32 := [32]byte{}
367                 copy(b32[:], data)
368                 res := bytom.NewHash(b32)
369                 hashs = append(hashs, &res)
370         }
371         return
372 }
373
374 func (a *API) claimPeginTx(ctx context.Context, ins struct {
375         Password     string                 `json:"password"`
376         RawTx        bytomtypes.Tx          `json:"raw_transaction"`
377         BlockHeader  bytomtypes.BlockHeader `json:"block_header"`
378         TxHashes     []chainjson.HexBytes   `json:"tx_hashes"`
379         StatusHashes []chainjson.HexBytes   `json:"status_hashes"`
380         Flags        []uint32               `json:"flags"`
381         MatchedTxIDs []chainjson.HexBytes   `json:"matched_tx_ids"`
382         ClaimScript  chainjson.HexBytes     `json:"claim_script"`
383 }) Response {
384         tmpl, err := a.createrawpegin(ctx, ins)
385         if err != nil {
386                 log.WithField("build err", err).Error("fail on createrawpegin.")
387                 return NewErrorResponse(err)
388         }
389         // 交易签名
390         if err := txbuilder.Sign(ctx, tmpl, ins.Password, a.PseudohsmSignTemplate); err != nil {
391                 log.WithField("build err", err).Error("fail on sign transaction.")
392                 return NewErrorResponse(err)
393         }
394
395         // submit
396         if err := txbuilder.FinalizeTx(ctx, a.chain, tmpl.Transaction); err != nil {
397                 return NewErrorResponse(err)
398         }
399
400         log.WithField("tx_id", tmpl.Transaction.ID.String()).Info("claim script tx")
401         return NewSuccessResponse(&submitTxResp{TxID: &tmpl.Transaction.ID})
402 }
403
404 // GetMerkleBlockResp is resp struct for GetTxOutProof API
405 type GetMerkleBlock struct {
406         BlockHeader  bytomtypes.BlockHeader `json:"block_header"`
407         TxHashes     []chainjson.HexBytes   `json:"tx_hashes"`
408         StatusHashes []chainjson.HexBytes   `json:"status_hashes"`
409         Flags        []uint32               `json:"flags"`
410         MatchedTxIDs []chainjson.HexBytes   `json:"matched_tx_ids"`
411 }
412
413 func (a *API) createrawpegin(ctx context.Context, ins struct {
414         Password     string                 `json:"password"`
415         RawTx        bytomtypes.Tx          `json:"raw_transaction"`
416         BlockHeader  bytomtypes.BlockHeader `json:"block_header"`
417         TxHashes     []chainjson.HexBytes   `json:"tx_hashes"`
418         StatusHashes []chainjson.HexBytes   `json:"status_hashes"`
419         Flags        []uint32               `json:"flags"`
420         MatchedTxIDs []chainjson.HexBytes   `json:"matched_tx_ids"`
421         ClaimScript  chainjson.HexBytes     `json:"claim_script"`
422 }) (*txbuilder.Template, error) {
423         // proof验证
424         var flags []uint8
425         for flag := range ins.Flags {
426                 flags = append(flags, uint8(flag))
427         }
428         txHashes := toHash(ins.TxHashes)
429         matchedTxIDs := toHash(ins.MatchedTxIDs)
430         if !bytomtypes.ValidateTxMerkleTreeProof(txHashes, flags, matchedTxIDs, ins.BlockHeader.BlockCommitment.TransactionsMerkleRoot) {
431                 return nil, errors.New("Merkleblock validation failed")
432         }
433         // CheckBytomProof
434         //difficulty.CheckBytomProofOfWork(ins.BlockHeader.Hash(), ins.BlockHeader)
435         // 增加spv验证以及连接主链api查询交易的确认数
436         if util.ValidatePegin {
437                 if err := util.IsConfirmedBytomBlock(ins.BlockHeader.Height, consensus.ActiveNetParams.PeginMinDepth); err != nil {
438                         return nil, err
439                 }
440         }
441         // 找出与claim script有关联的交易的输出
442         var claimScript []byte
443         nOut := len(ins.RawTx.Outputs)
444         if ins.ClaimScript == nil {
445                 // 遍历寻找与交易输出有关的claim script
446                 cps, err := a.wallet.AccountMgr.ListControlProgram()
447                 if err != nil {
448                         return nil, err
449                 }
450
451                 for _, cp := range cps {
452                         _, controlProg := a.wallet.AccountMgr.GetPeginControlPrograms(cp.ControlProgram)
453                         if controlProg == nil {
454                                 continue
455                         }
456                         // 获取交易的输出
457                         nOut = getPeginTxnOutputIndex(ins.RawTx, controlProg)
458                         if nOut != len(ins.RawTx.Outputs) {
459                                 claimScript = cp.ControlProgram
460                         }
461                 }
462         } else {
463                 claimScript = ins.ClaimScript
464                 _, controlProg := a.wallet.AccountMgr.GetPeginControlPrograms(claimScript)
465                 // 获取交易的输出
466                 nOut = getPeginTxnOutputIndex(ins.RawTx, controlProg)
467         }
468         if nOut == len(ins.RawTx.Outputs) {
469                 return nil, errors.New("Failed to find output in bytom to the mainchain_address from getpeginaddress")
470         }
471
472         // 根据ClaimScript 获取account id
473         var hash [32]byte
474         sha3pool.Sum256(hash[:], claimScript)
475         data := a.wallet.DB.Get(account.ContractKey(hash))
476         if data == nil {
477                 return nil, errors.New("Failed to find control program through claim script")
478         }
479
480         cp := &account.CtrlProgram{}
481         if err := json.Unmarshal(data, cp); err != nil {
482                 return nil, errors.New("Failed on unmarshal control program")
483         }
484
485         // 构造交易
486         // 用输出作为交易输入 生成新的交易
487         builder := txbuilder.NewBuilder(time.Now())
488         // TODO 根据raw tx生成一个utxo
489         //txInput := types.NewClaimInputInput(nil, *ins.RawTx.Outputs[nOut].AssetId, ins.RawTx.Outputs[nOut].Amount, cp.ControlProgram)
490         assetId := bc.AssetID{}
491         assetId.V0 = ins.RawTx.Outputs[nOut].AssetId.GetV0()
492         assetId.V1 = ins.RawTx.Outputs[nOut].AssetId.GetV1()
493         assetId.V2 = ins.RawTx.Outputs[nOut].AssetId.GetV2()
494         assetId.V3 = ins.RawTx.Outputs[nOut].AssetId.GetV3()
495
496         sourceID := bc.Hash{}
497         sourceID.V0 = ins.RawTx.OutputID(nOut).GetV0()
498         sourceID.V1 = ins.RawTx.OutputID(nOut).GetV1()
499         sourceID.V2 = ins.RawTx.OutputID(nOut).GetV2()
500         sourceID.V3 = ins.RawTx.OutputID(nOut).GetV3()
501         outputAccount := ins.RawTx.Outputs[nOut].Amount
502
503         txInput := types.NewClaimInputInput(nil, sourceID, assetId, outputAccount, uint64(nOut), cp.ControlProgram)
504         if err := builder.AddInput(txInput, &txbuilder.SigningInstruction{}); err != nil {
505                 return nil, err
506         }
507         program, err := a.wallet.AccountMgr.CreateAddress(cp.AccountID, false)
508         if err != nil {
509                 return nil, err
510         }
511
512         if err = builder.AddOutput(types.NewTxOutput(assetId, outputAccount, program.ControlProgram)); err != nil {
513                 return nil, err
514         }
515
516         tmpl, txData, err := builder.Build()
517         if err != nil {
518                 return nil, err
519         }
520
521         // todo把一些主链的信息加到交易的stack中
522         var stack [][]byte
523
524         //amount
525         amount := strconv.FormatUint(ins.RawTx.Outputs[nOut].Amount, 10)
526         stack = append(stack, []byte(amount))
527         // 主链的gennesisBlockHash
528         stack = append(stack, []byte(consensus.ActiveNetParams.ParentGenesisBlockHash))
529         // claim script
530         stack = append(stack, claimScript)
531         // raw tx
532         tx, _ := json.Marshal(ins.RawTx)
533         stack = append(stack, tx)
534         // proof
535         MerkleBLock := GetMerkleBlock{
536                 BlockHeader:  ins.BlockHeader,
537                 TxHashes:     ins.TxHashes,
538                 StatusHashes: ins.StatusHashes,
539                 Flags:        ins.Flags,
540                 MatchedTxIDs: ins.MatchedTxIDs,
541         }
542         txOutProof, _ := json.Marshal(MerkleBLock)
543         stack = append(stack, txOutProof)
544
545         //      tmpl.Transaction.Inputs[0].Peginwitness = stack
546         txData.Inputs[0].Peginwitness = stack
547
548         //交易费估算
549         txGasResp, err := EstimateTxGas(*tmpl)
550         if err != nil {
551                 return nil, err
552         }
553         txData.Outputs[0].Amount = txData.Outputs[0].Amount - uint64(txGasResp.TotalNeu)
554         //重设置Transaction
555         tmpl.Transaction = types.NewTx(*txData)
556         return tmpl, nil
557 }
558
559 func (a *API) buildMainChainTx(ins struct {
560         Utxo           account.UTXO       `json:"utxo"`
561         Tx             types.Tx           `json:"raw_transaction"`
562         RootXPubs      []chainkd.XPub     `json:"root_xpubs"`
563         Alias          string             `json:"alias"`
564         ControlProgram string             `json:"control_program"`
565         ClaimScript    chainjson.HexBytes `json:"claim_script"`
566 }) Response {
567
568         var xpubs []chainkd.XPub
569         for _, xpub := range ins.RootXPubs {
570                 // pub + scriptPubKey 生成一个随机数A
571                 var tmp [32]byte
572                 h := hmac.New(sha256.New, xpub[:])
573                 h.Write(ins.ClaimScript)
574                 tweak := h.Sum(tmp[:])
575                 // pub +  A 生成一个新的公钥pub_new
576                 chaildXPub := xpub.Child(tweak)
577                 xpubs = append(xpubs, chaildXPub)
578         }
579         acc := &account.Account{}
580         var err error
581         if acc, err = a.wallet.AccountMgr.FindByAlias(ins.Alias); err != nil {
582                 acc, err = a.wallet.AccountMgr.Create(xpubs, len(xpubs), ins.Alias, signers.BIP0044)
583                 if err != nil {
584                         return NewErrorResponse(err)
585                 }
586         }
587         ins.Utxo.ControlProgramIndex = acc.Signer.KeyIndex
588
589         txInput, sigInst, err := utxoToInputs(acc.Signer, &ins.Utxo)
590         if err != nil {
591                 return NewErrorResponse(err)
592         }
593
594         builder := mainchain.NewBuilder(time.Now())
595         builder.AddInput(txInput, sigInst)
596         changeAmount := uint64(0)
597         retire := false
598         for _, key := range ins.Tx.GetResultIds() {
599                 output, err := ins.Tx.Retire(*key)
600                 if err != nil {
601                         log.WithFields(log.Fields{"moudle": "transact", "err": err}).Warn("buildMainChainTx error")
602                         continue
603                 }
604                 retire = true
605                 var controlProgram []byte
606                 retBool := true
607                 if controlProgram, retBool = getInput(ins.Tx.Entries, *key, ins.ControlProgram); !retBool {
608                         return NewErrorResponse(errors.New("The corresponding input cannot be found"))
609                 }
610
611                 assetID := bytom.AssetID{
612                         V0: output.Source.Value.AssetId.GetV0(),
613                         V1: output.Source.Value.AssetId.GetV1(),
614                         V2: output.Source.Value.AssetId.GetV2(),
615                         V3: output.Source.Value.AssetId.GetV3(),
616                 }
617                 out := bytomtypes.NewTxOutput(assetID, output.Source.Value.Amount, controlProgram)
618                 builder.AddOutput(out)
619                 changeAmount = ins.Utxo.Amount - output.Source.Value.Amount
620
621         }
622
623         if !retire {
624                 return NewErrorResponse(errors.New("It's not a transaction to retire assets"))
625         }
626
627         if changeAmount > 0 {
628                 u := ins.Utxo
629                 assetID := bytom.AssetID{
630                         V0: u.AssetID.GetV0(),
631                         V1: u.AssetID.GetV1(),
632                         V2: u.AssetID.GetV2(),
633                         V3: u.AssetID.GetV3(),
634                 }
635                 out := bytomtypes.NewTxOutput(assetID, changeAmount, ins.Utxo.ControlProgram)
636                 builder.AddOutput(out)
637         }
638
639         tmpl, tx, err := builder.Build()
640         if err != nil {
641                 return NewErrorResponse(err)
642         }
643         //交易费估算
644         txGasResp, err := EstimateTxGasForMainchain(*tmpl)
645         if err != nil {
646                 return NewErrorResponse(err)
647         }
648         for i, out := range tmpl.Transaction.Outputs {
649                 if bytes.Equal(out.ControlProgram, ins.Utxo.ControlProgram) {
650                         tx.Outputs[i].Amount = changeAmount - uint64(txGasResp.TotalNeu)
651                 }
652         }
653         tmpl.Transaction = bytomtypes.NewTx(*tx)
654         return NewSuccessResponse(tmpl)
655 }
656
657 //
658 func getInput(entry map[bc.Hash]bc.Entry, outputID bc.Hash, controlProgram string) ([]byte, bool) {
659         output := entry[outputID].(*bc.Retirement)
660         mux := entry[*output.Source.Ref].(*bc.Mux)
661
662         for _, valueSource := range mux.GetSources() {
663                 spend := entry[*valueSource.Ref].(*bc.Spend)
664                 prevout := entry[*spend.SpentOutputId].(*bc.Output)
665
666                 var ctrlProgram chainjson.HexBytes
667                 ctrlProgram = prevout.ControlProgram.Code
668                 tmp, _ := ctrlProgram.MarshalText()
669                 if string(tmp) == controlProgram {
670                         return ctrlProgram, true
671                 }
672         }
673         return nil, false
674 }
675
676 // UtxoToInputs convert an utxo to the txinput
677 func utxoToInputs(signer *signers.Signer, u *account.UTXO) (*bytomtypes.TxInput, *mainchain.SigningInstruction, error) {
678         sourceID := bytom.Hash{
679                 V0: u.SourceID.GetV0(),
680                 V1: u.SourceID.GetV1(),
681                 V2: u.SourceID.GetV2(),
682                 V3: u.SourceID.GetV3(),
683         }
684
685         assetID := bytom.AssetID{
686                 V0: u.AssetID.GetV0(),
687                 V1: u.AssetID.GetV1(),
688                 V2: u.AssetID.GetV2(),
689                 V3: u.AssetID.GetV3(),
690         }
691
692         txInput := bytomtypes.NewSpendInput(nil, sourceID, assetID, u.Amount, u.SourcePos, u.ControlProgram)
693         sigInst := &mainchain.SigningInstruction{}
694         if signer == nil {
695                 return txInput, sigInst, nil
696         }
697
698         // TODO  u.Change看怎么填写
699         path, _ := signers.Path(signer, signers.AccountKeySpace, u.Change, u.ControlProgramIndex)
700         if u.Address == "" {
701                 sigInst.AddWitnessKeys(signer.XPubs, path, signer.Quorum)
702                 return txInput, sigInst, nil
703         }
704
705         address, err := common.DecodeBytomAddress(u.Address, &consensus.ActiveNetParams)
706         if err != nil {
707                 return nil, nil, err
708         }
709
710         switch address.(type) {
711         case *common.AddressWitnessPubKeyHash:
712                 sigInst.AddRawWitnessKeys(signer.XPubs, path, signer.Quorum)
713                 derivedXPubs := chainkd.DeriveXPubs(signer.XPubs, path)
714                 derivedPK := derivedXPubs[0].PublicKey()
715                 sigInst.WitnessComponents = append(sigInst.WitnessComponents, mainchain.DataWitness([]byte(derivedPK)))
716
717         case *common.AddressWitnessScriptHash:
718                 sigInst.AddRawWitnessKeys(signer.XPubs, path, signer.Quorum)
719                 //path := signers.Path(signer, signers.AccountKeySpace, u.ControlProgramIndex)
720                 //derivedXPubs := chainkd.DeriveXPubs(signer.XPubs, path)
721                 derivedXPubs := signer.XPubs
722                 derivedPKs := chainkd.XPubKeys(derivedXPubs)
723                 script, err := vmutil.P2SPMultiSigProgram(derivedPKs, signer.Quorum)
724                 if err != nil {
725                         return nil, nil, err
726                 }
727                 sigInst.WitnessComponents = append(sigInst.WitnessComponents, mainchain.DataWitness(script))
728
729         default:
730                 return nil, nil, errors.New("unsupport address type")
731         }
732
733         return txInput, sigInst, nil
734 }
735
736 type signRespForMainchain struct {
737         Tx           *mainchain.Template `json:"transaction"`
738         SignComplete bool                `json:"sign_complete"`
739 }
740
741 func (a *API) signWithKey(ins struct {
742         Xprv        string             `json:"xprv"`
743         XPub        chainkd.XPub       `json:"xpub"`
744         Txs         mainchain.Template `json:"transaction"`
745         ClaimScript chainjson.HexBytes `json:"claim_script"`
746 }) Response {
747         xprv := &chainkd.XPrv{}
748         if err := xprv.UnmarshalText([]byte(ins.Xprv)); err != nil {
749                 return NewErrorResponse(err)
750         }
751         // pub + scriptPubKey 生成一个随机数A
752         var tmp [32]byte
753         h := hmac.New(sha256.New, ins.XPub[:])
754         h.Write(ins.ClaimScript)
755         tweak := h.Sum(tmp[:])
756         // pub +  A 生成一个新的公钥pub_new
757         privateKey := xprv.Child(tweak, false)
758
759         if err := sign(&ins.Txs, privateKey); err != nil {
760                 return NewErrorResponse(err)
761         }
762         log.Info("Sign Transaction complete.")
763         log.Info(mainchain.SignProgress(&ins.Txs))
764         return NewSuccessResponse(&signRespForMainchain{Tx: &ins.Txs, SignComplete: mainchain.SignProgress(&ins.Txs)})
765 }
766
767 func sign(tmpl *mainchain.Template, xprv chainkd.XPrv) error {
768         for i, sigInst := range tmpl.SigningInstructions {
769                 for j, wc := range sigInst.WitnessComponents {
770                         switch sw := wc.(type) {
771                         case *mainchain.SignatureWitness:
772                                 err := sw.Sign(tmpl, uint32(i), xprv)
773                                 if err != nil {
774                                         return errors.WithDetailf(err, "adding signature(s) to signature witness component %d of input %d", j, i)
775                                 }
776                         case *mainchain.RawTxSigWitness:
777                                 err := sw.Sign(tmpl, uint32(i), xprv)
778                                 if err != nil {
779                                         return errors.WithDetailf(err, "adding signature(s) to raw-signature witness component %d of input %d", j, i)
780                                 }
781                         }
782                 }
783         }
784         return materializeWitnesses(tmpl)
785 }
786
787 func materializeWitnesses(txTemplate *mainchain.Template) error {
788         msg := txTemplate.Transaction
789
790         if msg == nil {
791                 return errors.Wrap(txbuilder.ErrMissingRawTx)
792         }
793
794         if len(txTemplate.SigningInstructions) > len(msg.Inputs) {
795                 return errors.Wrap(txbuilder.ErrBadInstructionCount)
796         }
797
798         for i, sigInst := range txTemplate.SigningInstructions {
799                 if msg.Inputs[sigInst.Position] == nil {
800                         return errors.WithDetailf(txbuilder.ErrBadTxInputIdx, "signing instruction %d references missing tx input %d", i, sigInst.Position)
801                 }
802
803                 var witness [][]byte
804                 for j, wc := range sigInst.WitnessComponents {
805                         err := wc.Materialize(&witness)
806                         if err != nil {
807                                 return errors.WithDetailf(err, "error in witness component %d of input %d", j, i)
808                         }
809                 }
810                 msg.SetInputArguments(sigInst.Position, witness)
811         }
812
813         return nil
814 }