otx_pool_plugin_signer/
lib.rs1mod 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 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 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 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}