RapidChain选举网络-Demo
这两天看到了 RapidChain 系统,对它的选举网络挺感兴趣,决定复现一下
下面是它的架构图
假设:分片配置环节初始节点集已经建立了身份
然后通过一定的算法(论文中提到的是哈希取区间)从节点池中选取一部分构成组,再在组中选取特定节点构成更高一级的组,层层推进,最终形成一个个分片委员会
接下来我将对这块内容对于 恶意节点的抵抗模拟
进行简单复现,由于节点数不足,哈希取区间的算法被替代为随机数
RapidChain_with_log
这里我将分布放出完整代码并作一定的解释
代码仍然是用 rust 写的,同时引入了包 rand
(0.8.5),终端输入以下内容
假定7的倍数为恶意节点,把45个节点5个一组进行分组成为一个次级委员会
9个次级委员会,3个一组,每个次级委员会选出一个代表,形成正式委员会
首先导入库
1 2 3 4
| use rand::seq::SliceRandom; use rand::{thread_rng, Rng}; use std::fs::File; use std::io::Write;
|
接下来是主函数,首先 创建日志文件
和 格式化信息
1 2 3 4 5 6 7
| let mut log_file = File::create("log.txt").unwrap(); writeln!(&mut log_file, "循环次数: 50").unwrap();
let mut sec_tol: Vec<u32> = vec![0; 5]; let mut ird_tol: Vec<u32> = vec![0; 4];
|
接下来是一个大循环,之后的大部分代码都写在循环中。这也是这次实验的关键代码,下面的代码可以通过函数进行替换,这里放出初始部分,可以更直观展示进程
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
| for _i in 1..=50 {
let mut rng = thread_rng(); let mut numbers: Vec<u32> = (1..=45).collect();
numbers.shuffle(&mut rng);
let _group: Vec<u32> = numbers.iter().take(45).cloned().collect();
let groups: Vec<Vec<u32>> = numbers .chunks(5) .map(|chunk| { let mut group = chunk.to_vec(); group.sort(); group }) .collect();
let mut total_malicious_count = 0; for (_i, group) in groups.iter().enumerate() { let mut malicious_count = 0; for &num in group.iter() { if num % 7 == 0 { malicious_count += 1; } } total_malicious_count += malicious_count;
}
let mut index = 0; let mut sec_vec = vec![0; 9]; for (_i, group) in groups.iter().enumerate() { if sec_vec[index] == 0 { let random_index = rng.gen_range(0..4); sec_vec[index] = group[random_index]; index += 1; } }
total_malicious_count = 0; for (_i, num) in sec_vec.iter().enumerate() { let mut malicious_count = 0; if num % 7 == 0 { malicious_count += 1; } total_malicious_count += malicious_count; } match total_malicious_count { 0 => sec_tol[0] += 1, 1 => sec_tol[1] += 1, 2 => sec_tol[2] += 1, 3 => sec_tol[3] += 1, 4 => sec_tol[4] += 1, _ => {} }
let final_group: Vec<u32> = sec_vec.choose_multiple(&mut rng, 3).cloned().collect();
total_malicious_count = 0; for (_i, num) in final_group.iter().enumerate() { let mut malicious_count = 0; if num % 7 == 0 { malicious_count += 1; } total_malicious_count += malicious_count; } match total_malicious_count { 0 => ird_tol[0] += 1, 1 => ird_tol[1] += 1, 2 => ird_tol[2] += 1, 3 => ird_tol[3] += 1, _ => {} } }
|
在循环外进行最终统计,实际上在日志中看到的就是这部分内容(可以用循环代替,这里笔者懒得动了,所以看着很冗余)顺便一提,虽然 rust 会自己把打开的文件关掉,但你不能不记得这件事。就像结婚纪念日,你对象可以不提,但你自己得记住,这是态度问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| writeln!(&mut log_file, "第二次分配后的恶意节点数统计:").unwrap(); writeln!(&mut log_file, "0个恶意节点的次数: {}" , sec_tol[0]).unwrap(); writeln!(&mut log_file, "1个恶意节点的次数: {}" , sec_tol[1]).unwrap(); writeln!(&mut log_file, "2个恶意节点的次数: {}" , sec_tol[2]).unwrap(); writeln!(&mut log_file, "3个恶意节点的次数: {}" , sec_tol[3]).unwrap();
writeln!(&mut log_file, "").unwrap();
writeln!(&mut log_file, "第三次分配后的恶意节点数统计:").unwrap(); writeln!(&mut log_file, "0个恶意节点的次数: {}" , ird_tol[0]).unwrap(); writeln!(&mut log_file, "1个恶意节点的次数: {}" , ird_tol[1]).unwrap(); writeln!(&mut log_file, "2个恶意节点的次数: {}" , ird_tol[2]).unwrap(); writeln!(&mut log_file, "3个恶意节点的次数: {}" , ird_tol[3]).unwrap();
log_file.flush().unwrap();
|
最后附上一张输出记录的整合图,我跑了两次模拟然后把记录合并
可以看到正式委员会中存在2个恶意节点的概率相对来说还是比较高的,这算是一个比较大的风险。
改进方法:
- 扩大正式委员会的数量,对恶意节点进行稀释
- 调整次级分片中节点数量的比例,在平衡交易效率的同时降低受恶意节点的干扰
本次实验中并没有模拟交易效率,这部分内容可能在之后放出