otx_pool_plugin_signer/
lib.rs

1mod helper;
2
3use helper::SignInfo;
4
5use otx_format::jsonrpc_types::OpenTransaction;
6use otx_pool_config::{built_in_plugins::SignerConfig, CkbConfig, ScriptConfig};
7use otx_pool_plugin_protocol::{
8    HostServiceHandler, MessageFromHost, MessageFromPlugin, Plugin, PluginInfo, PluginMeta,
9};
10use otx_sdk::build_tx::send_tx;
11
12use anyhow::{anyhow, Result};
13use ckb_sdk::types::Address;
14use ckb_types::core::service::Request;
15use ckb_types::H256;
16use dashmap::DashMap;
17
18use std::env;
19use std::path::PathBuf;
20use std::sync::Arc;
21
22#[derive(Clone)]
23struct Context {
24    plugin_name: String,
25    otxs: Arc<DashMap<H256, OpenTransaction>>,
26    sign_info: SignInfo,
27    ckb_config: CkbConfig,
28    _script_config: ScriptConfig,
29    service_handler: HostServiceHandler,
30}
31
32impl Context {
33    fn new(
34        plugin_name: &str,
35        sign_info: SignInfo,
36        ckb_config: CkbConfig,
37        script_config: ScriptConfig,
38        service_handler: HostServiceHandler,
39    ) -> Self {
40        Context {
41            plugin_name: plugin_name.to_owned(),
42            otxs: Arc::new(DashMap::new()),
43            sign_info,
44            ckb_config,
45            _script_config: script_config,
46            service_handler,
47        }
48    }
49}
50
51pub struct Signer {
52    meta: PluginMeta,
53    info: PluginInfo,
54    context: Context,
55}
56
57impl Signer {
58    pub fn new(
59        service_handler: HostServiceHandler,
60        config: SignerConfig,
61        ckb_config: CkbConfig,
62        script_config: ScriptConfig,
63    ) -> Result<Signer> {
64        let name = "singer";
65        let state = PluginMeta::new(PathBuf::default(), true, true);
66        let info = PluginInfo::new(
67            name,
68            "This plugin indexes OTXs that are waiting to be signed and enables them to be signed using a hosted private key.",
69            "1.0",
70        );
71        let key = env::var(config.get_env_key_name())?.parse::<H256>()?;
72        let address = env::var(config.get_env_default_address())?
73            .parse::<Address>()
74            .map_err(|e| anyhow!(e))?;
75
76        let context = Context::new(
77            name,
78            SignInfo::new(&address, &key, ckb_config.clone()),
79            ckb_config,
80            script_config,
81            service_handler,
82        );
83        Ok(Signer {
84            meta: state,
85            info,
86            context,
87        })
88    }
89}
90
91impl Plugin for Signer {
92    fn get_name(&self) -> String {
93        self.info.name.clone()
94    }
95
96    fn get_info(&self) -> PluginInfo {
97        self.info.clone()
98    }
99
100    fn get_meta(&self) -> PluginMeta {
101        self.meta.clone()
102    }
103
104    fn on_new_otx(&self, otx: OpenTransaction) {
105        log::info!(
106            "on_new_open_tx, index otxs count: {:?}",
107            self.context.otxs.len()
108        );
109        if let Ok(aggregate_count) = otx.get_aggregate_count() {
110            log::info!("aggregate count: {:?}", aggregate_count);
111            if aggregate_count == 1 {
112                return;
113            }
114        }
115        let otx_hash = otx.get_tx_hash().expect("get tx hash");
116        self.context.otxs.insert(otx_hash, otx.clone());
117
118        let ckb_tx = if let Ok(tx) = otx.try_into() {
119            tx
120        } else {
121            log::error!("open tx converts to Ckb tx failed.");
122            return;
123        };
124
125        // sign
126        let signer = SignInfo::new(
127            self.context.sign_info.secp_address(),
128            self.context.sign_info.privkey(),
129            self.context.ckb_config.clone(),
130        );
131        let signed_ckb_tx = signer.sign_ckb_tx(ckb_tx).unwrap();
132
133        // send_ckb
134        let tx_hash =
135            if let Ok(tx_hash) = send_tx(self.context.ckb_config.get_ckb_uri(), signed_ckb_tx) {
136                tx_hash
137            } else {
138                log::error!("failed to send final tx.");
139                return;
140            };
141        log::info!("commit final Ckb tx: {:?}", tx_hash.to_string());
142
143        // call host service to notify the host that the final tx has been sent
144        let message = MessageFromPlugin::SentToCkb(tx_hash);
145        if let Some(MessageFromHost::Ok) = Request::call(&self.context.service_handler, message) {
146            self.context.otxs.clear();
147        }
148    }
149
150    fn on_commit_otx(&self, otx_hashes: Vec<H256>) {
151        log::info!(
152            "{} on commit open tx remove committed otx: {:?}",
153            self.context.plugin_name,
154            otx_hashes
155                .iter()
156                .map(|hash| hash.to_string())
157                .collect::<Vec<String>>()
158        );
159        otx_hashes.iter().for_each(|otx_hash| {
160            self.context.otxs.remove(otx_hash);
161        })
162    }
163}