Skip to content

Commit 6f144fc

Browse files
committed
feat: support multi-chain vanity generation
1 parent 0fe865b commit 6f144fc

4 files changed

Lines changed: 358 additions & 123 deletions

File tree

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,23 @@ path = "src/gui.rs"
1515
[dependencies]
1616
# 密码学和哈希
1717
sha2 = "0.10"
18-
ripemd = "0.1"
1918
k256 = { version = "0.13", features = ["std"] }
2019
rand = "0.8"
2120
hex = "0.4"
2221

2322
# Bip39 助记词和密钥派生
24-
bip39 = "2.2"
23+
bip39 = "1.2"
24+
bip32 = { version = "0.5", features = ["secp256k1"] }
2525
hmac = "0.12"
2626
pbkdf2 = "0.12"
27-
bip32 = { version = "0.5", features = ["secp256k1"] }
2827

2928
# Base58编码
3029
bs58 = "0.5"
3130

3231
# Keccak 与 ed25519
3332
tiny-keccak = { version = "2.0", features = ["keccak"] }
3433
ed25519-dalek = { version = "1", features = ["std", "rand"] }
34+
ed25519-dalek-bip32 = "0.1"
3535

3636
# 多线程和并发
3737
rayon = "1.7"

src/cli.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -261,22 +261,39 @@ fn run_vanity_generator(config: &Config) {
261261
}
262262

263263
let batch: Vec<_> = (0..config.batch_size)
264-
.map(|_| generate_tron_address())
264+
.map(|_| {
265+
let mnemonic = generate_mnemonic();
266+
generate_from_mnemonic_all(&mnemonic)
267+
})
265268
.collect();
266269

267-
for tron in batch {
270+
for multi in batch {
268271
if should_stop.load(Ordering::Relaxed) {
269272
break;
270273
}
271274

272275
counter.fetch_add(1, Ordering::Relaxed);
273276

274-
if is_vanity_address(&tron.address, &patterns) {
275-
found.fetch_add(1, Ordering::Relaxed);
276-
print_address(&tron, true);
277-
let _ = save_address_to_file(&config.output_file, &tron, true);
278-
} else if config.save_all {
279-
let _ = save_address_to_file(&config.output_file, &tron, false);
277+
// 检查三条链是否匹配
278+
let hits = [
279+
(&multi.tron, ChainType::Tron),
280+
(&multi.evm, ChainType::Evm),
281+
(&multi.sol, ChainType::Sol),
282+
];
283+
284+
let mut matched = false;
285+
for (addr, chain) in hits {
286+
if is_vanity_address(&addr.address, &patterns) {
287+
matched = true;
288+
found.fetch_add(1, Ordering::Relaxed);
289+
print_multi_address(&multi, chain);
290+
let _ = save_multi_address_to_file(&config.output_file, &multi, chain);
291+
}
292+
}
293+
294+
if !matched && config.save_all {
295+
// 默认保存 TRON 以兼容旧格式
296+
let _ = save_address_to_file(&config.output_file, &multi.tron, false);
280297
}
281298
}
282299
}

src/gui.rs

Lines changed: 94 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ use iced::mouse;
44
use iced::widget::canvas::{self, path, Canvas};
55
use iced::{
66
executor, theme,
7-
widget::{
8-
button, column, container, pick_list, progress_bar, row, svg, text, text_input, Container,
9-
},
7+
widget::{button, column, container, progress_bar, row, svg, text, text_input, Container},
108
Alignment, Application, Border, Color, Command, Element, Font, Length, Settings, Size, Theme,
119
};
1210
use std::sync::{
@@ -51,8 +49,8 @@ fn load_logo() -> svg::Handle {
5149
}
5250

5351
pub struct VanityApp {
54-
// 链选择
55-
selected_chain: ChainType,
52+
// 链选择(多选)
53+
selected_chains: Vec<ChainType>,
5654

5755
// 配置
5856
patterns_input: String,
@@ -86,7 +84,8 @@ pub struct VanityApp {
8684
pause_signal: Arc<AtomicBool>,
8785
gen_count: Arc<AtomicU64>,
8886
found_count: Arc<AtomicU64>,
89-
vanity_cache: Arc<Mutex<Option<VanityAddress>>>,
87+
// 缓存匹配结果,附带完整三链展示文本
88+
vanity_cache: Arc<Mutex<Option<(VanityAddress, String)>>>,
9089

9190
// 最近发现的靓号(用于手动保存)
9291
last_found: Option<VanityAddress>,
@@ -101,7 +100,7 @@ pub struct VanityApp {
101100
impl Default for VanityApp {
102101
fn default() -> Self {
103102
Self {
104-
selected_chain: ChainType::Tron,
103+
selected_chains: vec![ChainType::Tron],
105104
batch_size: "1000".to_string(),
106105
thread_count: num_cpus::get().to_string(),
107106
patterns_input: "1111,2222,3333,4444,5555,6666,7777,8888,9999,0000".to_string(),
@@ -143,7 +142,7 @@ impl VanityApp {
143142

144143
#[derive(Debug, Clone)]
145144
pub enum Message {
146-
ChainChanged(ChainType),
145+
ChainToggled(ChainType),
147146
PatternsChanged(String),
148147
BatchSizeChanged(String),
149148
ThreadCountChanged(String),
@@ -172,7 +171,13 @@ impl Application for VanityApp {
172171

173172
fn update(&mut self, message: Message) -> Command<Message> {
174173
match message {
175-
Message::ChainChanged(chain) => self.selected_chain = chain,
174+
Message::ChainToggled(chain) => {
175+
if let Some(pos) = self.selected_chains.iter().position(|c| c == &chain) {
176+
self.selected_chains.remove(pos);
177+
} else {
178+
self.selected_chains.push(chain);
179+
}
180+
}
176181
Message::PatternsChanged(input) => self.patterns_input = input,
177182
Message::BatchSizeChanged(input) => self.batch_size = input,
178183
Message::ThreadCountChanged(input) => self.thread_count = input,
@@ -196,7 +201,7 @@ impl Application for VanityApp {
196201
}
197202
}
198203
Message::StartPressed => {
199-
if !self.is_running {
204+
if !self.is_running && !self.selected_chains.is_empty() {
200205
self.is_running = true;
201206
self.is_paused = false;
202207
self.total_generated = 0;
@@ -206,16 +211,22 @@ impl Application for VanityApp {
206211
self.start_time = Some(Instant::now());
207212
self.gen_start_time = Some(Instant::now());
208213
self.log_messages.clear();
214+
215+
let chains_str = self.selected_chains
216+
.iter()
217+
.map(|c| c.label())
218+
.collect::<Vec<_>>()
219+
.join(" | ");
209220
self.log_messages.push(format!(
210-
"▶ {} 启动,开始搜索靓号...",
211-
self.selected_chain.label()
221+
"▶ [{}] 启动,开始搜索靓号...",
222+
chains_str
212223
));
213224

214225
let stop_signal = Arc::clone(&self.stop_signal);
215226
let pause_signal = Arc::clone(&self.pause_signal);
216227
let gen_count = Arc::clone(&self.gen_count);
217228
let found_count = Arc::clone(&self.found_count);
218-
let chain = self.selected_chain;
229+
let selected_chains = self.selected_chains.clone();
219230

220231
stop_signal.store(false, Ordering::Relaxed);
221232
pause_signal.store(false, Ordering::Relaxed);
@@ -243,7 +254,7 @@ impl Application for VanityApp {
243254
let found = Arc::clone(&found_count);
244255
let vanity_cache = Arc::clone(&self.vanity_cache);
245256
let patterns_clone = patterns.clone();
246-
let chain_copy = chain;
257+
let chains_copy = selected_chains.clone();
247258
let save_path = self.save_file_path.clone();
248259

249260
thread::spawn(move || loop {
@@ -257,16 +268,40 @@ impl Application for VanityApp {
257268
}
258269

259270
for _ in 0..batch {
260-
let addr = generate_vanity_address(chain_copy);
271+
// 生成单个助记词对应的三种链地址
272+
let mnemonic = generate_mnemonic();
273+
let multi_addr = generate_from_mnemonic_all(&mnemonic);
274+
261275
let patterns_refs: Vec<&str> =
262276
patterns_clone.iter().map(|s| s.as_str()).collect();
263-
if is_vanity_address(&addr.address, &patterns_refs) {
264-
found.fetch_add(1, Ordering::Relaxed);
265-
// 保存到用户指定的文件
266-
let _ = save_address_to_file(&save_path, &addr, true);
267-
// 缓存靓号信息用于 UI 显示
268-
if let Ok(mut cache) = vanity_cache.lock() {
269-
*cache = Some(addr.clone());
277+
278+
// 对每个选中的链进行匹配
279+
let addresses = vec![
280+
(&multi_addr.tron, ChainType::Tron),
281+
(&multi_addr.evm, ChainType::Evm),
282+
(&multi_addr.sol, ChainType::Sol),
283+
];
284+
285+
for (addr, chain_type) in addresses {
286+
if chains_copy.contains(&chain_type)
287+
&& is_vanity_address(&addr.address, &patterns_refs)
288+
{
289+
found.fetch_add(1, Ordering::Relaxed);
290+
let _ =
291+
save_multi_address_to_file(&save_path, &multi_addr, chain_type);
292+
293+
let display = format!(
294+
"✨ 发现靓号: [{}] {} | TRON: {} | EVM: {} | SOL: {}",
295+
chain_type.label(),
296+
addr.address,
297+
multi_addr.tron.address,
298+
multi_addr.evm.address,
299+
multi_addr.sol.address,
300+
);
301+
302+
if let Ok(mut cache) = vanity_cache.lock() {
303+
*cache = Some((addr.clone(), display));
304+
}
270305
}
271306
}
272307
gen.fetch_add(1, Ordering::Relaxed);
@@ -324,15 +359,8 @@ impl Application for VanityApp {
324359

325360
// 检查是否有新的靓号
326361
if let Ok(mut cache) = self.vanity_cache.lock() {
327-
if let Some(vanity_info) = cache.take() {
328-
self.log_messages.insert(
329-
0,
330-
format!(
331-
"✨ 发现靓号: [{}] {}",
332-
vanity_info.chain.label(),
333-
vanity_info.address
334-
),
335-
);
362+
if let Some((vanity_info, display)) = cache.take() {
363+
self.log_messages.insert(0, display);
336364
self.last_found = Some(vanity_info);
337365
}
338366
}
@@ -364,6 +392,33 @@ impl Application for VanityApp {
364392
fn view(&self) -> Element<'_, Message> {
365393
const CHAINS: [ChainType; 3] = [ChainType::Tron, ChainType::Evm, ChainType::Sol];
366394

395+
// 构建链选择按钮组(多选)
396+
let chain_buttons = CHAINS
397+
.iter()
398+
.fold(row![].spacing(8), |row, &chain| {
399+
let is_selected = self.selected_chains.contains(&chain);
400+
let btn = if is_selected {
401+
button(
402+
text(chain.label())
403+
.size(14)
404+
.style(iced::theme::Text::Color(Color::from_rgb8(255, 255, 255))),
405+
)
406+
.padding(10)
407+
.style(iced::theme::Button::Positive)
408+
.on_press(Message::ChainToggled(chain))
409+
} else {
410+
button(
411+
text(chain.label())
412+
.size(14)
413+
.style(iced::theme::Text::Color(Color::from_rgb8(142, 162, 185))),
414+
)
415+
.padding(10)
416+
.style(iced::theme::Button::Secondary)
417+
.on_press(Message::ChainToggled(chain))
418+
};
419+
row.push(btn)
420+
});
421+
367422
let header = row![
368423
svg(self.logo_handle.clone())
369424
.width(Length::Fixed(40.0))
@@ -379,10 +434,11 @@ impl Application for VanityApp {
379434
.spacing(4)
380435
.width(Length::Fill)
381436
.align_items(Alignment::Start),
382-
pick_list(CHAINS, Some(self.selected_chain), Message::ChainChanged)
383-
.placeholder("选择链")
384-
.padding(10)
385-
.width(Length::Fixed(150.0)),
437+
column![
438+
text("选择链").size(12).style(iced::theme::Text::Color(accent())),
439+
chain_buttons,
440+
]
441+
.spacing(6),
386442
]
387443
.spacing(12)
388444
.align_items(Alignment::Center);
@@ -429,13 +485,14 @@ impl Application for VanityApp {
429485

430486
let controls = row![
431487
primary_button("启动", Message::StartPressed),
488+
danger_button("停止", Message::StopPressed),
432489
ghost_button(
433490
if self.is_paused { "继续" } else { "暂停" },
434491
Message::PausePressed
435492
),
436-
danger_button("停止", Message::StopPressed),
437493
]
438-
.spacing(12);
494+
.spacing(14)
495+
.align_items(Alignment::Center);
439496

440497
let uptime = self.start_time.map(|t| t.elapsed().as_secs()).unwrap_or(0);
441498

0 commit comments

Comments
 (0)