Skip to content

Commit 16c6db8

Browse files
committed
feat: add logging for channel auto-accept failures
This helps operators understand why channels aren't being auto-accepted, making debugging easier when channel opening fails. The logging covers both sender and receiver perspectives, including warnings when funding amounts are insufficient or UDT types don't match auto-accept requirements.
1 parent 6bd3783 commit 16c6db8

File tree

5 files changed

+472
-19
lines changed

5 files changed

+472
-19
lines changed

crates/fiber-lib/src/ckb/config.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::Result;
55
use ckb_jsonrpc_types::{OutPoint as OutPointWrapper, Script as ScriptWrapper};
66
use ckb_sdk::{traits::DefaultCellCollector, CkbRpcAsyncClient};
77
use ckb_types::core::ScriptHashType;
8-
use ckb_types::prelude::Builder;
8+
use ckb_types::prelude::{Builder, Pack};
99
use ckb_types::H256;
1010
use ckb_types::{
1111
core::DepType,
@@ -270,6 +270,27 @@ pub struct UdtArgInfo {
270270
#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq, Hash)]
271271
pub struct UdtCfgInfos(pub Vec<UdtArgInfo>);
272272

273+
impl UdtCfgInfos {
274+
/// Find a matching UDT info by script (code_hash, hash_type, and args pattern)
275+
pub fn find_matching_udt(&self, udt_script: &Script) -> Option<&UdtArgInfo> {
276+
use regex::Regex;
277+
for udt in &self.0 {
278+
if let Ok(hash_type) = udt_script.hash_type().try_into() {
279+
if udt.script.code_hash.pack() == udt_script.code_hash()
280+
&& udt.script.hash_type == hash_type
281+
{
282+
let args = format!("0x{:x}", udt_script.args().raw_data());
283+
let pattern = Regex::new(&udt.script.args).expect("invalid expression");
284+
if pattern.is_match(&args) {
285+
return Some(udt);
286+
}
287+
}
288+
}
289+
}
290+
None
291+
}
292+
}
293+
273294
impl FromStr for UdtCfgInfos {
274295
type Err = serde_json::Error;
275296

crates/fiber-lib/src/ckb/contracts.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use ckb_types::{
55
prelude::{Builder, Entity, Pack, PackVec},
66
};
77
use once_cell::sync::OnceCell;
8-
use regex::Regex;
98
use serde::{Deserialize, Serialize};
109
use std::{collections::HashMap, vec};
1110
use thiserror::Error;
@@ -377,20 +376,7 @@ impl ContractsContext {
377376
}
378377

379378
pub(crate) fn get_udt_info(&self, udt_script: &Script) -> Option<&UdtArgInfo> {
380-
for udt in &self.get_udt_whitelist().0 {
381-
if let Ok(_type) = udt_script.hash_type().try_into() {
382-
if udt.script.code_hash.pack() == udt_script.code_hash()
383-
&& udt.script.hash_type == _type
384-
{
385-
let args = format!("0x{:x}", udt_script.args().raw_data());
386-
let pattern = Regex::new(&udt.script.args).expect("invalid expression");
387-
if pattern.is_match(&args) {
388-
return Some(udt);
389-
}
390-
}
391-
}
392-
}
393-
None
379+
self.get_udt_whitelist().find_matching_udt(udt_script)
394380
}
395381
}
396382

@@ -445,7 +431,7 @@ pub fn get_cell_deps_count_by_contracts(contracts: Vec<Contract>) -> usize {
445431
get_contracts_context().get_cell_deps_count(contracts)
446432
}
447433

448-
fn get_udt_info(script: &Script) -> Option<UdtArgInfo> {
434+
pub fn get_udt_info(script: &Script) -> Option<UdtArgInfo> {
449435
get_contracts_context().get_udt_info(script).cloned()
450436
}
451437

crates/fiber-lib/src/ckb/tests/config.rs

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use crate::ckb::config::{UdtArgInfo, UdtCellDep, UdtCfgInfos, UdtDep, UdtScript}
22
use crate::fiber::gen::fiber::UdtCfgInfos as MoleculeUdtCfgInfos;
33
use ckb_jsonrpc_types::OutPoint;
44
use ckb_types::core::{DepType, ScriptHashType};
5+
use ckb_types::packed::Script;
6+
use ckb_types::prelude::{Builder, Pack};
57
use ckb_types::H256;
68
use molecule::prelude::Entity;
79

@@ -30,3 +32,185 @@ fn test_udt_whitelist() {
3032
UdtCfgInfos::from(MoleculeUdtCfgInfos::from_slice(&serialized).expect("invalid mol"));
3133
assert_eq!(udt_whitelist, deserialized);
3234
}
35+
36+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
37+
#[cfg_attr(not(target_arch = "wasm32"), test)]
38+
fn test_find_matching_udt_exact_match() {
39+
let code_hash = H256::from([1u8; 32]);
40+
let args = "0x1234".to_string();
41+
let udt_whitelist = UdtCfgInfos(vec![UdtArgInfo {
42+
name: "TestUDT".to_string(),
43+
script: UdtScript {
44+
code_hash: code_hash.clone(),
45+
hash_type: ScriptHashType::Data,
46+
args: args.clone(),
47+
},
48+
auto_accept_amount: Some(100),
49+
cell_deps: vec![],
50+
}]);
51+
52+
let script = Script::new_builder()
53+
.code_hash(code_hash.pack())
54+
.hash_type(ScriptHashType::Data.into())
55+
.args(args.as_bytes().pack())
56+
.build();
57+
58+
let found = udt_whitelist.find_matching_udt(&script);
59+
assert!(found.is_some());
60+
assert_eq!(found.unwrap().name, "TestUDT");
61+
}
62+
63+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
64+
#[cfg_attr(not(target_arch = "wasm32"), test)]
65+
fn test_find_matching_udt_regex_pattern() {
66+
let code_hash = H256::from([2u8; 32]);
67+
let udt_whitelist = UdtCfgInfos(vec![UdtArgInfo {
68+
name: "RegexUDT".to_string(),
69+
script: UdtScript {
70+
code_hash: code_hash.clone(),
71+
hash_type: ScriptHashType::Data,
72+
args: "0x[0-9a-f]{4}".to_string(), // Regex pattern matching 4 hex digits
73+
},
74+
auto_accept_amount: Some(200),
75+
cell_deps: vec![],
76+
}]);
77+
78+
// Test with matching args
79+
let script = Script::new_builder()
80+
.code_hash(code_hash.pack())
81+
.hash_type(ScriptHashType::Data.into())
82+
.args("0xabcd".as_bytes().pack())
83+
.build();
84+
85+
let found = udt_whitelist.find_matching_udt(&script);
86+
assert!(found.is_some());
87+
assert_eq!(found.unwrap().name, "RegexUDT");
88+
89+
// Test with non-matching args
90+
let script_no_match = Script::new_builder()
91+
.code_hash(code_hash.pack())
92+
.hash_type(ScriptHashType::Data.into())
93+
.args("0xabc".as_bytes().pack()) // Only 3 hex digits, doesn't match pattern
94+
.build();
95+
96+
let found = udt_whitelist.find_matching_udt(&script_no_match);
97+
assert!(found.is_none());
98+
}
99+
100+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
101+
#[cfg_attr(not(target_arch = "wasm32"), test)]
102+
fn test_find_matching_udt_wrong_code_hash() {
103+
let code_hash1 = H256::from([3u8; 32]);
104+
let code_hash2 = H256::from([4u8; 32]);
105+
let udt_whitelist = UdtCfgInfos(vec![UdtArgInfo {
106+
name: "TestUDT".to_string(),
107+
script: UdtScript {
108+
code_hash: code_hash1.clone(),
109+
hash_type: ScriptHashType::Data,
110+
args: "0x00".to_string(),
111+
},
112+
auto_accept_amount: Some(100),
113+
cell_deps: vec![],
114+
}]);
115+
116+
let script = Script::new_builder()
117+
.code_hash(code_hash2.pack()) // Different code_hash
118+
.hash_type(ScriptHashType::Data.into())
119+
.args("0x00".as_bytes().pack())
120+
.build();
121+
122+
let found = udt_whitelist.find_matching_udt(&script);
123+
assert!(found.is_none());
124+
}
125+
126+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
127+
#[cfg_attr(not(target_arch = "wasm32"), test)]
128+
fn test_find_matching_udt_wrong_hash_type() {
129+
let code_hash = H256::from([5u8; 32]);
130+
let udt_whitelist = UdtCfgInfos(vec![UdtArgInfo {
131+
name: "TestUDT".to_string(),
132+
script: UdtScript {
133+
code_hash: code_hash.clone(),
134+
hash_type: ScriptHashType::Data,
135+
args: "0x00".to_string(),
136+
},
137+
auto_accept_amount: Some(100),
138+
cell_deps: vec![],
139+
}]);
140+
141+
let script = Script::new_builder()
142+
.code_hash(code_hash.pack())
143+
.hash_type(ScriptHashType::Type.into()) // Different hash_type
144+
.args("0x00".as_bytes().pack())
145+
.build();
146+
147+
let found = udt_whitelist.find_matching_udt(&script);
148+
assert!(found.is_none());
149+
}
150+
151+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
152+
#[cfg_attr(not(target_arch = "wasm32"), test)]
153+
fn test_find_matching_udt_multiple_udts() {
154+
let code_hash1 = H256::from([6u8; 32]);
155+
let code_hash2 = H256::from([7u8; 32]);
156+
let udt_whitelist = UdtCfgInfos(vec![
157+
UdtArgInfo {
158+
name: "FirstUDT".to_string(),
159+
script: UdtScript {
160+
code_hash: code_hash1.clone(),
161+
hash_type: ScriptHashType::Data,
162+
args: "0x00".to_string(),
163+
},
164+
auto_accept_amount: Some(100),
165+
cell_deps: vec![],
166+
},
167+
UdtArgInfo {
168+
name: "SecondUDT".to_string(),
169+
script: UdtScript {
170+
code_hash: code_hash2.clone(),
171+
hash_type: ScriptHashType::Data,
172+
args: "0x01".to_string(),
173+
},
174+
auto_accept_amount: Some(200),
175+
cell_deps: vec![],
176+
},
177+
]);
178+
179+
// Test finding first UDT
180+
let script1 = Script::new_builder()
181+
.code_hash(code_hash1.pack())
182+
.hash_type(ScriptHashType::Data.into())
183+
.args("0x00".as_bytes().pack())
184+
.build();
185+
186+
let found = udt_whitelist.find_matching_udt(&script1);
187+
assert!(found.is_some());
188+
assert_eq!(found.unwrap().name, "FirstUDT");
189+
190+
// Test finding second UDT
191+
let script2 = Script::new_builder()
192+
.code_hash(code_hash2.pack())
193+
.hash_type(ScriptHashType::Data.into())
194+
.args("0x01".as_bytes().pack())
195+
.build();
196+
197+
let found = udt_whitelist.find_matching_udt(&script2);
198+
assert!(found.is_some());
199+
assert_eq!(found.unwrap().name, "SecondUDT");
200+
}
201+
202+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
203+
#[cfg_attr(not(target_arch = "wasm32"), test)]
204+
fn test_find_matching_udt_empty_whitelist() {
205+
let udt_whitelist = UdtCfgInfos(vec![]);
206+
let code_hash = H256::from([8u8; 32]);
207+
208+
let script = Script::new_builder()
209+
.code_hash(code_hash.pack())
210+
.hash_type(ScriptHashType::Data.into())
211+
.args("0x00".as_bytes().pack())
212+
.build();
213+
214+
let found = udt_whitelist.find_matching_udt(&script);
215+
assert!(found.is_none());
216+
}

0 commit comments

Comments
 (0)