1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use lifeline::Sender;
use microkv::namespace::NamespaceMicroKV;

use crate::bridge::{Extrinsic, ToExtrinsicsMessage};
use crate::service::pangolin::types::ScanDataWrapper;

pub struct ScanScheduleMMRRootEvent<'a> {
    data: &'a mut ScanDataWrapper,
    microkv: NamespaceMicroKV,
}

impl<'a> ScanScheduleMMRRootEvent<'a> {
    pub fn new(data: &'a mut ScanDataWrapper, microkv: NamespaceMicroKV) -> Self {
        Self { data, microkv }
    }
}

impl<'a> ScanScheduleMMRRootEvent<'a> {
    pub async fn handle(&mut self) -> color_eyre::Result<()> {
        let event = self
            .data
            .subquery
            .query_latest_schedule_mmr_root_event()
            .await?;
        if event.is_none() {
            tracing::info!(
                target: "pangolin-ropsten",
                "[pangolin] [schedule-mmr-root] Not have more ScheduleMMRRootEvent"
            );
            return Ok(());
        }
        let latest = event.unwrap();
        if latest.emitted == 1 {
            tracing::info!(
                target: "pangolin-ropsten",
                "[pangolin] [schedule-mmr-root] The latest ScheduleMMRRootEvent is emitted. event block is: {} and at block: {}. nothing to do.",
                latest.event_block_number,
                latest.at_block_number
            );
            return Ok(());
        }
        if latest.outdated == 1 {
            tracing::info!(
                target: "pangolin-ropsten",
                "[pangolin] [schedule-mmr-root]The latest ScheduleMMRRootEvent is outdated. event block is: {} and at block: {}. nothing to do.",
                latest.event_block_number,
                latest.at_block_number
            );
            return Ok(());
        }

        tracing::info!(
            target: "pangolin-ropsten",
            "[pangolin] [schedule-mmr-root] Queried latest ScheduleMMRRootEvent event block is: {} and at block: {}",
            latest.event_block_number,
            latest.at_block_number
        );

        let event_block_number = latest.event_block_number;

        let client = &self.data.pangolin;
        let finalized_block_hash = client.subxt().rpc().finalized_head().await?;
        let block = client
            .subxt()
            .rpc()
            .block(Some(finalized_block_hash))
            .await?;
        let finalized_block_header_number = match block {
            Some(v) => v.block.header.number,
            None => {
                tracing::warn!(
                    target: "pangolin-ropsten",
                    "[pangolin] [schedule-mmr-root] Can not get last block header by finalized block hash: {}",
                    finalized_block_hash
                );
                return Ok(());
            }
        };

        if finalized_block_header_number < event_block_number {
            tracing::info!(
                target: "pangolin-ropsten",
                "[pangolin] [schedule-mmr-root] The finalized block number ({}) less than event block number ({}). do nothing.",
                finalized_block_header_number,
                event_block_number
            );
            return Ok(());
        }

        let saved_latest: Option<u32> = self.microkv.get_as("latest_mmr_root_sign")?;
        if Some(event_block_number) == saved_latest {
            tracing::info!(
                target: "pangolin-ropsten",
                "[pangolin] [schedule-mmr-root] This event block number ({}) is already submitted. Don't submit again.",
                event_block_number
            );
            return Ok(());
        }

        if !client
            .ethereum()
            .need_to_sign_mmr_root_of(
                event_block_number,
                Some(finalized_block_header_number),
                client.account().real_account(),
            )
            .await?
        {
            tracing::warn!(
                target: "pangolin-ropsten",
                "[pangolin] [schedule-mmr-root] Don't need to sign mmr root for this event block: {} and at block: {}",
                latest.event_block_number,
                latest.at_block_number
            );
            return Ok(());
        }

        tracing::info!(
            target: "pangolin-ropsten",
            "[pangolin] [schedule-mmr-root] Send sign mmr root for event block: {} and at block: {}",
            latest.event_block_number,
            latest.at_block_number
        );
        let sender = self.data.sender_to_extrinsics_mut();
        let ex = Extrinsic::SignAndSendMmrRoot(latest.event_block_number);
        sender.send(ToExtrinsicsMessage::Extrinsic(ex)).await?;

        self.microkv
            .put("latest_mmr_root_sign", &event_block_number)?;
        Ok(())
    }
}