10 log "github.com/sirupsen/logrus"
11 "github.com/vapor/account"
12 "github.com/vapor/blockchain/txbuilder"
13 "github.com/vapor/consensus"
14 "github.com/vapor/crypto/sha3pool"
15 chainjson "github.com/vapor/encoding/json"
16 "github.com/vapor/errors"
17 "github.com/vapor/protocol/bc"
18 "github.com/vapor/protocol/bc/types"
19 bytomtypes "github.com/vapor/protocol/bc/types/bytom/types"
20 "github.com/vapor/protocol/validation"
21 "github.com/vapor/util"
24 func getPeginTxnOutputIndex(rawTx bytomtypes.Tx, controlProg []byte) int {
25 for index, output := range rawTx.Outputs {
26 if bytes.Equal(output.ControlProgram, controlProg) {
33 func toHash(hexBytes []chainjson.HexBytes) (hashs []*bc.Hash) {
34 for _, data := range hexBytes {
37 res := bc.NewHash(b32)
38 hashs = append(hashs, &res)
43 func (a *API) claimPeginTx(ctx context.Context, ins struct {
44 Password string `json:"password"`
45 RawTx bytomtypes.Tx `json:"raw_transaction"`
46 BlockHeader bytomtypes.BlockHeader `json:"block_header"`
47 TxHashes []chainjson.HexBytes `json:"tx_hashes"`
48 StatusHashes []chainjson.HexBytes `json:"status_hashes"`
49 Flags []uint32 `json:"flags"`
50 MatchedTxIDs []chainjson.HexBytes `json:"matched_tx_ids"`
51 ClaimScript chainjson.HexBytes `json:"claim_script"`
53 tmpl, err := a.createRawPegin(ctx, ins)
55 log.WithField("build err", err).Error("fail on createrawpegin.")
56 return NewErrorResponse(err)
59 if err := txbuilder.Sign(ctx, tmpl, ins.Password, a.PseudohsmSignTemplate); err != nil {
60 log.WithField("build err", err).Error("fail on sign transaction.")
61 return NewErrorResponse(err)
65 if err := txbuilder.FinalizeTx(ctx, a.chain, tmpl.Transaction); err != nil {
66 return NewErrorResponse(err)
69 log.WithField("tx_id", tmpl.Transaction.ID.String()).Info("claim script tx")
70 return NewSuccessResponse(&submitTxResp{TxID: &tmpl.Transaction.ID})
73 func (a *API) createRawPegin(ctx context.Context, ins struct {
74 Password string `json:"password"`
75 RawTx bytomtypes.Tx `json:"raw_transaction"`
76 BlockHeader bytomtypes.BlockHeader `json:"block_header"`
77 TxHashes []chainjson.HexBytes `json:"tx_hashes"`
78 StatusHashes []chainjson.HexBytes `json:"status_hashes"`
79 Flags []uint32 `json:"flags"`
80 MatchedTxIDs []chainjson.HexBytes `json:"matched_tx_ids"`
81 ClaimScript chainjson.HexBytes `json:"claim_script"`
82 }) (*txbuilder.Template, error) {
85 for flag := range ins.Flags {
86 flags = append(flags, uint8(flag))
88 txHashes := toHash(ins.TxHashes)
89 matchedTxIDs := toHash(ins.MatchedTxIDs)
90 statusHashes := toHash(ins.StatusHashes)
91 if !types.ValidateTxMerkleTreeProof(txHashes, flags, matchedTxIDs, ins.BlockHeader.BlockCommitment.TransactionsMerkleRoot) {
92 return nil, errors.New("Merkleblock validation failed")
95 //difficulty.CheckBytomProofOfWork(ins.BlockHeader.Hash(), ins.BlockHeader)
96 // 增加spv验证以及连接主链api查询交易的确认数
97 if util.ValidatePegin {
98 if err := util.IsConfirmedBytomBlock(ins.BlockHeader.Height, consensus.ActiveNetParams.PeginMinDepth); err != nil {
102 // 找出与claim script有关联的交易的输出
103 var claimScript []byte
104 nOut := len(ins.RawTx.Outputs)
105 if ins.ClaimScript == nil {
106 // 遍历寻找与交易输出有关的claim script
107 cps, err := a.wallet.AccountMgr.ListControlProgram()
112 for _, cp := range cps {
113 _, controlProg := a.wallet.AccountMgr.GetPeginControlPrograms(cp.ControlProgram)
114 if controlProg == nil {
118 nOut = getPeginTxnOutputIndex(ins.RawTx, controlProg)
119 if nOut != len(ins.RawTx.Outputs) {
120 claimScript = cp.ControlProgram
124 claimScript = ins.ClaimScript
125 _, controlProg := a.wallet.AccountMgr.GetPeginControlPrograms(claimScript)
127 nOut = getPeginTxnOutputIndex(ins.RawTx, controlProg)
129 if nOut == len(ins.RawTx.Outputs) || nOut == -1 {
130 return nil, errors.New("Failed to find output in bytom to the mainchain_address from getpeginaddress")
133 // 根据ClaimScript 获取account id
135 sha3pool.Sum256(hash[:], claimScript)
136 data := a.wallet.DB.Get(account.ContractKey(hash))
138 return nil, errors.New("Failed to find control program through claim script")
141 cp := &account.CtrlProgram{}
142 if err := json.Unmarshal(data, cp); err != nil {
143 return nil, errors.New("Failed on unmarshal control program")
148 builder := txbuilder.NewBuilder(time.Now())
149 // TODO 根据raw tx生成一个utxo
150 sourceID := *ins.RawTx.OutputID(nOut)
151 outputAccount := ins.RawTx.Outputs[nOut].Amount
152 assetID := *ins.RawTx.Outputs[nOut].AssetId
154 txInput := types.NewClaimInput(nil, sourceID, assetID, outputAccount, uint64(nOut), cp.ControlProgram)
155 if err := builder.AddInput(txInput, &txbuilder.SigningInstruction{}); err != nil {
158 program, err := a.wallet.AccountMgr.CreateAddress(cp.AccountID, false)
163 if err = builder.AddOutput(types.NewTxOutput(assetID, outputAccount, program.ControlProgram)); err != nil {
167 tmpl, txData, err := builder.Build()
172 // todo把一些主链的信息加到交易的stack中
176 amount := strconv.FormatUint(ins.RawTx.Outputs[nOut].Amount, 10)
177 stack = append(stack, []byte(amount))
178 // 主链的gennesisBlockHash
179 stack = append(stack, []byte(consensus.ActiveNetParams.ParentGenesisBlockHash))
181 stack = append(stack, claimScript)
183 tx, _ := json.Marshal(ins.RawTx)
184 stack = append(stack, tx)
186 blockHeader, err := ins.BlockHeader.MarshalText()
190 merkleBlock := validation.MerkleBlock{
191 BlockHeader: blockHeader,
193 StatusHashes: statusHashes,
195 MatchedTxIDs: matchedTxIDs,
198 txOutProof, _ := json.Marshal(merkleBlock)
200 stack = append(stack, txOutProof)
202 // tmpl.Transaction.Inputs[0].Peginwitness = stack
203 txData.Inputs[0].Peginwitness = stack
206 txGasResp, err := EstimateTxGas(*tmpl)
210 txData.Outputs[0].Amount = txData.Outputs[0].Amount - uint64(txGasResp.TotalNeu)
212 tmpl.Transaction = types.NewTx(*txData)
216 func (a *API) claimContractPeginTx(ctx context.Context, ins struct {
217 Password string `json:"password"`
218 RawTx bytomtypes.Tx `json:"raw_transaction"`
219 BlockHeader bytomtypes.BlockHeader `json:"block_header"`
220 TxHashes []chainjson.HexBytes `json:"tx_hashes"`
221 StatusHashes []chainjson.HexBytes `json:"status_hashes"`
222 Flags []uint32 `json:"flags"`
223 MatchedTxIDs []chainjson.HexBytes `json:"matched_tx_ids"`
224 ClaimScript chainjson.HexBytes `json:"claim_script"`
226 tmpl, err := a.createContractRawPegin(ctx, ins)
228 log.WithField("build err", err).Error("fail on claimContractPeginTx.")
229 return NewErrorResponse(err)
232 if err := txbuilder.Sign(ctx, tmpl, ins.Password, a.PseudohsmSignTemplate); err != nil {
233 log.WithField("build err", err).Error("fail on sign transaction.")
234 return NewErrorResponse(err)
238 if err := txbuilder.FinalizeTx(ctx, a.chain, tmpl.Transaction); err != nil {
239 return NewErrorResponse(err)
242 log.WithField("tx_id", tmpl.Transaction.ID.String()).Info("claim script tx")
243 return NewSuccessResponse(&submitTxResp{TxID: &tmpl.Transaction.ID})
246 func (a *API) createContractRawPegin(ctx context.Context, ins struct {
247 Password string `json:"password"`
248 RawTx bytomtypes.Tx `json:"raw_transaction"`
249 BlockHeader bytomtypes.BlockHeader `json:"block_header"`
250 TxHashes []chainjson.HexBytes `json:"tx_hashes"`
251 StatusHashes []chainjson.HexBytes `json:"status_hashes"`
252 Flags []uint32 `json:"flags"`
253 MatchedTxIDs []chainjson.HexBytes `json:"matched_tx_ids"`
254 ClaimScript chainjson.HexBytes `json:"claim_script"`
255 }) (*txbuilder.Template, error) {
258 for flag := range ins.Flags {
259 flags = append(flags, uint8(flag))
261 txHashes := toHash(ins.TxHashes)
262 matchedTxIDs := toHash(ins.MatchedTxIDs)
263 statusHashes := toHash(ins.StatusHashes)
264 if !types.ValidateTxMerkleTreeProof(txHashes, flags, matchedTxIDs, ins.BlockHeader.BlockCommitment.TransactionsMerkleRoot) {
265 return nil, errors.New("Merkleblock validation failed")
268 //difficulty.CheckBytomProofOfWork(ins.BlockHeader.Hash(), ins.BlockHeader)
269 // 增加spv验证以及连接主链api查询交易的确认数
270 if util.ValidatePegin {
271 if err := util.IsConfirmedBytomBlock(ins.BlockHeader.Height, consensus.ActiveNetParams.PeginMinDepth); err != nil {
275 // 找出与claim script有关联的交易的输出
276 var claimScript []byte
277 nOut := len(ins.RawTx.Outputs)
278 if ins.ClaimScript == nil {
279 // 遍历寻找与交易输出有关的claim script
280 cps, err := a.wallet.AccountMgr.ListControlProgram()
285 for _, cp := range cps {
286 _, controlProg := a.wallet.AccountMgr.GetPeginContractControlPrograms(claimScript)
288 nOut = getPeginTxnOutputIndex(ins.RawTx, controlProg)
289 if nOut != len(ins.RawTx.Outputs) {
290 claimScript = cp.ControlProgram
294 claimScript = ins.ClaimScript
295 _, controlProg := a.wallet.AccountMgr.GetPeginContractControlPrograms(claimScript)
297 nOut = getPeginTxnOutputIndex(ins.RawTx, controlProg)
299 if nOut == len(ins.RawTx.Outputs) || nOut == -1 {
300 return nil, errors.New("Failed to find output in bytom to the mainchain_address from createContractRawPegin")
303 // 根据ClaimScript 获取account id
305 sha3pool.Sum256(hash[:], claimScript)
306 data := a.wallet.DB.Get(account.ContractKey(hash))
308 return nil, errors.New("Failed to find control program through claim script")
311 cp := &account.CtrlProgram{}
312 if err := json.Unmarshal(data, cp); err != nil {
313 return nil, errors.New("Failed on unmarshal control program")
318 builder := txbuilder.NewBuilder(time.Now())
319 // TODO 根据raw tx生成一个utxo
321 sourceID := *ins.RawTx.OutputID(nOut)
322 outputAccount := ins.RawTx.Outputs[nOut].Amount
323 assetID := *ins.RawTx.Outputs[nOut].AssetId
325 txInput := types.NewClaimInput(nil, sourceID, assetID, outputAccount, uint64(nOut), cp.ControlProgram)
326 if err := builder.AddInput(txInput, &txbuilder.SigningInstruction{}); err != nil {
329 program, err := a.wallet.AccountMgr.CreateAddress(cp.AccountID, false)
334 if err = builder.AddOutput(types.NewTxOutput(assetID, outputAccount, program.ControlProgram)); err != nil {
338 tmpl, txData, err := builder.Build()
343 // todo把一些主链的信息加到交易的stack中
347 amount := strconv.FormatUint(ins.RawTx.Outputs[nOut].Amount, 10)
348 stack = append(stack, []byte(amount))
349 // 主链的gennesisBlockHash
350 stack = append(stack, []byte(consensus.ActiveNetParams.ParentGenesisBlockHash))
352 stack = append(stack, claimScript)
354 tx, _ := ins.RawTx.MarshalText()
355 //tx, _ := json.Marshal(ins.RawTx)
356 stack = append(stack, tx)
358 blockHeader, err := ins.BlockHeader.MarshalText()
362 merkleBlock := validation.MerkleBlock{
363 BlockHeader: blockHeader,
365 StatusHashes: statusHashes,
367 MatchedTxIDs: matchedTxIDs,
369 txOutProof, _ := json.Marshal(merkleBlock)
370 stack = append(stack, txOutProof)
371 // tmpl.Transaction.Inputs[0].Peginwitness = stack
372 txData.Inputs[0].Peginwitness = stack
375 txGasResp, err := EstimateTxGas(*tmpl)
379 txData.Outputs[0].Amount = txData.Outputs[0].Amount - uint64(txGasResp.TotalNeu)
381 tmpl.Transaction = types.NewTx(*txData)