12 "github.com/spf13/cobra"
13 bytomtypes "github.com/vapor/claim/bytom/protocolbc/types"
14 "github.com/vapor/config"
15 chainjson "github.com/vapor/encoding/json"
16 "github.com/vapor/util"
20 var gClaimTxMap map[uint64]claimTx
21 var currentHeight uint64
23 type WSRequest struct {
24 Topic string `json:"topic"`
27 type WSResponse struct {
28 NotificationType string `json:"notification_type"`
29 Data interface{} `json:"data"`
30 ErrorDetail string `json:"error_detail,omitempty"`
34 Password string `json:"password"`
35 RawTx bytomtypes.Tx `json:"raw_transaction"`
36 BlockHeader bytomtypes.BlockHeader `json:"block_header"`
37 TxHashes []chainjson.HexBytes `json:"tx_hashes"`
38 StatusHashes []chainjson.HexBytes `json:"status_hashes"`
39 Flags []uint32 `json:"flags"`
40 MatchedTxIDs []chainjson.HexBytes `json:"matched_tx_ids"`
41 ClaimScript chainjson.HexBytes `json:"claim_script"`
44 var startHeight uint64 = 0
46 var runCmd = &cobra.Command{
48 Short: "monitor claim tx",
53 runCmd.PersistentFlags().Uint64Var(&startHeight, "start_height", 0, "Start monitoring block height for transactions")
56 func run(cmd *cobra.Command, args []string) {
62 if _, err := runCmd.ExecuteC(); err != nil {
63 os.Exit(util.ErrLocalExe)
66 gClaimTxMap = make(map[uint64]claimTx)
69 if err := client.New("127.0.0.1:9888"); err != nil {
74 go getRawTransactionWithHeight()
76 Topic: "notify_raw_blocks",
81 msg, err := client.RecvData()
87 err = json.Unmarshal(msg, &rep)
89 log.Printf("Unmarshal error: %v", err)
92 block := &bytomtypes.Block{}
93 switch rep.NotificationType {
94 case "raw_blocks_connected":
95 data := fmt.Sprint(rep.Data)
96 err = block.UnmarshalText([]byte(data))
100 case "raw_blocks_disconnected":
101 data := fmt.Sprint(rep.Data)
102 err = block.UnmarshalText([]byte(data))
106 case "request_status":
107 if rep.ErrorDetail != "" {
108 log.Println(rep.ErrorDetail)
115 currentHeight = block.Height
116 err := getRawTransaction(block)
127 for k, v := range gClaimTxMap {
128 if k <= currentHeight {
129 resp, exitCode := util.ClientCall("/claim-pegin-transaction", &v)
130 if exitCode != util.Success {
132 delete(gClaimTxMap, k)
137 Txid string `json:"tx_id"`
140 restoreStruct(resp, &out)
142 delete(gClaimTxMap, k)
144 fmt.Println(out.Txid)
145 time.Sleep(3 * time.Second)
152 func restoreStruct(data interface{}, out interface{}) {
153 dataMap, ok := data.(map[string]interface{})
155 fmt.Println("invalid type assertion")
156 os.Exit(util.ErrLocalParse)
159 rawData, err := json.MarshalIndent(dataMap, "", " ")
162 os.Exit(util.ErrLocalParse)
164 json.Unmarshal(rawData, out)
167 func getRawTransaction(block *bytomtypes.Block) error {
168 peginInfo, err := getPeginInfo()
172 for _, tx := range block.Transactions {
173 for _, output := range tx.Outputs {
174 for k, v := range peginInfo {
175 var claimScript chainjson.HexBytes
176 if err := claimScript.UnmarshalText([]byte(k)); err != nil {
179 var controlProgram chainjson.HexBytes
180 if err := controlProgram.UnmarshalText([]byte(v)); err != nil {
184 if !bytes.Equal(output.ControlProgram, controlProgram) {
187 blockHash := block.Hash()
188 merkleProof, err := getMerkleProof(blockHash.String(), tx.ID.String())
195 BlockHeader: merkleProof.BlockHeader,
196 TxHashes: merkleProof.TxHashes,
197 StatusHashes: merkleProof.StatusHashes,
198 Flags: merkleProof.Flags,
199 MatchedTxIDs: merkleProof.MatchedTxIDs,
200 ClaimScript: claimScript,
203 height := block.Height + 6
205 gClaimTxMap[height] = tmp
214 func getRawTransactionWithHeight() {
216 if currentHeight > 0 {
217 num := currentHeight - startHeight
218 for i := uint64(0); i < num; i++ {
219 block, err := getBlockWithHeight(startHeight)
223 err = getRawTransaction(&block)
229 if startHeight >= currentHeight {
233 time.Sleep(1 * time.Second)
237 type MerkleBlockResp struct {
238 BlockHeader bytomtypes.BlockHeader `json:"block_header"`
239 TxHashes []chainjson.HexBytes `json:"tx_hashes"`
240 StatusHashes []chainjson.HexBytes `json:"status_hashes"`
241 Flags []uint32 `json:"flags"`
242 MatchedTxIDs []chainjson.HexBytes `json:"matched_tx_ids"`
245 func getMerkleProof(blockHash string, txId string) (MerkleBlockResp, error) {
246 //body_json = {"tx_id": tx_id,"block_hash": block_hash}
248 TxID string `json:"tx_id"`
249 BlockHash string `json:"block_hash"`
251 util.MainchainConfig = &config.MainChainRpcConfig{
252 MainchainRpcHost: "127.0.0.1",
253 MainchainRpcPort: "9888",
255 var blockHeader MerkleBlockResp
256 resp, err := util.CallRPC("/get-merkle-proof", &Req{TxID: txId, BlockHash: blockHash})
258 return blockHeader, err
260 tmp, _ := json.Marshal(resp)
262 json.Unmarshal(tmp, &blockHeader)
264 return blockHeader, nil
267 func getBlockWithHeight(blockHeight uint64) (bytomtypes.Block, error) {
269 BlockHeight uint64 `json:"block_height"`
271 util.MainchainConfig = &config.MainChainRpcConfig{
272 MainchainRpcHost: "127.0.0.1",
273 MainchainRpcPort: "9888",
275 type RawBlockResp struct {
276 RawBlock *bytomtypes.Block `json:"raw_block"`
278 var block RawBlockResp
279 resp, err := util.CallRPC("/get-raw-block", &Req{BlockHeight: blockHeight})
281 return *block.RawBlock, err
283 tmp, _ := json.Marshal(resp)
285 json.Unmarshal(tmp, &block)
286 return *block.RawBlock, nil