├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── blockdag ├── .gitignore ├── Cargo.toml └── src │ ├── blockdag │ ├── anticone.rs │ ├── block.rs │ ├── calcblue.rs │ ├── cardinality.rs │ ├── dagsim.rs │ ├── hourglass.rs │ ├── mod.rs │ └── node.rs │ └── lib.rs ├── godag ├── .gitignore ├── Cargo.toml └── src │ └── main.rs └── pics ├── Fig.3.png ├── Fig.4.jpg └── Fig.X1.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | target/ 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "aho-corasick" 3 | version = "0.6.4" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | dependencies = [ 6 | "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 7 | ] 8 | 9 | [[package]] 10 | name = "atty" 11 | version = "0.2.9" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | dependencies = [ 14 | "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", 15 | "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 16 | "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "bitflags" 21 | version = "1.0.1" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | 24 | [[package]] 25 | name = "blockdag" 26 | version = "0.1.0" 27 | dependencies = [ 28 | "env_logger 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", 29 | "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 30 | "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 31 | "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 32 | ] 33 | 34 | [[package]] 35 | name = "cfg-if" 36 | version = "0.1.2" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | 39 | [[package]] 40 | name = "env_logger" 41 | version = "0.5.9" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | dependencies = [ 44 | "atty 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 46 | "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 47 | "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", 48 | "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 49 | ] 50 | 51 | [[package]] 52 | name = "fuchsia-zircon" 53 | version = "0.3.3" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | dependencies = [ 56 | "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 58 | ] 59 | 60 | [[package]] 61 | name = "fuchsia-zircon-sys" 62 | version = "0.3.3" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | 65 | [[package]] 66 | name = "godag" 67 | version = "0.1.0" 68 | dependencies = [ 69 | "blockdag 0.1.0", 70 | "env_logger 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", 71 | "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 72 | ] 73 | 74 | [[package]] 75 | name = "humantime" 76 | version = "1.1.1" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | dependencies = [ 79 | "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 80 | ] 81 | 82 | [[package]] 83 | name = "lazy_static" 84 | version = "1.0.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | 87 | [[package]] 88 | name = "libc" 89 | version = "0.2.40" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | 92 | [[package]] 93 | name = "log" 94 | version = "0.4.1" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | dependencies = [ 97 | "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 98 | ] 99 | 100 | [[package]] 101 | name = "memchr" 102 | version = "2.0.1" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | dependencies = [ 105 | "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", 106 | ] 107 | 108 | [[package]] 109 | name = "quick-error" 110 | version = "1.2.1" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | 113 | [[package]] 114 | name = "rand" 115 | version = "0.4.2" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | dependencies = [ 118 | "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 121 | ] 122 | 123 | [[package]] 124 | name = "redox_syscall" 125 | version = "0.1.37" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | 128 | [[package]] 129 | name = "redox_termios" 130 | version = "0.1.1" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | dependencies = [ 133 | "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", 134 | ] 135 | 136 | [[package]] 137 | name = "regex" 138 | version = "0.2.10" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | dependencies = [ 141 | "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", 142 | "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 143 | "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", 144 | "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 145 | "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 146 | ] 147 | 148 | [[package]] 149 | name = "regex-syntax" 150 | version = "0.5.5" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | dependencies = [ 153 | "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 154 | ] 155 | 156 | [[package]] 157 | name = "termcolor" 158 | version = "0.3.6" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | dependencies = [ 161 | "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 162 | ] 163 | 164 | [[package]] 165 | name = "termion" 166 | version = "1.5.1" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | dependencies = [ 169 | "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", 170 | "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", 171 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 172 | ] 173 | 174 | [[package]] 175 | name = "thread_local" 176 | version = "0.3.5" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | dependencies = [ 179 | "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 180 | "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 181 | ] 182 | 183 | [[package]] 184 | name = "time" 185 | version = "0.1.39" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | dependencies = [ 188 | "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", 189 | "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", 190 | "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 191 | ] 192 | 193 | [[package]] 194 | name = "ucd-util" 195 | version = "0.1.1" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | 198 | [[package]] 199 | name = "unreachable" 200 | version = "1.0.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | dependencies = [ 203 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 204 | ] 205 | 206 | [[package]] 207 | name = "utf8-ranges" 208 | version = "1.0.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | 211 | [[package]] 212 | name = "void" 213 | version = "1.0.2" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | 216 | [[package]] 217 | name = "winapi" 218 | version = "0.3.4" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | dependencies = [ 221 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 222 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 223 | ] 224 | 225 | [[package]] 226 | name = "winapi-i686-pc-windows-gnu" 227 | version = "0.4.0" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | 230 | [[package]] 231 | name = "winapi-x86_64-pc-windows-gnu" 232 | version = "0.4.0" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | 235 | [[package]] 236 | name = "wincolor" 237 | version = "0.1.6" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | dependencies = [ 240 | "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 241 | ] 242 | 243 | [metadata] 244 | "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" 245 | "checksum atty 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6609a866dd1a1b2d0ee1362195bf3e4f6438abb2d80120b83b1e1f4fb6476dd0" 246 | "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" 247 | "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" 248 | "checksum env_logger 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "00c45cec4cde3daac5f036c74098b4956151525cdf360cff5ee0092c98823e54" 249 | "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 250 | "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 251 | "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" 252 | "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" 253 | "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" 254 | "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" 255 | "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" 256 | "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" 257 | "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" 258 | "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" 259 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 260 | "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb" 261 | "checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb" 262 | "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" 263 | "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" 264 | "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" 265 | "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" 266 | "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" 267 | "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" 268 | "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" 269 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 270 | "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" 271 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 272 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 273 | "checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" 274 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "godag", 5 | "blockdag", 6 | ] 7 | 8 | [profile.test] 9 | opt-level=3 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-dag 2 | BlockDAG algorithms Rust language simulation. 3 | 4 | BlockChain (for example Bitcoin, Etherum, etc.) is just a 'k=0' special subtype of BlockDAG, that's why they suffer from the highly restrictive throughput. DAG is the future! 5 | 6 | --- 7 | 8 | # How to build 9 | 10 | Run the simulation for the example Fig.3, the 'k' is 3 in the example. 11 | 12 | ```bash 13 | $ cargo test test_fig3 -- --nocapture 14 | ``` 15 | 16 | Run the simulation for the example Fig.4, the 'k' is 3 in the example. 17 | 18 | ```bash 19 | $ cargo test test_fig4 -- --nocapture 20 | ``` 21 | 22 | Run the simulation for the example Fig.X1 or Fig.X2, the 'k' is set to 0 in these 2 examples. 23 | 24 | ```bash 25 | $ cargo test test_fig_x1 -- --nocapture 26 | $ cargo test test_fig_x2 -- --nocapture 27 | ``` 28 | 29 | Run the simulation for the example of generating 1000 random blocks, and execute the blue selection in a real-time calculation. 30 | 31 | ```bash 32 | $ cargo test test_add_block -- --nocapture 33 | ``` 34 | 35 | To add a new example DAG to see the DAG blue selection behaviour, it's quite easy. For example, to test a DAG in this figure 'Fig.4', just add a piece of codes like this: 36 | ![Fig.4](https://github.com/garyyu/rust-dag/blob/master/pics/Fig.4.jpg) 37 | 38 | ```rust 39 | #[test] 40 | fn test_your_example() { 41 | 42 | let k: i32 = 3; 43 | 44 | let _ = env_logger::try_init(); 45 | 46 | let node = Node::init("YourExampleDag"); 47 | 48 | let mut node_w = node.write().unwrap(); 49 | 50 | macro_rules! dag_add { 51 | ( block=$a:expr, references=$b:expr ) => (node_add_block($a, $b, &mut node_w, k, true)); 52 | } 53 | dag_add!(block="Genesis", references=&Vec::new()); 54 | 55 | dag_add!(block="B", references=&vec!["Genesis"]); 56 | dag_add!(block="C", references=&vec!["Genesis"]); 57 | dag_add!(block="D", references=&vec!["Genesis"]); 58 | dag_add!(block="E", references=&vec!["Genesis"]); 59 | 60 | dag_add!(block="F", references=&vec!["B","C"]); 61 | dag_add!(block="H", references=&vec!["E"]); 62 | dag_add!(block="I", references=&vec!["C","D"]); 63 | 64 | dag_add!(block="J", references=&vec!["F","D"]); 65 | dag_add!(block="K", references=&vec!["J","I","E"]); 66 | dag_add!(block="L", references=&vec!["F"]); 67 | dag_add!(block="N", references=&vec!["D","H"]); 68 | 69 | dag_add!(block="M", references=&vec!["L","K"]); 70 | dag_add!(block="O", references=&vec!["K"]); 71 | dag_add!(block="P", references=&vec!["K"]); 72 | dag_add!(block="Q", references=&vec!["N"]); 73 | 74 | dag_add!(block="R", references=&vec!["O","P","N"]); 75 | 76 | dag_add!(block="S", references=&vec!["Q"]); 77 | dag_add!(block="T", references=&vec!["S"]); 78 | dag_add!(block="U", references=&vec!["T"]); 79 | 80 | println!("{}", &node_w); 81 | 82 | dag_print(&node_w.dag); 83 | 84 | let blue_selection = dag_blue_print(&node_w.dag); 85 | println!("k={}, {}", k, &blue_selection); 86 | 87 | assert_eq!(2 + 2, 4); 88 | } 89 | ``` 90 | 91 | then run it by ```cargo test test_your_example -- --nocapture``` 92 | The output will be like this: 93 | 94 | ```console 95 | running 1 test 96 | node=fig4,height=7,size_of_dag=20,dag={Genesis,B,C,D,E,F,H,I,J,L,N,K,Q,M,O,P,S,R,T,U},tips={R,M,U} 97 | dag={ 98 | {name=Genesis,block=name=Genesis,height=0,size_of_past_set=0,size_of_past_blue=0,blue=1,prev={}} 99 | {name=B,block=name=B,height=1,size_of_past_set=1,size_of_past_blue=1,blue=1,prev={Genesis}} 100 | {name=C,block=name=C,height=1,size_of_past_set=1,size_of_past_blue=1,blue=1,prev={Genesis}} 101 | {name=D,block=name=D,height=1,size_of_past_set=1,size_of_past_blue=1,blue=1,prev={Genesis}} 102 | {name=E,block=name=E,height=1,size_of_past_set=1,size_of_past_blue=1,blue=0,prev={Genesis}} 103 | {name=F,block=name=F,height=2,size_of_past_set=3,size_of_past_blue=3,blue=1,prev={B,C}} 104 | {name=H,block=name=H,height=2,size_of_past_set=2,size_of_past_blue=1,blue=0,prev={E}} 105 | {name=I,block=name=I,height=2,size_of_past_set=3,size_of_past_blue=3,blue=1,prev={C,D}} 106 | {name=J,block=name=J,height=3,size_of_past_set=5,size_of_past_blue=5,blue=1,prev={F,D}} 107 | {name=L,block=name=L,height=3,size_of_past_set=4,size_of_past_blue=4,blue=0,prev={F}} 108 | {name=N,block=name=N,height=3,size_of_past_set=4,size_of_past_blue=2,blue=0,prev={H,D}} 109 | {name=K,block=name=K,height=4,size_of_past_set=8,size_of_past_blue=7,blue=1,prev={I,J,E}} 110 | {name=Q,block=name=Q,height=4,size_of_past_set=5,size_of_past_blue=2,blue=0,prev={N}} 111 | {name=M,block=name=M,height=5,size_of_past_set=10,size_of_past_blue=8,blue=1,prev={L,K}} 112 | {name=O,block=name=O,height=5,size_of_past_set=9,size_of_past_blue=8,blue=1,prev={K}} 113 | {name=P,block=name=P,height=5,size_of_past_set=9,size_of_past_blue=8,blue=1,prev={K}} 114 | {name=S,block=name=S,height=5,size_of_past_set=6,size_of_past_blue=2,blue=0,prev={Q}} 115 | {name=R,block=name=R,height=6,size_of_past_set=13,size_of_past_blue=10,blue=1,prev={O,N,P}} 116 | {name=T,block=name=T,height=6,size_of_past_set=7,size_of_past_blue=2,blue=0,prev={S}} 117 | {name=U,block=name=U,height=7,size_of_past_set=8,size_of_past_blue=2,blue=0,prev={T}} 118 | } 119 | k=3, blues={Genesis,B,C,D,F,I,J,K,M,O,P,R,} total=12/20 120 | test tests::test_your_example ... ok 121 | ``` 122 | 123 | The following picture is another examples: Fig.3. 124 | 125 | ![Fig.3](https://github.com/garyyu/rust-dag/blob/master/pics/Fig.3.png) 126 | 127 | Please join us the BlockDAG discussion on [https://godag.github.io](https://godag.github.io). 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /blockdag/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /blockdag/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blockdag" 3 | version = "0.1.0" 4 | authors = ["Gary YU "] 5 | 6 | [dependencies] 7 | rand = "0.4.2" 8 | time = "0.1.39" 9 | log = "0.4.0" 10 | env_logger = "0.5.9" -------------------------------------------------------------------------------- /blockdag/src/blockdag/anticone.rs: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2018 The rust-dag Authors 3 | // This file is part of the rust-dag library. 4 | // 5 | // The rust-dag library is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU Lesser General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // The rust-dag library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public License 16 | // along with the rust-dag library. If not, see . 17 | 18 | use std::collections::HashMap; 19 | use std::collections::hash_map::Entry; 20 | use std::sync::{Arc,RwLock}; 21 | 22 | use blockdag::{Block,MaxMin,Node}; 23 | use blockdag::{sorted_keys_by_height,step_one_past,append_maps}; 24 | 25 | const ANTICONE_MAX_ITERATION: i32 = 30; 26 | 27 | /// Function providing anti-cone calculations. 28 | /// 29 | pub fn tips_anticone(tip_name: &str, tips: &HashMap>>) -> HashMap>>{ 30 | 31 | let mut anticone: HashMap>> = HashMap::new(); 32 | 33 | if tips.len()==0 { 34 | //println!("tips_anticone(): tip={} error! tips is empty", tip_name); 35 | return anticone; 36 | } 37 | 38 | let mut maxi_pred_set: HashMap>> = HashMap::new(); 39 | let mut rest_pred_set: HashMap>> = HashMap::new(); 40 | 41 | for (key, value) in tips { 42 | 43 | // let tip = Arc::clone(value); 44 | // let tip = tip.read().unwrap(); 45 | 46 | if key == tip_name { 47 | maxi_pred_set.insert(String::from(key.clone()), Arc::clone(value)); 48 | }else { 49 | rest_pred_set.insert(String::from(key.clone()), Arc::clone(value)); 50 | anticone.insert(String::from(key.clone()), Arc::clone(value)); 51 | } 52 | } 53 | 54 | if maxi_pred_set.len()==0 { 55 | println!("tips_anticone(): error! tip {} is not in tips", tip_name); 56 | return HashMap::new(); 57 | } 58 | 59 | //println!("tips_anticone(): tip={} size_of_anticone={}", tip_name, anticone.len()); 60 | 61 | let mut used_rest: HashMap = HashMap::new(); 62 | let mut used_maxi: HashMap = HashMap::new(); 63 | 64 | let mut rest_maxmin = MaxMin{max:0, min:::max_value()}; 65 | let mut maxi_maxmin = MaxMin{max:0, min:::max_value()}; 66 | 67 | let mut iteration_steps = 0; 68 | while rest_pred_set.len() > 0 && iteration_steps < ANTICONE_MAX_ITERATION { 69 | 70 | let mut new_rest_pred: HashMap>> = HashMap::new(); 71 | let _rest_local_maxmin = step_one_past(&rest_pred_set, &mut new_rest_pred, &mut used_rest, &mut rest_maxmin); 72 | 73 | //let mut maxi_height_max = 0; 74 | loop { 75 | let mut new_maxi_pred: HashMap>> = HashMap::new(); 76 | let max_local_maxmin = step_one_past(&maxi_pred_set, &mut new_maxi_pred, &mut used_maxi, &mut maxi_maxmin); 77 | 78 | append_maps(&mut maxi_pred_set, &new_maxi_pred); 79 | drop(new_maxi_pred); 80 | 81 | if max_local_maxmin.max <= rest_maxmin.min { 82 | //maxi_height_max = max_local_maxmin.max; 83 | break; 84 | } 85 | iteration_steps += 1; 86 | } 87 | 88 | //println!("tips_anticone(): tip={} rest_height_min={} rest={:?} maxi_height_max={} max={:?} size_of_anticone={}", tip_name, rest_maxmin.min, 89 | // sorted_keys_by_height(&new_rest_pred, true).iter().map(|&(ref n,_)|{n}).collect::>(), 90 | // maxi_height_max, sorted_keys_by_height(&maxi_pred_set, true).iter().map(|&(ref n,_)|{n}).collect::>(), 91 | // anticone.len()); 92 | let rest_keys = new_rest_pred.iter().map(|(k,_)|{k.clone()}).collect::>(); 93 | for name in &rest_keys { 94 | if maxi_pred_set.get(name).is_some() { 95 | new_rest_pred.remove(name); 96 | } 97 | } 98 | 99 | append_maps(&mut anticone, &new_rest_pred); 100 | 101 | rest_pred_set = new_rest_pred; 102 | //println!("tips_anticone(): tip={} size_of_anticone={} rest_pred_set={}", tip_name, anticone.len(), rest_pred_set.len()); 103 | 104 | iteration_steps += 1; 105 | } 106 | //println!("tips_anticone(): tip={} final result: size_of_anticone={}", tip_name, anticone.len()); 107 | 108 | if iteration_steps >= ANTICONE_MAX_ITERATION { 109 | warn!("tips_anticone(): tip={}. too many iterations! force to break.", tip_name); 110 | } 111 | 112 | return anticone; 113 | } 114 | 115 | /// Function providing anti-cone blue counting, optimized for k: exit if counter > k already. No limitation, any block can be the input block. 116 | /// 117 | /// 'any_name' block may have no relationship with tips. 118 | /// 'classmates' collect blocks name whose height is same. 119 | /// 'tips' here is the unique identification of the block DAG G, denotes all those reachable blocks from tips blocks. 120 | /// 121 | pub fn anticone_blue(any_name: &str, node: &Node, tips: &HashMap>>, k: i32) -> (i32,HashMap>>) { 122 | 123 | if tips.get(any_name).is_some() { 124 | return tips_anticone_blue(any_name, tips, k); 125 | } 126 | 127 | // firstly, we have to create a virtual tips, a nice way is to find the block's tips snapshot when it's added to the dag, plus the classmates blocks. 128 | let dag = &node.dag; 129 | let mut virtual_tips = dag.get(any_name).unwrap().read().unwrap().tips_snapshot.clone(); 130 | let height = dag.get(any_name).unwrap().read().unwrap().height; 131 | { 132 | let classmates = node.classmates.get(&height).unwrap(); 133 | for classmate_name in classmates { 134 | let tip = Arc::clone(dag.get(classmate_name).unwrap()); 135 | virtual_tips.entry(classmate_name.clone()).or_insert(tip); 136 | } 137 | } 138 | debug!("anticone_blue(): k={}. virtual tips={:?}", k, sorted_keys_by_height(&virtual_tips, false).iter().map(|&(ref n,_)|{n}).collect::>()); 139 | 140 | // left half 141 | let (anticone_blue_count_left,mut anticone_left) = tips_anticone_blue(any_name, &virtual_tips, k); 142 | debug!("anticone_blue(): left half anticone_blue_count={}, anticone_blue={:?}", anticone_blue_count_left, sorted_keys_by_height(&anticone_left, true).iter().map(|&(ref n,_)|{n}).collect::>()); 143 | if anticone_blue_count_left > k { 144 | return (anticone_blue_count_left, anticone_left); 145 | } 146 | 147 | // right half 148 | let (anticone_blue_count_right,anticone_right) = tips_anticone_blue_rev(any_name, &virtual_tips, k-anticone_blue_count_left); 149 | debug!("anticone_blue(): right half anticone_blue_count={}", anticone_blue_count_right); 150 | append_maps(&mut anticone_left, &anticone_right); 151 | 152 | return (anticone_blue_count_left+anticone_blue_count_right, anticone_left); 153 | } 154 | 155 | /// Function providing anti-cone blue counting, optimized for k: exit once counter > k already. Limitation: input block must be one of tips. 156 | /// 157 | pub fn tips_anticone_blue(tip_name: &str, tips: &HashMap>>, k: i32) -> (i32,HashMap>>){ 158 | 159 | debug!("tips_anticone_blue(): tip={} func enter. tips={:?}", tip_name, sorted_keys_by_height(tips, true).iter().map(|&(ref n,_)|{n}).collect::>()); 160 | 161 | let mut anticone_blue_count: i32 = 0; 162 | let mut anticone: HashMap>> = HashMap::new(); 163 | 164 | if tips.len()==0 { 165 | error!("tips_anticone_blue(): tip={} error! tips is empty", tip_name); 166 | return (-1,anticone); 167 | } 168 | 169 | let mut maxi_pred_set: HashMap>> = HashMap::new(); 170 | let mut rest_pred_set: HashMap>> = HashMap::new(); 171 | 172 | for (key, value) in tips { 173 | 174 | if key == tip_name { 175 | maxi_pred_set.insert(String::from(key.clone()), Arc::clone(value)); 176 | }else { 177 | rest_pred_set.insert(String::from(key.clone()), Arc::clone(value)); 178 | 179 | let tip = &value.read().unwrap(); 180 | if tip.is_blue { 181 | anticone.insert(String::from(key.clone()), Arc::clone(value)); 182 | anticone_blue_count += 1; 183 | } 184 | } 185 | } 186 | 187 | if maxi_pred_set.len()==0 { 188 | error!("tips_anticone_blue(): error! tip {} is not in tips", tip_name); 189 | return (-1,HashMap::new()); 190 | } 191 | 192 | debug!("tips_anticone_blue(): tip={} size_of_anticone_blue={}", tip_name, anticone.len()); 193 | 194 | let mut used_rest: HashMap = HashMap::new(); 195 | let mut used_maxi: HashMap = HashMap::new(); 196 | 197 | let mut rest_maxmin = MaxMin{max:0, min:::max_value()}; 198 | let mut maxi_maxmin = MaxMin{max:0, min:::max_value()}; 199 | 200 | while rest_pred_set.len() > 0 && anticone_blue_count <= k { 201 | 202 | let mut new_rest_pred: HashMap>> = HashMap::new(); 203 | let _rest_local_maxmin = step_one_past(&rest_pred_set, &mut new_rest_pred, &mut used_rest, &mut rest_maxmin); 204 | 205 | // let mut maxi_height_max = 0; 206 | loop { 207 | let mut new_maxi_pred: HashMap>> = HashMap::new(); 208 | let max_local_maxmin = step_one_past(&maxi_pred_set, &mut new_maxi_pred, &mut used_maxi, &mut maxi_maxmin); 209 | 210 | append_maps(&mut maxi_pred_set, &new_maxi_pred); 211 | drop(new_maxi_pred); 212 | 213 | if max_local_maxmin.max <= rest_maxmin.min { 214 | // maxi_height_max = max_local_maxmin.max; 215 | break; 216 | } 217 | } 218 | 219 | // debug!("tips_anticone_blue(): tip={} rest_height_min={} rest={:?} maxi_height_max={} max={:?} size_of_anticone={}", tip_name, rest_maxmin.min, 220 | // sorted_keys_by_height(&new_rest_pred, true).iter().map(|&(ref n,_)|{n}).collect::>(), 221 | // maxi_height_max, sorted_keys_by_height(&maxi_pred_set, true).iter().map(|&(ref n,_)|{n}).collect::>(), 222 | // anticone.len()); 223 | let rest_keys = new_rest_pred.iter().map(|(k,_)|{k.clone()}).collect::>(); 224 | for name in &rest_keys { 225 | if maxi_pred_set.get(name).is_some() { 226 | new_rest_pred.remove(name); 227 | } 228 | } 229 | 230 | for (key, value) in &new_rest_pred { 231 | 232 | let rest = &value.read().unwrap(); 233 | if rest.is_blue { 234 | if let Entry::Vacant(v) = anticone.entry(key.clone()) { 235 | v.insert(Arc::clone(value)); 236 | anticone_blue_count += 1; 237 | } 238 | } 239 | } 240 | 241 | rest_pred_set = new_rest_pred; 242 | debug!("tips_anticone_blue(): tip={} size_of_anticone={} rest_pred_set={}", tip_name, anticone.len(), rest_pred_set.len()); 243 | } 244 | debug!("tips_anticone_blue(): tip={} final result: size_of_anticone={}", tip_name, anticone.len()); 245 | 246 | return (anticone_blue_count,anticone); 247 | } 248 | 249 | 250 | /// Function providing anti-cone blue counting, optimized for k: exit once counter > k already, but step in reverse direction. Limitation: input block must be one of tips. 251 | /// 252 | pub fn tips_anticone_blue_rev(tip_name: &str, tips: &HashMap>>, k: i32) -> (i32,HashMap>>){ 253 | 254 | let mut anticone_blue_count: i32 = 0; 255 | let mut anticone: HashMap>> = HashMap::new(); 256 | 257 | if tips.len()==0 { 258 | error!("tips_anticone_blue_rev(): tip={} error! tips is empty", tip_name); 259 | return (-1,anticone); 260 | } 261 | 262 | let mut maxi_pred_set: HashMap>> = HashMap::new(); 263 | let mut rest_pred_set: HashMap>> = HashMap::new(); 264 | 265 | for (key, value) in tips { 266 | 267 | if key == tip_name { 268 | maxi_pred_set.insert(String::from(key.clone()), Arc::clone(value)); 269 | }else { 270 | rest_pred_set.insert(String::from(key.clone()), Arc::clone(value)); 271 | } 272 | } 273 | 274 | if maxi_pred_set.len()==0 { 275 | error!("tips_anticone_blue_rev(): error! tip {} is not in tips", tip_name); 276 | return (-1,HashMap::new()); 277 | } 278 | 279 | debug!("tips_anticone_blue_rev(): tip={} size_of_anticone_blue={}", tip_name, anticone.len()); 280 | 281 | let mut used_rest: HashMap = HashMap::new(); 282 | let mut used_maxi: HashMap = HashMap::new(); 283 | 284 | let mut rest_maxmin = MaxMin{max:0, min:::max_value()}; 285 | let mut maxi_maxmin = MaxMin{max:0, min:::max_value()}; 286 | 287 | while rest_pred_set.len() > 0 && anticone_blue_count <= k { 288 | 289 | let mut new_rest_pred: HashMap>> = HashMap::new(); 290 | let _rest_local_maxmin = step_one_next(&rest_pred_set, &mut new_rest_pred, &mut used_rest, &mut rest_maxmin); 291 | 292 | // let mut maxi_height_min = 0; 293 | loop { 294 | let mut new_maxi_pred: HashMap>> = HashMap::new(); 295 | let max_local_maxmin = step_one_next(&maxi_pred_set, &mut new_maxi_pred, &mut used_maxi, &mut maxi_maxmin); 296 | 297 | append_maps(&mut maxi_pred_set, &new_maxi_pred); 298 | drop(new_maxi_pred); 299 | 300 | if max_local_maxmin.min >= rest_maxmin.max { 301 | // maxi_height_min = max_local_maxmin.min; 302 | break; 303 | } 304 | } 305 | 306 | // debug!("tips_anticone_blue_rev(): tip={} rest_height_max={} rest={:?} maxi_height_min={} max={:?} size_of_anticone={}", tip_name, rest_maxmin.max, 307 | // sorted_keys_by_height(&new_rest_pred, true).iter().map(|&(ref n,_)|{n}).collect::>(), 308 | // maxi_height_min, sorted_keys_by_height(&maxi_pred_set, true).iter().map(|&(ref n,_)|{n}).collect::>(), 309 | // anticone.len()); 310 | let rest_keys = new_rest_pred.iter().map(|(k,_)|{k.clone()}).collect::>(); 311 | for name in &rest_keys { 312 | if maxi_pred_set.get(name).is_some() { 313 | new_rest_pred.remove(name); 314 | } 315 | } 316 | 317 | for (key, value) in &new_rest_pred { 318 | 319 | let rest = &value.read().unwrap(); 320 | if rest.is_blue { 321 | if let Entry::Vacant(v) = anticone.entry(key.clone()) { 322 | v.insert(Arc::clone(value)); 323 | anticone_blue_count += 1; 324 | } 325 | } 326 | } 327 | 328 | rest_pred_set = new_rest_pred; 329 | debug!("tips_anticone_blue_rev(): tip={} size_of_anticone_blue={} rest_pred_set={}", tip_name, anticone.len(), rest_pred_set.len()); 330 | } 331 | debug!("tips_anticone_blue_rev(): tip={} final result: size_of_anticone_blue={}", tip_name, anticone.len()); 332 | 333 | return (anticone_blue_count,anticone); 334 | } 335 | 336 | fn step_one_next(pred: &HashMap>>, new_pred: &mut HashMap>>, used: &mut HashMap, maxmin: &mut MaxMin) -> MaxMin{ 337 | 338 | let mut local_maxmin = MaxMin{max:0, min:::max_value()}; 339 | 340 | for (key, value) in pred { 341 | if let Entry::Vacant(v) = used.entry(key.clone()){ 342 | 343 | let rest = Arc::clone(value); 344 | let rest = rest.read().unwrap(); 345 | 346 | for (key2, value2) in &rest.next { 347 | 348 | if let Entry::Vacant(v) = new_pred.entry(key2.clone()) { 349 | let prev = Arc::clone(value2); 350 | let prev = prev.read().unwrap(); 351 | 352 | if prev.height > local_maxmin.max { 353 | local_maxmin.max = prev.height; 354 | } 355 | 356 | if prev.height < local_maxmin.min { 357 | local_maxmin.min = prev.height; 358 | } 359 | 360 | v.insert(Arc::clone(value2)); 361 | } 362 | } 363 | 364 | v.insert(true); 365 | } 366 | } 367 | 368 | if local_maxmin.max > maxmin.max { 369 | maxmin.max = local_maxmin.max; 370 | } 371 | 372 | if local_maxmin.min < maxmin.min { 373 | maxmin.min = local_maxmin.min; 374 | } 375 | 376 | return local_maxmin; 377 | } 378 | 379 | 380 | 381 | -------------------------------------------------------------------------------- /blockdag/src/blockdag/block.rs: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2018 The rust-dag Authors 3 | // This file is part of the rust-dag library. 4 | // 5 | // The rust-dag library is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU Lesser General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // The rust-dag library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public License 16 | // along with the rust-dag library. If not, see . 17 | 18 | use std::collections::HashMap; 19 | use std::collections::hash_map::Entry; 20 | use std::sync::{Arc,RwLock}; 21 | use std::fmt; 22 | use std::cmp::Ordering; 23 | 24 | /// Structure providing fast access to block data. 25 | /// 26 | pub struct Block{ 27 | pub name: String, // bits stream, local verified. that is: hash of block head. (in simulation we use a readable string) 28 | pub height: u64, // bits stream, local verified. 29 | pub size_of_past_set: u64, // bits stream, local verified. 30 | pub size_of_past_blue: u64, // local generated. 31 | pub is_blue: bool, // local generated. 32 | pub size_of_anticone_blue: i32, // local generated. 33 | pub prev: HashMap>>, // bits stream. 34 | pub next: HashMap>>, // local generated, not in bits stream transmitting 35 | pub tips_snapshot: HashMap>>, // local generated. a snapshot of tips at the time of block added to the local dag. after added. 36 | } 37 | 38 | #[derive(Clone, Debug)] 39 | pub struct BlockRaw{ // simulation of raw block data 40 | pub name: String, // bits stream, local verified. that is: hash of block head. (in simulation we use a readable string) 41 | pub height: u64, // bits stream, local verified. 42 | pub size_of_past_set: u64, // bits stream, local verified. 43 | pub prev: Vec, // bits stream. 44 | } 45 | 46 | 47 | 48 | pub struct MaxMin{ 49 | pub max: u64, 50 | pub min: u64, 51 | } 52 | 53 | impl fmt::Display for Block { 54 | 55 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 56 | 57 | let mut formated_info = if self.is_blue { 58 | format!("name={},height={},size_of_past_set={},size_of_past_blue={},blue=1,prev=", self.name, self.height, self.size_of_past_set, self.size_of_past_blue) 59 | }else{ 60 | format!("name={},height={},size_of_past_set={},size_of_past_blue={},blue=0,prev=", self.name, self.height, self.size_of_past_set, self.size_of_past_blue) 61 | }; 62 | 63 | formated_info.push_str(&format!("{:?}", sorted_keys_by_height(&self.prev, false).iter().map(|&(ref n,_)|{n}).collect::>())); 64 | 65 | write!(f, "{}", formated_info) 66 | } 67 | } 68 | 69 | pub fn append_maps(target: &mut HashMap>>, source: &HashMap>>){ 70 | 71 | for (key, value) in source { 72 | 73 | if let Entry::Vacant(v) = target.entry(key.clone()){ 74 | v.insert(Arc::clone(value)); 75 | } 76 | } 77 | } 78 | 79 | /// Remove from the list all the block predecessors and successors which is in the list, self included. 80 | /// 81 | pub fn remove_past_future(block: &Block, list: &mut HashMap>>){ 82 | 83 | let exist = list.remove(&String::from(block.name.clone())); 84 | if exist.is_none() { 85 | return; 86 | } 87 | 88 | remove_successors(block, list); 89 | remove_predecessors(block, list); 90 | } 91 | 92 | 93 | /// Remove from the list all the block successors which is in the list, self not included. 94 | /// 95 | fn remove_successors(block: &Block, list: &mut HashMap>>){ 96 | 97 | for (_key, value) in &block.next { 98 | 99 | let next = Arc::clone(value); 100 | let next = next.read().unwrap(); 101 | 102 | let exist = list.remove(&String::from(next.name.clone())); 103 | if exist.is_some() { 104 | remove_successors(&next, list); 105 | } 106 | } 107 | } 108 | 109 | /// Remove from the list all the block predecessors which is in the list, self not included. 110 | /// 111 | fn remove_predecessors(block: &Block, list: &mut HashMap>>){ 112 | 113 | for (_key, value) in &block.prev { 114 | 115 | let prev = Arc::clone(value); 116 | let prev = prev.read().unwrap(); 117 | 118 | let exist = list.remove(&String::from(prev.name.clone())); 119 | if exist.is_some() { 120 | remove_predecessors(&prev, list); 121 | } 122 | } 123 | } 124 | 125 | 126 | pub fn sorted_keys_by_height(source: &HashMap>>, reverse: bool) -> Vec<(String, u64)>{ 127 | 128 | let mut keys_vec: Vec<(String, u64)> = Vec::new(); 129 | 130 | for (_key, value) in source { 131 | let block = Arc::clone(value); 132 | let block = block.read().unwrap(); 133 | 134 | keys_vec.push((String::from(block.name.clone()), block.height)); 135 | } 136 | 137 | if reverse==true { 138 | keys_vec.sort_by(|a, b| { 139 | match a.1.cmp(&b.1).reverse() { 140 | Ordering::Equal => a.0.cmp(&b.0), 141 | other => other, 142 | } 143 | }); 144 | }else{ 145 | keys_vec.sort_by(|a, b| { 146 | match a.1.cmp(&b.1) { 147 | Ordering::Equal => a.0.cmp(&b.0), 148 | other => other, 149 | } 150 | }); 151 | } 152 | return keys_vec; 153 | } 154 | 155 | /// lexicographical topological priority queue. 156 | /// 157 | pub fn get_ltpq(source: &HashMap>>) -> Vec<(String, u64)>{ 158 | 159 | let mut keys_vec: Vec<(String, u64)> = Vec::new(); 160 | 161 | for (_key, value) in source { 162 | let block = Arc::clone(value); 163 | let block = block.read().unwrap(); 164 | 165 | keys_vec.push((String::from(block.name.clone()), block.size_of_past_set)); 166 | } 167 | 168 | keys_vec.sort_by(|a, b| { 169 | match a.1.cmp(&b.1).reverse() { 170 | Ordering::Equal => a.0.cmp(&b.0), 171 | other => other, 172 | } 173 | }); 174 | 175 | return keys_vec; 176 | } 177 | 178 | /// score topological priority queue. 179 | /// 180 | /// where the score of a block is defined as the number of blue blocks in its past: score(B) := |BLUEk (past(B))|. 181 | /// 182 | pub fn get_stpq(source: &HashMap>>) -> Vec<(String, u64, u64)>{ 183 | 184 | let mut keys_vec: Vec<(String, u64, u64)> = Vec::new(); 185 | 186 | for (_key, value) in source { 187 | let block = Arc::clone(value); 188 | let block = block.read().unwrap(); 189 | 190 | keys_vec.push((String::from(block.name.clone()), block.size_of_past_blue, block.size_of_past_set)); 191 | } 192 | 193 | keys_vec.sort_by(|a, b| { 194 | match a.1.cmp(&b.1).reverse() { 195 | Ordering::Equal => { 196 | match a.2.cmp(&b.2).reverse() { 197 | Ordering::Equal => a.0.cmp(&b.0), 198 | other => other, 199 | } 200 | }, 201 | other => other, 202 | } 203 | }); 204 | 205 | return keys_vec; 206 | } 207 | 208 | 209 | 210 | // Move from the list all the block successors which is in the list, self not included, to the target list. 211 | // 212 | //fn move_successors(block: &Block, list: &mut HashMap>>, target: &mut HashMap>>){ 213 | // 214 | // for (_key, value) in &block.next { 215 | // 216 | // let next = Arc::clone(value); 217 | // let next = next.read().unwrap(); 218 | // 219 | // move_successors(&next, list, target); 220 | // 221 | // let exist = list.remove(&next.name.clone()); 222 | // if exist.is_some() { 223 | // target.entry(String::from(next.name.clone())) 224 | // .or_insert(Arc::clone(value)); 225 | // } 226 | // } 227 | //} -------------------------------------------------------------------------------- /blockdag/src/blockdag/calcblue.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The rust-dag Authors 2 | // This file is part of the rust-dag library. 3 | // 4 | // The rust-dag library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The rust-dag library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with the rust-dag library. If not, see . 16 | 17 | use std::collections::HashMap; 18 | use std::sync::{Arc,RwLock}; 19 | 20 | use blockdag::{Block,Node,tips_anticone,tips_anticone_blue,anticone_blue,get_ltpq,get_stpq,sorted_keys_by_height,sizeof_pastset}; 21 | 22 | /// Function providing blue block calculation. 23 | /// 24 | /// input 'block': a new added block to be calculated. before call this function, tips must have been updated for this new block. 25 | /// 26 | pub fn calc_blue(block_name: &str, node: &mut Node, k: i32){ 27 | 28 | debug!("calc_blue(): block {}. func enter.", block_name); 29 | 30 | let dag = &node.dag; 31 | 32 | { 33 | let block = dag.get(block_name); 34 | if block.is_none() { 35 | error!("calc_blue(): error! block {} not exist in dag.", block_name); 36 | return; 37 | } 38 | } // scope to limit the lifetime of block. 39 | 40 | if block_name=="Genesis" { 41 | let mut block_w = dag.get(block_name).unwrap().write().unwrap(); 42 | block_w.is_blue = true; 43 | block_w.size_of_anticone_blue = 0; 44 | return; 45 | } 46 | 47 | let tips = &node.tips; 48 | if tips.len() == 0 { 49 | error!("calc_blue(): error! tips must not be empty."); 50 | return; 51 | } 52 | 53 | // step 2 54 | let score_stpq = get_stpq(tips); 55 | 56 | debug!("calc_blue(): block {}.tip_max_name={},max_past_blue={}. tips={:?}", block_name, score_stpq[0].0, score_stpq[0].1, 57 | sorted_keys_by_height(tips, false).iter().map(|&(ref n,_)|{n}).collect::>()); 58 | 59 | // step 3 60 | if &score_stpq[0].0 == block_name { 61 | 62 | debug!("calc_blue(): step 3. block {}. new block is the max past blue", block_name); 63 | 64 | // step 4. clear all others tip's blue flag 65 | for (_key, value) in tips { 66 | 67 | let block = Arc::clone(value); 68 | let tip = &mut block.write().unwrap(); 69 | if &tip.name != block_name { 70 | tip.is_blue = false; 71 | tip.size_of_anticone_blue = -1; 72 | } 73 | } 74 | 75 | // step 5 76 | for &(ref name,_,_) in &score_stpq { 77 | 78 | // step 6 79 | let (blues, blue_anticone) = tips_anticone_blue(name, tips, k); 80 | if blues < 0 || blues > k { 81 | debug!("calc_blue(): block {}. tip {} size_of_anticone_blue={} not blue.", block_name, name, blues); 82 | }else { 83 | // step 7 84 | { 85 | let mut block_w = dag.get(name).unwrap().write().unwrap(); 86 | block_w.is_blue = true; 87 | block_w.size_of_anticone_blue = blues; 88 | drop(block_w); 89 | debug!("calc_blue(): step 4.1. block {}. add {} to the blue. size_of_anticone_blue={}", block_name, name, blues); 90 | } // scope to limit the lifetime of 'write()' lock. 91 | 92 | // step 8 93 | check_blue(&blue_anticone, k); 94 | } 95 | 96 | } // scope to limit the lifetime of blue_anticone. 97 | 98 | // step 9 99 | // let block_r = dag.get(block_name).unwrap().read().unwrap(); 100 | // let prev_keys = get_ltpq(&block_r.prev); 101 | // drop(block_r); // must be released immediately, otherwise the following loop could enter deadlock. 102 | 103 | // another algorithm, to check all the anticone(bmax), not only the predecessor(z;G) 104 | let anticone_of_new = tips_anticone(block_name, tips); 105 | let prev_keys = get_ltpq(&anticone_of_new); 106 | drop(anticone_of_new); 107 | 108 | for &(ref name,_) in &prev_keys { 109 | 110 | if dag.get(name).unwrap().read().unwrap().is_blue { 111 | continue; 112 | } // if expression has an implicit scope, so the 'read()' lock will be released immediately after if {}. 113 | 114 | debug!("calc_blue(): step 6. block {}. come to block {}", block_name, name); 115 | { 116 | // step 10 117 | let (blues, blue_anticone) = anticone_blue(name, node, tips, k); 118 | 119 | if blues >= 0 && blues <= k { 120 | 121 | // step 11 122 | debug!("calc_blue(): step 7. block {}. query block {}: size_of_anticone_blue={}. try to write_lock {}", block_name, name, blues, name); 123 | { 124 | let mut pred = dag.get(name).unwrap().write().unwrap(); 125 | pred.is_blue = true; 126 | pred.size_of_anticone_blue = blues; 127 | debug!("calc_blue(): step 7. block {}. add {} to the blue. size_of_anticone_blue={}", block_name, pred.name, blues); 128 | 129 | } // scope to limit the lifetime of 'write()' lock. 130 | 131 | // step 12 132 | check_blue(&blue_anticone, k); 133 | } 134 | } // scope to limit the lifetime of blue_anticone. 135 | } 136 | 137 | // step 9. have to re-calculate 'size_of_past_blue' (for those successors) because 'blue' state changed. 138 | for &(ref name,_) in &prev_keys { 139 | 140 | let block = &dag.get(name).unwrap(); 141 | let (_,size_of_past_blue) = sizeof_pastset(&block.read().unwrap()); 142 | { 143 | let block_w = &mut block.write().unwrap(); 144 | block_w.size_of_past_blue = size_of_past_blue; 145 | } 146 | } 147 | 148 | }else{ 149 | 150 | debug!("calc_blue(): block {}. new block is not the max past blue", block_name); 151 | 152 | // step 16 153 | let (blues,blue_anticone) = tips_anticone_blue(block_name, tips, k); 154 | debug!("calc_blue(): step 11. block {}. size_of_anticone_blue={}", block_name, blues); 155 | if blues>=0 && blues<=k { 156 | 157 | let mut block_w = dag.get(block_name).unwrap().write().unwrap(); 158 | 159 | // step 17 160 | block_w.is_blue = true; 161 | block_w.size_of_anticone_blue = blues; 162 | //println!("calc_blue(): block {}. add {} to the blue. size_of_anticone_blue={}", block_name, block_w.name, blues); 163 | drop(block_w); 164 | 165 | // step 18 166 | check_blue(&blue_anticone, k); 167 | } 168 | } 169 | 170 | 171 | } 172 | 173 | fn check_blue(blue_anticone: &HashMap>>, _k: i32) { 174 | 175 | for (_key, value) in blue_anticone { 176 | 177 | //debug!("check_blue(): try to write_lock {}", key); 178 | let mut block_w = value.write().unwrap(); 179 | block_w.size_of_anticone_blue += 1; 180 | //debug!("check_blue(): {} size_of_anticone_blue increase to {}", block_w.name, block_w.size_of_anticone_blue); 181 | } 182 | } 183 | 184 | 185 | 186 | // Function update all successors (recursively) of this block, if it's blue, size_of_past_blue minus 1. 187 | // 188 | // todo: this iteration could be terrible in performance! 189 | // 190 | //fn dec_successors_past_blue(block: &Block, used: &mut HashMap){ 191 | // 192 | // for (key, value) in &block.next { 193 | // 194 | // if used.get(key).is_some() { 195 | // continue; 196 | // }else{ 197 | // used.insert(key.clone(), true); 198 | // } 199 | // 200 | // //debug!("dec_successors_anticone_blue(): try to write_lock {}", key); 201 | // { 202 | // let mut next = value.write().unwrap(); 203 | // if next.is_blue { 204 | // next.size_of_past_blue -= 1; 205 | // } 206 | // } // scope to limit the lifetime of 'write()' lock. 207 | // 208 | // let next = &value.read().unwrap(); 209 | // dec_successors_past_blue(next, used); 210 | // } 211 | //} -------------------------------------------------------------------------------- /blockdag/src/blockdag/cardinality.rs: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2018 The rust-dag Authors 3 | // This file is part of the rust-dag library. 4 | // 5 | // The rust-dag library is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU Lesser General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // The rust-dag library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public License 16 | // along with the rust-dag library. If not, see . 17 | 18 | use std::collections::HashMap; 19 | use std::collections::hash_map::Entry; 20 | use std::sync::{Arc,RwLock}; 21 | 22 | use blockdag::{Block,MaxMin,append_maps}; 23 | 24 | /// Function providing cardinality of pastset blocks calculation. 25 | /// 26 | pub fn sizeof_pastset(block: &Block) -> (u64,u64){ 27 | 28 | let mut size_of_past: u64 = 0; 29 | let mut size_of_past_blue: u64 = 0; 30 | 31 | if block.prev.len()==0 { 32 | return (size_of_past,size_of_past_blue); 33 | } 34 | 35 | let mut maxi_pred_set: HashMap>> = HashMap::new(); 36 | let mut rest_pred_set: HashMap>> = HashMap::new(); 37 | 38 | // find the max sizeofpast among block's predecessors 39 | let mut max_sizeofpast: u64 = 0; 40 | let mut bmax_name = String::new(); 41 | 42 | for (_key, value) in &block.prev { 43 | 44 | let prev = Arc::clone(value); 45 | let prev = prev.read().unwrap(); 46 | 47 | if max_sizeofpast < prev.size_of_past_set { 48 | max_sizeofpast = prev.size_of_past_set; 49 | bmax_name = String::from(prev.name.clone()); 50 | } 51 | 52 | if prev.name == "Genesis" { 53 | return (1,1); 54 | } 55 | 56 | if prev.is_blue { 57 | size_of_past_blue += 1; 58 | } 59 | 60 | rest_pred_set.insert(String::from(prev.name.clone()), Arc::clone(value)); 61 | } 62 | 63 | if bmax_name.len()==0 { 64 | panic!("sizeof_pastset(): impossible! bmax=nil."); 65 | } 66 | 67 | let bmax_block = block.prev.get(&bmax_name).unwrap(); 68 | maxi_pred_set.insert(bmax_name.clone(), Arc::clone(bmax_block)); 69 | 70 | rest_pred_set.remove(&bmax_name); 71 | 72 | size_of_past = max_sizeofpast + block.prev.len() as u64; 73 | size_of_past_blue += bmax_block.read().unwrap().size_of_past_blue; 74 | //println!("sizeof_pastset(): block={} bmax={} size_of_past={}", block.name, bmax_name, size_of_past); 75 | 76 | let mut used_rest: HashMap = HashMap::new(); 77 | let mut used_maxi: HashMap = HashMap::new(); 78 | 79 | let mut rest_maxmin = MaxMin{max:0, min:::max_value()}; 80 | let mut maxi_maxmin = MaxMin{max:0, min:::max_value()}; 81 | 82 | while rest_pred_set.len() > 0 { 83 | 84 | let mut new_rest_pred: HashMap>> = HashMap::new(); 85 | let _rest_local_maxmin = step_one_past(&rest_pred_set, &mut new_rest_pred, &mut used_rest, &mut rest_maxmin); 86 | 87 | //let mut maxi_height_max = 0; 88 | loop { 89 | let mut new_maxi_pred: HashMap>> = HashMap::new(); 90 | let max_local_maxmin = step_one_past(&maxi_pred_set, &mut new_maxi_pred, &mut used_maxi, &mut maxi_maxmin); 91 | 92 | append_maps(&mut maxi_pred_set, &new_maxi_pred); 93 | drop(new_maxi_pred); 94 | 95 | if max_local_maxmin.max <= rest_maxmin.min { 96 | //maxi_height_max = max_local_maxmin.max; 97 | break; 98 | } 99 | } 100 | 101 | //println!("sizeof_pastset(): block={} rest_height_min={} rest={:?} maxi_height_max={} max={:?} size_of_past={}", block.name, rest_maxmin.min, 102 | // sorted_keys_by_height(&new_rest_pred, false).iter().map(|&(ref n,_)|{n}).collect::>(), 103 | // maxi_height_max, sorted_keys_by_height(&maxi_pred_set, false).iter().map(|&(ref n,_)|{n}).collect::>(), 104 | // size_of_past); 105 | let rest_keys = new_rest_pred.iter().map(|(k,_)|{k.clone()}).collect::>(); 106 | for name in &rest_keys { 107 | if maxi_pred_set.get(name).is_some() { 108 | new_rest_pred.remove(name); 109 | } 110 | } 111 | 112 | size_of_past += new_rest_pred.len() as u64; 113 | for (_,value) in &new_rest_pred { 114 | let rest = &value.read().unwrap(); 115 | if rest.is_blue { 116 | size_of_past_blue += 1; 117 | } 118 | } 119 | 120 | drop(rest_pred_set); 121 | rest_pred_set = new_rest_pred; 122 | //println!("sizeof_pastset(): block={} size_of_past={} rest_pred_set={}", block.name, size_of_past, rest_pred_set.len()); 123 | } 124 | //println!("sizeof_pastset(): block={} final result: size_of_past={}", block.name, size_of_past); 125 | 126 | return (size_of_past,size_of_past_blue); 127 | } 128 | 129 | pub fn step_one_past(pred: &HashMap>>, new_pred: &mut HashMap>>, used: &mut HashMap, maxmin: &mut MaxMin) -> MaxMin{ 130 | 131 | let mut local_maxmin = MaxMin{max:0, min:::max_value()}; 132 | 133 | for (key, value) in pred { 134 | if let Entry::Vacant(v) = used.entry(key.clone()){ 135 | 136 | let rest = Arc::clone(value); 137 | let rest = rest.read().unwrap(); 138 | 139 | for (key2, value2) in &rest.prev { 140 | 141 | if let Entry::Vacant(v) = new_pred.entry(key2.clone()) { 142 | let prev = Arc::clone(value2); 143 | let prev = prev.read().unwrap(); 144 | 145 | if prev.height > local_maxmin.max { 146 | local_maxmin.max = prev.height; 147 | } 148 | 149 | if prev.height < local_maxmin.min { 150 | local_maxmin.min = prev.height; 151 | } 152 | 153 | v.insert(Arc::clone(value2)); 154 | } 155 | } 156 | 157 | v.insert(true); 158 | } 159 | } 160 | 161 | if local_maxmin.max > maxmin.max { 162 | maxmin.max = local_maxmin.max; 163 | } 164 | 165 | if local_maxmin.min < maxmin.min { 166 | maxmin.min = local_maxmin.min; 167 | } 168 | 169 | return local_maxmin; 170 | } 171 | 172 | -------------------------------------------------------------------------------- /blockdag/src/blockdag/dagsim.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The rust-dag Authors 2 | // This file is part of the rust-dag library. 3 | // 4 | // The rust-dag library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The rust-dag library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with the rust-dag library. If not, see . 16 | 17 | use std::collections::HashMap; 18 | use std::sync::{Arc,RwLock}; 19 | 20 | use blockdag::Block; 21 | use blockdag::{sizeof_pastset,sorted_keys_by_height}; 22 | 23 | pub fn dag_add_block(name: &str, references: &Vec<&str>, dag: &mut HashMap>>){ 24 | 25 | //create this block 26 | let this_block = Arc::new(RwLock::new(Block{ 27 | name: String::from(name.clone()), 28 | height: 0, 29 | size_of_past_set: 0, 30 | size_of_past_blue: 0, 31 | is_blue: false, 32 | size_of_anticone_blue: -1, 33 | prev: HashMap::new(), 34 | next: HashMap::new(), 35 | tips_snapshot: HashMap::new(), 36 | })); 37 | 38 | //add references 39 | 'outer: for reference in references { 40 | let value = dag.get(*reference); 41 | match value { 42 | None => { 43 | let except_message = format!("dag_add_block(): error! block reference invalid. block name = {} references = {}", name, reference); 44 | panic!(except_message); 45 | }, 46 | Some(block) => { 47 | let reference_block = Arc::clone(block); 48 | 49 | // add previous blocks to this block 50 | { 51 | let reference_block = reference_block.read().unwrap(); 52 | 53 | // if reference_block.is_blue == false { 54 | // continue 'outer; 55 | // } 56 | 57 | let mut this_block_w = this_block.write().unwrap(); 58 | this_block_w.prev.insert(reference_block.name.clone(), Arc::clone(block)); 59 | 60 | // height is the maximum previous height +1 61 | if reference_block.height+1 > this_block_w.height { 62 | this_block_w.height = reference_block.height+1; 63 | } 64 | } 65 | 66 | // add self as previous block's next 67 | let mut reference_block = reference_block.write().unwrap(); 68 | reference_block.next.insert(String::from(name.clone()), Arc::clone(&this_block)); 69 | } 70 | } 71 | } 72 | 73 | // size of pastset 74 | let (size_of_past_set,size_of_past_blue) = sizeof_pastset(&this_block.read().unwrap()); 75 | { 76 | let mut this_block_w = this_block.write().unwrap(); 77 | this_block_w.size_of_past_set = size_of_past_set; 78 | this_block_w.size_of_past_blue = size_of_past_blue; 79 | } 80 | 81 | dag.insert(String::from(name.clone()), this_block); 82 | } 83 | 84 | pub fn dag_print(dag: &HashMap>>) -> String{ 85 | 86 | let sorted_keys = sorted_keys_by_height(dag, false); 87 | 88 | let mut formatted_info = String::from("dag={\n"); 89 | for (name,_) in sorted_keys { 90 | let block = dag.get(&name); 91 | if block.is_some() { 92 | let block = Arc::clone(block.unwrap()); 93 | let block = block.read().unwrap(); 94 | formatted_info.push_str(&format!("{{name={},block={}}}\n", name, block)); 95 | } 96 | } 97 | formatted_info.push_str("}"); 98 | info!("{}",formatted_info); 99 | return formatted_info; 100 | } 101 | 102 | pub fn dag_blue_print(dag: &HashMap>>) -> String{ 103 | 104 | let mut total_blues = 0; 105 | let sorted_keys = sorted_keys_by_height(dag, false); 106 | 107 | let mut formatted_info = String::from("blues={"); 108 | for &(ref name,_) in &sorted_keys { 109 | let block = dag.get(name); 110 | if block.is_some() { 111 | let block = block.unwrap().read().unwrap(); 112 | if block.is_blue { 113 | if total_blues<=1000 { 114 | formatted_info.push_str(&format!("{},", name)); 115 | } 116 | total_blues += 1; 117 | } 118 | } 119 | } 120 | if total_blues>=1000 { 121 | formatted_info.push_str("..."); 122 | } 123 | formatted_info.push_str(&format!("}} total={}/{}",total_blues,dag.len())); 124 | return formatted_info; 125 | } 126 | 127 | pub fn dag_red_print(dag: &HashMap>>) -> String{ 128 | 129 | let mut total_reds = 0; 130 | let sorted_keys = sorted_keys_by_height(dag, false); 131 | 132 | let mut formatted_info = String::from("reds ={"); 133 | for &(ref name,_) in &sorted_keys { 134 | let block = dag.get(name); 135 | if block.is_some() { 136 | let block = block.unwrap().read().unwrap(); 137 | if !block.is_blue { 138 | formatted_info.push_str(&format!("{},", name)); 139 | total_reds += 1; 140 | } 141 | } 142 | } 143 | formatted_info.push_str(&format!("}} total={}/{}",total_reds,dag.len())); 144 | return formatted_info; 145 | } -------------------------------------------------------------------------------- /blockdag/src/blockdag/hourglass.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The rust-dag Authors 2 | // This file is part of the rust-dag library. 3 | // 4 | // The rust-dag library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The rust-dag library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with the rust-dag library. If not, see . 16 | 17 | //use std::collections::HashMap; 18 | //use std::collections::hash_map::Entry; 19 | //use std::sync::{Arc,RwLock}; 20 | // 21 | //use blockdag::{Block,Node,MaxMin,append_maps}; 22 | // 23 | //// Function providing blue hourglass blocks calculation. 24 | //// 25 | //// input 'block': add a new blue block 26 | //// 27 | //pub fn blue_hourglass_update(block: &Block, node: &mut Node){ 28 | // 29 | //// let dag = &node.dag; 30 | //// let hourglass = &node.hourglass; 31 | //} 32 | // 33 | //// Function looking for nearest hourglass pair. 34 | //// 35 | //// For example: Vec![ (2,4), (4,5), (7,8), (9,12), (15,19), (20,21) ] 36 | //// 37 | //pub fn get_nearest_hourglass(height: u64, hourglass: &Vec<(u64,u64)>) -> (u64,u64){ 38 | // 39 | // let mut nearest:(u64,u64) = (0,0); 40 | // 41 | // //todo: not efficient to use sequential loop for searching, to be improved. 42 | // for &(low,high) in hourglass { 43 | // if height>=high { 44 | // break; 45 | // } 46 | // 47 | // nearest = (low,high); 48 | // } 49 | // 50 | // return nearest; 51 | //} -------------------------------------------------------------------------------- /blockdag/src/blockdag/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2018 The rust-dag Authors 3 | // This file is part of the rust-dag library. 4 | // 5 | // The rust-dag library is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU Lesser General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // The rust-dag library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public License 16 | // along with the rust-dag library. If not, see . 17 | 18 | 19 | //use std::sync::Arc; 20 | 21 | mod block; 22 | mod node; 23 | mod dagsim; 24 | mod cardinality; 25 | mod anticone; 26 | mod hourglass; 27 | mod calcblue; 28 | 29 | pub use self::block::{Block,BlockRaw,MaxMin,append_maps,remove_past_future,sorted_keys_by_height,get_ltpq,get_stpq}; 30 | pub use self::node::{Node,node_add_block,update_tips,handle_block_rx}; 31 | pub use self::dagsim::{dag_add_block,dag_print,dag_blue_print,dag_red_print}; 32 | pub use self::cardinality::{sizeof_pastset,step_one_past}; 33 | pub use self::anticone::{tips_anticone,tips_anticone_blue,anticone_blue}; 34 | //pub use self::hourglass::{get_nearest_hourglass}; 35 | pub use self::calcblue::{calc_blue}; 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /blockdag/src/blockdag/node.rs: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2018 The rust-dag Authors 3 | // This file is part of the rust-dag library. 4 | // 5 | // The rust-dag library is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU Lesser General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // The rust-dag library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public License 16 | // along with the rust-dag library. If not, see . 17 | 18 | use std::collections::HashMap; 19 | use std::sync::{Arc,RwLock}; 20 | use std::fmt; 21 | 22 | use blockdag::{Block,BlockRaw}; 23 | use blockdag::{dag_add_block,sorted_keys_by_height,calc_blue}; 24 | 25 | /// Structure providing fast access to node data. 26 | /// 27 | pub struct Node{ 28 | pub name: String, 29 | pub height: u64, 30 | pub size_of_dag: u64, 31 | pub dag: HashMap>>, 32 | pub tips: HashMap>>, 33 | pub classmates: HashMap>, 34 | pub hourglass: Vec<(u64,u64)>, 35 | pub mined_blocks: u64, 36 | } 37 | 38 | impl Node { 39 | pub fn init(node_name: &str) -> Arc>{ 40 | 41 | let node = Arc::new(RwLock::new(Node{ 42 | name: String::from(node_name), 43 | height: 0, 44 | size_of_dag: 0, 45 | dag: HashMap::new(), 46 | tips: HashMap::new(), 47 | classmates: HashMap::new(), 48 | hourglass: Vec::new(), 49 | mined_blocks: 0 as u64, 50 | })); 51 | 52 | return node; 53 | } 54 | } 55 | 56 | impl fmt::Display for Node { 57 | 58 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 59 | 60 | let mut formatted_info = format!("node={},height={},size_of_dag={},dag={{", self.name, self.height, self.size_of_dag); 61 | 62 | let sorted_keys = sorted_keys_by_height(&self.dag, false); 63 | 64 | for (name,_) in sorted_keys { 65 | let tmp = format!("{},", &name); 66 | formatted_info.push_str(&tmp); 67 | } 68 | 69 | if self.dag.len() > 0 { 70 | formatted_info.pop(); 71 | } 72 | formatted_info.push_str("},tips={"); 73 | 74 | for (key, _value) in &self.tips { 75 | let tmp = format!("{},", key); 76 | formatted_info.push_str(&tmp); 77 | } 78 | 79 | if self.tips.len() > 0 { 80 | formatted_info.pop(); 81 | } 82 | 83 | formatted_info.push_str("}"); 84 | 85 | write!(f, "{}", formatted_info) 86 | } 87 | } 88 | 89 | //pub fn handle_block_tx(new_mined_block_name:&str, propagations: &mut HashMap>>, node: &Node, total_nodes: i32) { 90 | // 91 | // let new_mined_block = &node.dag.get(new_mined_block_name).unwrap().read().unwrap(); 92 | // let prev_names = new_mined_block.prev.iter().map(|(k,_)|{k.clone()}).collect::>(); 93 | // 94 | // let new_block_raw = BlockRaw{ 95 | // name:new_mined_block_name.clone().to_string(), 96 | // height: new_mined_block.height, 97 | // size_of_past_set: new_mined_block.size_of_past_set, 98 | // prev: prev_names, 99 | // propagation: total_nodes, 100 | // }; 101 | // 102 | // propagations.insert(new_mined_block_name.clone().to_string(), Arc::new(RwLock::new(new_block_raw))); 103 | // drop(propagations); 104 | //} 105 | 106 | pub fn handle_block_rx(block_rx: BlockRaw, node: &mut Node, stash: &mut HashMap, k: i32){ 107 | 108 | stash.entry(block_rx.name.clone()).or_insert(block_rx); 109 | 110 | // local processing with stash 111 | 112 | let mut block_added: Vec = Vec::new(); 113 | loop { 114 | 'outer: for (name_of_stash_block, stash_block) in &*stash { 115 | 116 | // before adding to dag, make sure all its predecessors are already in dag, otherwise skip it for this time. 117 | for prev in &stash_block.prev { 118 | let dag = &node.dag; 119 | if dag.get(prev).is_none() { 120 | continue 'outer; 121 | } 122 | } 123 | 124 | let prev_names = stash_block.prev.iter().map(|k| { &k[..] }).collect::>(); 125 | if true == node_add_block(name_of_stash_block, &prev_names, node, k, true) { 126 | block_added.push(name_of_stash_block.clone()); 127 | } 128 | } 129 | 130 | for added_name in &block_added { 131 | stash.remove(added_name); 132 | } 133 | 134 | if block_added.len()==0 { 135 | break; 136 | } 137 | // in cast one released stash block could release another stash block, loop check. 138 | block_added.truncate(0); 139 | } 140 | } 141 | 142 | pub fn node_add_block(name_of_new_block: &str, references: &Vec<&str>, node: &mut Node, k: i32, do_update_tips: bool) -> bool { 143 | 144 | // add block 145 | { 146 | let dag = &mut node.dag; 147 | if dag.get(name_of_new_block).is_some(){ 148 | return false; // block already received. 149 | } 150 | 151 | let classmates= &mut node.classmates; 152 | 153 | dag_add_block(name_of_new_block, references, dag); 154 | 155 | let block = dag.get(name_of_new_block); 156 | if block.is_some() { 157 | let block = Arc::clone(block.unwrap()); 158 | let block = block.read().unwrap(); 159 | if block.height > node.height { 160 | node.height = block.height; 161 | } 162 | 163 | // classmates update 164 | let classmate = classmates.entry(block.height).or_insert(vec![name_of_new_block.clone().into()]); 165 | if classmate.len() > 1 || classmate[0] != name_of_new_block { 166 | classmate.push(name_of_new_block.clone().into()); 167 | } 168 | //debug!("node_add_block(): new block={}. classmates update for height {}: {:?}", name_of_new_block, block.height, classmate); 169 | //todo: limit the classmates size, only keep latest heights. 170 | 171 | node.size_of_dag += 1; 172 | }else{ 173 | warn!("node_add_block(): block not found in dag. dag_add_block failed?"); 174 | return false; 175 | } 176 | } 177 | 178 | if do_update_tips { 179 | 180 | // update tips 181 | update_tips(name_of_new_block, node); 182 | 183 | // keep this tips in the block as the snapshot tips 184 | { 185 | let block = Arc::clone(&node.dag.get(name_of_new_block).unwrap()); 186 | let block_w = &mut block.write().unwrap(); 187 | block_w.tips_snapshot = node.tips.clone(); 188 | } 189 | 190 | // calculate blue 191 | calc_blue(name_of_new_block, node, k); 192 | } 193 | 194 | return true; 195 | } 196 | 197 | pub fn update_tips(name_of_new_block: &str, node: &mut Node){ 198 | 199 | //println!("update_tips(): new block={}", name_of_new_block); 200 | 201 | let dag = &node.dag; 202 | 203 | let block = dag.get(name_of_new_block); 204 | if block.is_none() { 205 | return; 206 | } 207 | 208 | let new_block = Arc::clone(block.unwrap()); 209 | let new_block = new_block.read().unwrap(); 210 | 211 | let mut to_be_removed: Vec = Vec::new(); 212 | 213 | for (prev, _value) in &new_block.prev { 214 | for (tip, _) in &node.tips { 215 | if prev==tip { 216 | to_be_removed.push(tip.to_string()); 217 | } 218 | } 219 | } 220 | 221 | let tips = &mut node.tips; 222 | 223 | if to_be_removed.len()>0 { 224 | for item in &to_be_removed { 225 | tips.remove(item); 226 | } 227 | } 228 | 229 | tips.insert(new_block.name.clone(), Arc::clone(block.unwrap())); 230 | 231 | //println!("update_tips(): new block={}, removed={:?}, new tips={}", name_of_new_block, to_be_removed, tips.len()); 232 | } 233 | -------------------------------------------------------------------------------- /blockdag/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The rust-dag Authors 2 | // This file is part of the rust-dag library. 3 | // 4 | // The rust-dag library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The rust-dag library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with the rust-dag library. If not, see . 16 | 17 | pub mod blockdag; 18 | 19 | 20 | #[macro_use] 21 | extern crate log; 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | 26 | extern crate env_logger; 27 | 28 | extern crate rand; 29 | extern crate time; 30 | 31 | use std::collections::HashMap; 32 | use std::sync::{Arc,RwLock}; 33 | use std::sync::atomic::{AtomicBool,AtomicIsize}; 34 | use std::sync::atomic::Ordering; 35 | use self::rand::Rng; 36 | use self::time::{PreciseTime}; 37 | use std::thread; 38 | use std::time::Duration; 39 | use std::sync::mpsc; 40 | 41 | use blockdag::{Node,BlockRaw}; 42 | use blockdag::{node_add_block,dag_print,dag_blue_print,dag_red_print,tips_anticone,sorted_keys_by_height,remove_past_future,update_tips,calc_blue,handle_block_rx,get_stpq}; 43 | 44 | #[test] 45 | fn test_fig3() { 46 | 47 | let k: i32 = 3; 48 | 49 | let _ = env_logger::try_init(); 50 | 51 | let node = Node::init("fig3"); 52 | 53 | let mut node_w = node.write().unwrap(); 54 | 55 | node_add_block("Genesis", &Vec::new(), &mut node_w, k, true); 56 | 57 | node_add_block("B", &vec!["Genesis"], &mut node_w, k, true); 58 | node_add_block("C", &vec!["Genesis"], &mut node_w, k, true); 59 | node_add_block("D", &vec!["Genesis"], &mut node_w, k, true); 60 | node_add_block("E", &vec!["Genesis"], &mut node_w, k, true); 61 | 62 | node_add_block("F", &vec!["B","C"], &mut node_w, k, true); 63 | node_add_block("H", &vec!["C","D","E"], &mut node_w, k, true); 64 | node_add_block("I", &vec!["E"], &mut node_w, k, true); 65 | 66 | node_add_block("J", &vec!["F","H"], &mut node_w, k, true); 67 | node_add_block("K", &vec!["B","H","I"], &mut node_w, k, true); 68 | node_add_block("L", &vec!["D","I"], &mut node_w, k, true); 69 | node_add_block("N", &vec!["L","K"], &mut node_w, k, true); 70 | node_add_block("M", &vec!["F","K"], &mut node_w, k, true); 71 | 72 | println!("{}", &node_w); 73 | 74 | dag_print(&node_w.dag); 75 | 76 | let blue_selection = dag_blue_print(&node_w.dag); 77 | println!("k={}, {}", k, &blue_selection); 78 | 79 | assert_eq!(&blue_selection, "blues={Genesis,B,C,D,F,H,J,K,M,N,} total=10/13"); 80 | 81 | let red_blocks = dag_red_print(&node_w.dag); 82 | println!("k={}, {}", k, &red_blocks); 83 | } 84 | 85 | #[test] 86 | fn test_fig4() { 87 | 88 | let k: i32 = 3; 89 | 90 | let _ = env_logger::try_init(); 91 | 92 | let node = Node::init("fig4"); 93 | 94 | let mut node_w = node.write().unwrap(); 95 | 96 | macro_rules! dag_add { 97 | ( block=$a:expr, references=$b:expr ) => (node_add_block($a, $b, &mut node_w, k, true)); 98 | } 99 | dag_add!(block="Genesis", references=&Vec::new()); 100 | 101 | dag_add!(block="B", references=&vec!["Genesis"]); 102 | dag_add!(block="C", references=&vec!["Genesis"]); 103 | dag_add!(block="D", references=&vec!["Genesis"]); 104 | dag_add!(block="E", references=&vec!["Genesis"]); 105 | 106 | dag_add!(block="F", references=&vec!["B","C"]); 107 | dag_add!(block="H", references=&vec!["E"]); 108 | dag_add!(block="I", references=&vec!["C","D"]); 109 | 110 | dag_add!(block="J", references=&vec!["F","D"]); 111 | dag_add!(block="K", references=&vec!["J","I","E"]); 112 | dag_add!(block="L", references=&vec!["F"]); 113 | dag_add!(block="N", references=&vec!["D","H"]); 114 | 115 | dag_add!(block="M", references=&vec!["L","K"]); 116 | dag_add!(block="O", references=&vec!["K"]); 117 | dag_add!(block="P", references=&vec!["K"]); 118 | dag_add!(block="Q", references=&vec!["N"]); 119 | 120 | dag_add!(block="R", references=&vec!["O","P","N"]); 121 | 122 | dag_add!(block="S", references=&vec!["Q"]); 123 | dag_add!(block="T", references=&vec!["S"]); 124 | dag_add!(block="U", references=&vec!["T"]); 125 | 126 | println!("{}", &node_w); 127 | 128 | dag_print(&node_w.dag); 129 | 130 | let blue_selection = dag_blue_print(&node_w.dag); 131 | println!("k={}, {}", k, &blue_selection); 132 | 133 | assert_eq!(&blue_selection, "blues={Genesis,B,C,D,F,I,J,K,M,O,P,R,} total=12/20"); 134 | 135 | let red_blocks = dag_red_print(&node_w.dag); 136 | println!("k={}, {}", k, &red_blocks); 137 | } 138 | 139 | #[test] 140 | fn test_anticone() { 141 | 142 | let k: i32 = 3; 143 | 144 | let node = Node::init("block add test"); 145 | 146 | let mut node_w = node.write().unwrap(); 147 | 148 | node_add_block("Genesis", &Vec::new(), &mut node_w, k, true); 149 | 150 | node_add_block("B", &vec!["Genesis"], &mut node_w, k, true); 151 | node_add_block("C", &vec!["Genesis"], &mut node_w, k, true); 152 | node_add_block("D", &vec!["Genesis"], &mut node_w, k, true); 153 | node_add_block("E", &vec!["Genesis"], &mut node_w, k, true); 154 | 155 | node_add_block("F", &vec!["B","C"], &mut node_w, k, true); 156 | node_add_block("H", &vec!["C","D","E"], &mut node_w, k, true); 157 | node_add_block("I", &vec!["E"], &mut node_w, k, true); 158 | 159 | let anticone = tips_anticone("H", &node_w.tips); 160 | let result = format!("anticone of {} = {:?}", "H", sorted_keys_by_height(&anticone, false)); 161 | println!("{}",result); 162 | assert_eq!(result, "anticone of H = [(\"B\", 1), (\"F\", 2), (\"I\", 2)]"); 163 | 164 | node_add_block("J", &vec!["F","H"], &mut node_w, k, true); 165 | node_add_block("K", &vec!["B","H","I"], &mut node_w, k, true); 166 | node_add_block("L", &vec!["D","I"], &mut node_w, k, true); 167 | node_add_block("M", &vec!["F","K"], &mut node_w, k, true); 168 | 169 | let anticone = tips_anticone("M", &node_w.tips); 170 | let result = format!("anticone of {} = {:?}", "M", sorted_keys_by_height(&anticone, false)); 171 | println!("{}",result); 172 | assert_eq!(result, "anticone of M = [(\"J\", 3), (\"L\", 3)]"); 173 | } 174 | 175 | 176 | #[test] 177 | fn test_add_block() { 178 | 179 | let blocks_generating:i32 = 1000_000; 180 | 181 | let max_classmate_blocks = 3; 182 | let max_prev_blocks = 5; 183 | 184 | let k: i32 = max_classmate_blocks; 185 | 186 | println!("One million blocks could take 1 or 2 minutes (depend on computer), please be patient... Block to be generated: {}", max_classmate_blocks); 187 | 188 | let start = PreciseTime::now(); 189 | 190 | let node = Node::init("block add test"); 191 | 192 | let mut node_w = node.write().unwrap(); 193 | 194 | node_add_block("Genesis", &Vec::new(), &mut node_w, k, true); 195 | 196 | let mut blocks_generated = 0; 197 | 198 | let mut _height:i32 = 1; 199 | while blocks_generated < blocks_generating { 200 | _height += 1; 201 | let classmate_blocks = rand::thread_rng().gen_range(1, max_classmate_blocks+1); 202 | // let back_steps = rand::thread_rng().gen_range(1, max_back_steps+1); 203 | //println!("height={} classmate_blocks={}", height, classmate_blocks); 204 | 205 | for _classmate in 1..classmate_blocks+1 { 206 | 207 | let prev_blocks = rand::thread_rng().gen_range(1, max_prev_blocks+1); 208 | //println!("height={} classmate={} prev_blocks={}", height, classmate, prev_blocks); 209 | 210 | let mut references = Vec::new(); 211 | 212 | // get one block from tips as 1st prev 213 | let mut tip_name_selected = String::new(); 214 | for (key, _) in node_w.tips.iter() { 215 | references.push(key.clone()); 216 | tip_name_selected.push_str(key); 217 | break; // just take one tip only. 218 | } 219 | 220 | // randomly select one from the anticone of that tip 221 | let mut anticone = tips_anticone(&tip_name_selected, &node_w.tips); 222 | 223 | while references.len() < prev_blocks && anticone.len()>0 { 224 | 225 | let mut anticone_clone = anticone.clone(); 226 | 227 | for (key, value) in anticone.iter() { 228 | if references.len() >= prev_blocks { 229 | break; 230 | } 231 | 232 | let block = Arc::clone(value); 233 | let block = block.read().unwrap(); 234 | 235 | references.push(key.clone()); 236 | 237 | // update anticone to remove all the past of this new referenced block. 238 | remove_past_future(&block, &mut anticone_clone); 239 | break; 240 | } 241 | 242 | anticone = anticone_clone; 243 | //println!("height={} classmate={} classmate_blocks={} prev_blocks={} references={:?} anticone size={}", height, classmate, classmate_blocks, prev_blocks, references, anticone.len()); 244 | } 245 | 246 | //println!("height={} classmate={} classmate_blocks={} prev_blocks={} references={:?}", height, classmate, classmate_blocks, prev_blocks, references); 247 | 248 | blocks_generated += 1; 249 | 250 | let mut references_str:Vec<&str> = Vec::new(); 251 | for reference in &references { 252 | references_str.push(reference); 253 | } 254 | 255 | let block_name = format!("{:06}", blocks_generated); 256 | node_add_block(&block_name, &references_str,&mut node_w, k, false); 257 | 258 | //println!("{}", &node_w); 259 | 260 | //dag_print(&node_w.dag); 261 | } 262 | 263 | // update tips once when a batch of blocks generated. 264 | let mut classmate_name = blocks_generated; 265 | for _classmate in 1..classmate_blocks+1 { 266 | let block_name = format!("{:06}", classmate_name); 267 | update_tips(&block_name, &mut node_w); 268 | calc_blue(&block_name, &mut node_w, k); 269 | classmate_name -= 1; 270 | } 271 | } 272 | 273 | let end = PreciseTime::now(); 274 | let d = start.to(end); 275 | let total_time_used = d.num_milliseconds() as f64; 276 | 277 | dag_print(&node_w.dag); 278 | 279 | println!("node=\"{}\",height={},size_of_dag={}", node_w.name, node_w.height, node_w.size_of_dag); 280 | println!("total time used: {} (ms)", total_time_used); 281 | 282 | let blue_selection = dag_blue_print(&node_w.dag); 283 | println!("k={}, {}", k, &blue_selection); 284 | 285 | assert_eq!(2 + 2, 4); 286 | } 287 | 288 | #[test] 289 | fn test_fig_x1() { 290 | 291 | let k: i32 = 3; 292 | 293 | let _ = env_logger::try_init(); 294 | 295 | let node = Node::init("figX1"); 296 | 297 | let mut node_w = node.write().unwrap(); 298 | 299 | node_add_block("Genesis", &Vec::new(), &mut node_w, k, true); 300 | 301 | node_add_block("B", &vec!["Genesis"], &mut node_w, k, true); 302 | node_add_block("C", &vec!["Genesis"], &mut node_w, k, true); 303 | node_add_block("D", &vec!["Genesis"], &mut node_w, k, true); 304 | node_add_block("E", &vec!["Genesis"], &mut node_w, k, true); 305 | 306 | node_add_block("01", &vec!["B","C","D","E"], &mut node_w, k, true); 307 | node_add_block("02", &vec!["B","E"], &mut node_w, k, true); 308 | node_add_block("03", &vec!["B","C","D","E"], &mut node_w, k, true); 309 | node_add_block("04", &vec!["E"], &mut node_w, k, true); 310 | 311 | node_add_block("05", &vec!["01","04"], &mut node_w, k, true); 312 | node_add_block("06", &vec!["01","03","04"], &mut node_w, k, true); 313 | node_add_block("07", &vec!["01","02"], &mut node_w, k, true); 314 | 315 | node_add_block("08", &vec!["02","03","05"], &mut node_w, k, true); 316 | node_add_block("09", &vec!["05","06","07"], &mut node_w, k, true); 317 | 318 | node_add_block("10", &vec!["08","09"], &mut node_w, k, true); 319 | node_add_block("11", &vec!["08","09"], &mut node_w, k, true); 320 | 321 | node_add_block("12", &vec!["11"], &mut node_w, k, true); 322 | node_add_block("13", &vec!["10","11"], &mut node_w, k, true); 323 | 324 | node_add_block("14", &vec!["13"], &mut node_w, k, true); 325 | node_add_block("15", &vec!["12","13"], &mut node_w, k, true); 326 | 327 | node_add_block("16", &vec!["12","14"], &mut node_w, k, true); 328 | node_add_block("17", &vec!["15","16"], &mut node_w, k, true); 329 | node_add_block("18", &vec!["16"], &mut node_w, k, true); 330 | 331 | node_add_block("19", &vec!["17","18"], &mut node_w, k, true); 332 | node_add_block("20", &vec!["17","18"], &mut node_w, k, true); 333 | node_add_block("21", &vec!["17"], &mut node_w, k, true); 334 | node_add_block("22", &vec!["17","18"], &mut node_w, k, true); 335 | node_add_block("23", &vec!["17","18"], &mut node_w, k, true); 336 | 337 | node_add_block("24", &vec!["19","23"], &mut node_w, k, true); 338 | node_add_block("25", &vec!["23"], &mut node_w, k, true); 339 | node_add_block("26", &vec!["23"], &mut node_w, k, true); 340 | 341 | node_add_block("27", &vec!["20","22","24","26"], &mut node_w, k, true); 342 | node_add_block("28", &vec!["21","22","24"], &mut node_w, k, true); 343 | node_add_block("29", &vec!["22","24","25","26"], &mut node_w, k, true); 344 | node_add_block("30", &vec!["21","24","25","26"], &mut node_w, k, true); 345 | node_add_block("31", &vec!["24"], &mut node_w, k, true); 346 | 347 | node_add_block("32", &vec!["22","25","31"], &mut node_w, k, true); 348 | node_add_block("33", &vec!["26","31"], &mut node_w, k, true); 349 | node_add_block("34", &vec!["22","31"], &mut node_w, k, true); 350 | 351 | node_add_block("35", &vec!["20","26","28","34"], &mut node_w, k, true); 352 | node_add_block("36", &vec!["20","28","30","33","34"], &mut node_w, k, true); 353 | node_add_block("37", &vec!["32"], &mut node_w, k, true); 354 | node_add_block("38", &vec!["20","32","33"], &mut node_w, k, true); 355 | node_add_block("39", &vec!["32"], &mut node_w, k, true); 356 | 357 | node_add_block("40", &vec!["21","33","37","39"], &mut node_w, k, true); 358 | node_add_block("41", &vec!["21","26","34","37"], &mut node_w, k, true); 359 | 360 | node_add_block("42", &vec!["27","29","36","39","41"], &mut node_w, k, true); 361 | node_add_block("43", &vec!["28","29","33","41"], &mut node_w, k, true); 362 | node_add_block("44", &vec!["29","32"], &mut node_w, k, true); 363 | node_add_block("45", &vec!["27","29","36","38","40"], &mut node_w, k, true); 364 | 365 | println!("{}", &node_w); 366 | 367 | dag_print(&node_w.dag); 368 | 369 | let blue_selection = dag_blue_print(&node_w.dag); 370 | println!("k={}, {}", k, &blue_selection); 371 | 372 | if k==0 { 373 | assert_eq!(&blue_selection, "blues={Genesis,B,01,05,09,11,13,14,16,18,23,26,30,36,45,} total=15/50") 374 | }else{ 375 | assert_eq!(2 + 2, 4); 376 | } 377 | 378 | let red_blocks = dag_red_print(&node_w.dag); 379 | println!("k={}, {}", k, &red_blocks); 380 | } 381 | 382 | 383 | #[test] 384 | fn test_fig_x2() { 385 | 386 | let k: i32 = 0; 387 | 388 | let _ = env_logger::try_init(); 389 | 390 | let node = Node::init("figX2"); 391 | 392 | let mut node_w = node.write().unwrap(); 393 | 394 | node_add_block("Genesis", &Vec::new(), &mut node_w, k, true); 395 | 396 | node_add_block("01", &vec!["Genesis"], &mut node_w, k, true); 397 | node_add_block("02", &vec!["Genesis"], &mut node_w, k, true); 398 | node_add_block("03", &vec!["Genesis"], &mut node_w, k, true); 399 | node_add_block("04", &vec!["Genesis"], &mut node_w, k, true); 400 | node_add_block("05", &vec!["Genesis"], &mut node_w, k, true); 401 | 402 | node_add_block("06", &vec!["01","02","03","04","05"], &mut node_w, k, true); 403 | node_add_block("07", &vec!["01","02","03","04","05"], &mut node_w, k, true); 404 | node_add_block("08", &vec!["01","02","03","04","05"], &mut node_w, k, true); 405 | node_add_block("09", &vec!["01","02","03","04","05"], &mut node_w, k, true); 406 | node_add_block("10", &vec!["01","02","03","04","05"], &mut node_w, k, true); 407 | 408 | node_add_block("11", &vec!["06","07","08","09","10"], &mut node_w, k, true); 409 | node_add_block("12", &vec!["06","07","08","09","10"], &mut node_w, k, true); 410 | node_add_block("13", &vec!["06","07","08","09","10"], &mut node_w, k, true); 411 | node_add_block("14", &vec!["06","07","08","09","10"], &mut node_w, k, true); 412 | node_add_block("15", &vec!["06","07","08","09","10"], &mut node_w, k, true); 413 | 414 | node_add_block("16", &vec!["11","12","13","14","15"], &mut node_w, k, true); 415 | node_add_block("17", &vec!["11","12","13","14","15"], &mut node_w, k, true); 416 | node_add_block("18", &vec!["11","12","13","14","15"], &mut node_w, k, true); 417 | node_add_block("19", &vec!["11","12","13","14","15"], &mut node_w, k, true); 418 | node_add_block("20", &vec!["11","12","13","14","15"], &mut node_w, k, true); 419 | 420 | node_add_block("21", &vec!["16","17","18","19","20"], &mut node_w, k, true); 421 | node_add_block("22", &vec!["16","17","18","19","20"], &mut node_w, k, true); 422 | node_add_block("23", &vec!["16","17","18","19","20"], &mut node_w, k, true); 423 | node_add_block("24", &vec!["16","17","18","19","20"], &mut node_w, k, true); 424 | node_add_block("25", &vec!["16","17","18","19","20"], &mut node_w, k, true); 425 | 426 | node_add_block("26", &vec!["21","22","23","24","25"], &mut node_w, k, true); 427 | node_add_block("27", &vec!["21","22","23","24","25"], &mut node_w, k, true); 428 | node_add_block("28", &vec!["21","22","23","24","25"], &mut node_w, k, true); 429 | node_add_block("29", &vec!["21","22","23","24","25"], &mut node_w, k, true); 430 | node_add_block("30", &vec!["21","22","23","24","25"], &mut node_w, k, true); 431 | 432 | node_add_block("31", &vec!["26","27","28","29","30"], &mut node_w, k, true); 433 | node_add_block("32", &vec!["26","27","28","29","30"], &mut node_w, k, true); 434 | node_add_block("33", &vec!["26","27","28","29","30"], &mut node_w, k, true); 435 | node_add_block("34", &vec!["26","27","28","29","30"], &mut node_w, k, true); 436 | node_add_block("35", &vec!["26","27","28","29","30"], &mut node_w, k, true); 437 | 438 | node_add_block("36", &vec!["31","32","33","34","35"], &mut node_w, k, true); 439 | node_add_block("37", &vec!["31","32","33","34","35"], &mut node_w, k, true); 440 | node_add_block("38", &vec!["31","32","33","34","35"], &mut node_w, k, true); 441 | node_add_block("39", &vec!["31","32","33","34","35"], &mut node_w, k, true); 442 | node_add_block("40", &vec!["31","32","33","34","35"], &mut node_w, k, true); 443 | 444 | node_add_block("41", &vec!["36","37","38","39","40"], &mut node_w, k, true); 445 | node_add_block("42", &vec!["36","37","38","39","40"], &mut node_w, k, true); 446 | node_add_block("43", &vec!["36","37","38","39","40"], &mut node_w, k, true); 447 | node_add_block("44", &vec!["36","37","38","39","40"], &mut node_w, k, true); 448 | node_add_block("45", &vec!["36","37","38","39","40"], &mut node_w, k, true); 449 | 450 | println!("{}", &node_w); 451 | 452 | dag_print(&node_w.dag); 453 | 454 | let blue_selection = dag_blue_print(&node_w.dag); 455 | println!("k={}, {}", k, &blue_selection); 456 | 457 | assert_eq!(2 + 2, 4); 458 | 459 | let red_blocks = dag_red_print(&node_w.dag); 460 | println!("k={}, {}", k, &red_blocks); 461 | } 462 | 463 | 464 | #[test] 465 | fn test_fig_x3() { 466 | 467 | let k: i32 = 3; 468 | 469 | let _ = env_logger::try_init(); 470 | 471 | let node = Node::init("figX3"); 472 | 473 | let mut node_w = node.write().unwrap(); 474 | 475 | macro_rules! dag_add { 476 | ( block=$a:expr, references=$b:expr ) => (node_add_block($a, $b, &mut node_w, k, true)); 477 | } 478 | dag_add!(block="Genesis", references=&Vec::new()); 479 | 480 | /* 481 | * auto generated by the following bash script: 482 | * $ sed 's/{name=0\(.*\),block=name=.*,height=.*,size_of_past_set=.*,size_of_past_blue=.*,blue=.,prev=\(.*\)}/dag_add!(block="0\1", references=\&vec!\2);/' input.log 483 | */ 484 | dag_add!(block="0001", references=&vec!["Genesis"]); 485 | dag_add!(block="0004", references=&vec!["Genesis"]); 486 | dag_add!(block="0010", references=&vec!["Genesis"]); 487 | dag_add!(block="0002", references=&vec!["0001"]); 488 | dag_add!(block="0005", references=&vec!["0004"]); 489 | dag_add!(block="0011", references=&vec!["0010"]); 490 | dag_add!(block="0003", references=&vec!["0002"]); 491 | dag_add!(block="0006", references=&vec!["0005"]); 492 | dag_add!(block="0012", references=&vec!["0011"]); 493 | dag_add!(block="0007", references=&vec!["0003", "0006"]); 494 | dag_add!(block="0016", references=&vec!["0003", "0006"]); 495 | dag_add!(block="0008", references=&vec!["0007"]); 496 | dag_add!(block="0017", references=&vec!["0016"]); 497 | dag_add!(block="0009", references=&vec!["0008"]); 498 | dag_add!(block="0018", references=&vec!["0017"]); 499 | dag_add!(block="0013", references=&vec!["0012", "0009"]); 500 | dag_add!(block="0019", references=&vec!["0012", "0009"]); 501 | dag_add!(block="0025", references=&vec!["0012", "0009"]); 502 | dag_add!(block="0014", references=&vec!["0013"]); 503 | dag_add!(block="0020", references=&vec!["0019"]); 504 | dag_add!(block="0026", references=&vec!["0025"]); 505 | dag_add!(block="0015", references=&vec!["0014"]); 506 | dag_add!(block="0021", references=&vec!["0020"]); 507 | dag_add!(block="0027", references=&vec!["0026"]); 508 | dag_add!(block="0022", references=&vec!["0018", "0015"]); 509 | dag_add!(block="0031", references=&vec!["0018", "0015", "0021"]); 510 | dag_add!(block="0023", references=&vec!["0022"]); 511 | dag_add!(block="0032", references=&vec!["0031"]); 512 | dag_add!(block="0024", references=&vec!["0023"]); 513 | dag_add!(block="0033", references=&vec!["0032"]); 514 | dag_add!(block="0028", references=&vec!["0021", "0027", "0024"]); 515 | dag_add!(block="0029", references=&vec!["0028"]); 516 | dag_add!(block="0030", references=&vec!["0029"]); 517 | dag_add!(block="0034", references=&vec!["0030"]); 518 | dag_add!(block="0037", references=&vec!["0033", "0030"]); 519 | dag_add!(block="0035", references=&vec!["0034"]); 520 | dag_add!(block="0038", references=&vec!["0037"]); 521 | dag_add!(block="0036", references=&vec!["0035"]); 522 | dag_add!(block="0039", references=&vec!["0038"]); 523 | dag_add!(block="0040", references=&vec!["0033", "0036"]); 524 | dag_add!(block="0043", references=&vec!["0036", "0039"]); 525 | dag_add!(block="0046", references=&vec!["0033", "0036"]); 526 | dag_add!(block="0053", references=&vec!["0036", "0039"]); 527 | dag_add!(block="0041", references=&vec!["0040"]); 528 | dag_add!(block="0044", references=&vec!["0043"]); 529 | dag_add!(block="0047", references=&vec!["0046"]); 530 | dag_add!(block="0042", references=&vec!["0041"]); 531 | dag_add!(block="0045", references=&vec!["0044"]); 532 | dag_add!(block="0048", references=&vec!["0047"]); 533 | dag_add!(block="0049", references=&vec!["0039", "0042"]); 534 | dag_add!(block="0055", references=&vec!["0039", "0042"]); 535 | dag_add!(block="0050", references=&vec!["0049"]); 536 | dag_add!(block="0056", references=&vec!["0055"]); 537 | dag_add!(block="0051", references=&vec!["0050"]); 538 | dag_add!(block="0057", references=&vec!["0056"]); 539 | dag_add!(block="0052", references=&vec!["0045", "0048", "0051"]); 540 | dag_add!(block="0061", references=&vec!["0045", "0048", "0051"]); 541 | dag_add!(block="0064", references=&vec!["0045", "0048", "0051"]); 542 | dag_add!(block="0054", references=&vec!["0052"]); 543 | dag_add!(block="0065", references=&vec!["0064"]); 544 | dag_add!(block="0058", references=&vec!["0053", "0057", "0054"]); 545 | dag_add!(block="0062", references=&vec!["0053", "0057", "0054"]); 546 | dag_add!(block="0066", references=&vec!["0065"]); 547 | dag_add!(block="0059", references=&vec!["0058"]); 548 | dag_add!(block="0063", references=&vec!["0062"]); 549 | dag_add!(block="0060", references=&vec!["0059"]); 550 | dag_add!(block="0067", references=&vec!["0061", "0066", "0063", "0060"]); 551 | dag_add!(block="0068", references=&vec!["0061", "0062", "0060"]); 552 | dag_add!(block="0070", references=&vec!["0060"]); 553 | dag_add!(block="0073", references=&vec!["0060"]); 554 | dag_add!(block="0076", references=&vec!["0061", "0066", "0063", "0060"]); 555 | dag_add!(block="0069", references=&vec!["0068"]); 556 | dag_add!(block="0071", references=&vec!["0070"]); 557 | dag_add!(block="0074", references=&vec!["0073"]); 558 | dag_add!(block="0077", references=&vec!["0076"]); 559 | dag_add!(block="0072", references=&vec!["0071"]); 560 | dag_add!(block="0075", references=&vec!["0074"]); 561 | dag_add!(block="0078", references=&vec!["0077"]); 562 | dag_add!(block="0079", references=&vec!["0067", "0069", "0072"]); 563 | dag_add!(block="0082", references=&vec!["0067", "0069", "0072", "0075"]); 564 | dag_add!(block="0086", references=&vec!["0067", "0069", "0072"]); 565 | dag_add!(block="0080", references=&vec!["0079"]); 566 | dag_add!(block="0083", references=&vec!["0082"]); 567 | dag_add!(block="0081", references=&vec!["0080"]); 568 | dag_add!(block="0084", references=&vec!["0083"]); 569 | dag_add!(block="0085", references=&vec!["0075", "0078", "0081"]); 570 | dag_add!(block="0088", references=&vec!["0075", "0078", "0081"]); 571 | dag_add!(block="0091", references=&vec!["0078", "0081", "0084"]); 572 | dag_add!(block="0087", references=&vec!["0085"]); 573 | dag_add!(block="0089", references=&vec!["0088"]); 574 | dag_add!(block="0093", references=&vec!["0091"]); 575 | dag_add!(block="0090", references=&vec!["0089"]); 576 | dag_add!(block="0092", references=&vec!["0086", "0084", "0087"]); 577 | dag_add!(block="0100", references=&vec!["0086", "0084", "0087"]); 578 | dag_add!(block="0094", references=&vec!["0093", "0090", "0092"]); 579 | dag_add!(block="0101", references=&vec!["0100"]); 580 | dag_add!(block="0095", references=&vec!["0094"]); 581 | dag_add!(block="0102", references=&vec!["0101"]); 582 | dag_add!(block="0096", references=&vec!["0095"]); 583 | dag_add!(block="0097", references=&vec!["0096"]); 584 | dag_add!(block="0098", references=&vec!["0097"]); 585 | dag_add!(block="0099", references=&vec!["0098"]); 586 | 587 | println!("{}", &node_w); 588 | 589 | dag_print(&node_w.dag); 590 | 591 | let blue_selection = dag_blue_print(&node_w.dag); 592 | println!("k={}, {}", k, &blue_selection); 593 | 594 | if k==0 { 595 | assert_eq!(&blue_selection, "blues={Genesis,0001,0002,0003,0007,0008,0009,0013,0014,0015,0031,0032,0033,0037,0038,0039,0043,0044,0045,0052,0054,0058,0059,0060,0076,0077,0078,0091,0093,0094,0095,0096,0097,0098,0099,} total=35/103"); 596 | }else { 597 | assert_eq!(2 + 2, 4); 598 | } 599 | 600 | let red_blocks = dag_red_print(&node_w.dag); 601 | println!("k={}, {}", k, &red_blocks); 602 | } 603 | 604 | #[test] 605 | fn test_nodes_sync() { 606 | 607 | let _ = env_logger::try_init(); 608 | 609 | const TOTAL_NODES: i32 = 100; // how many nodes to simulate. each node is a thread spawn. 610 | let blocks_generating:i32 = 1000; // how many blocks mining for this test. 611 | let blocks_one_time: i32 = 4; // how many blocks generating in one wait (loop). 612 | const K: i32 = 3; // how many blocks generating in parallel. 613 | 614 | println!("test_nodes_sync(): start. k={}, blocks={}, nodes={}", K, blocks_generating, TOTAL_NODES); 615 | 616 | // important note: the token-ring locker must be drop as soon as possible by node. 617 | let block_token_ring: Arc>>>> = Arc::new(RwLock::new(HashMap::new())); 618 | let mining_token_ring: Arc> = Arc::new(RwLock::new((0,0))); 619 | let blocks_generated = Arc::new(RwLock::new(0 as i32)); 620 | 621 | // block dispatcher 622 | let mut thread_mpsc = vec![]; 623 | 624 | let latest_block_hash = Arc::new(AtomicIsize::new(-1)); 625 | 626 | let mut handles = vec![]; 627 | 628 | let (dispatcher_tx, dispatcher_rx) = mpsc::channel(); 629 | 630 | // nodes threads 631 | let new_mining_start = Arc::new(AtomicBool::new(false)); 632 | 633 | for number in 0..TOTAL_NODES { 634 | 635 | let new_mining_start_clone = Arc::clone(&new_mining_start); 636 | 637 | let mining = Arc::clone(&mining_token_ring); 638 | let blocks_generated = Arc::clone(&blocks_generated); 639 | 640 | let (thread_sender, thread_receiver) = mpsc::channel(); 641 | thread_mpsc.push(thread_sender); 642 | 643 | let dispatcher_tx_clone = dispatcher_tx.clone(); 644 | let latest_block_hash_clone = latest_block_hash.clone(); 645 | 646 | let handle = thread::spawn(move || { 647 | 648 | let node = Node::init(&format!("node{}", number)); 649 | let mut node_w = node.write().unwrap(); 650 | node_add_block("Genesis", &Vec::new(), &mut node_w, K, true); 651 | drop(node_w); 652 | 653 | // block rx thread 654 | let node_for_rx = Arc::clone(&node); 655 | let _rx_handle = thread::spawn(move || { 656 | 657 | let mut node_stash: HashMap = HashMap::new(); 658 | let node_w2 = node_for_rx.read().unwrap(); 659 | let _node_name = node_w2.name.clone(); 660 | drop(node_w2); 661 | 662 | loop { 663 | let the_receive = thread_receiver.recv(); 664 | if the_receive.is_err() {break;} 665 | let new_block = the_receive.unwrap(); 666 | 667 | let mut node_w2 = node_for_rx.write().unwrap(); 668 | 669 | // processing block propagation 670 | handle_block_rx(new_block, &mut node_w2, &mut node_stash, K); 671 | debug!("{}. size_of_stash={}", &node_w2, node_stash.len()); 672 | drop(node_w2); 673 | 674 | // let random_sleep = rand::thread_rng().gen_range(1, 50); 675 | // thread::sleep(Duration::from_millis(random_sleep)); 676 | // thread::sleep(Duration::from_millis(random_sleep)); 677 | } 678 | 679 | //info!("{} rx thread exited", _node_name); 680 | 681 | }); 682 | 683 | // block mining and tx thread 684 | loop { 685 | if new_mining_start_clone.load(Ordering::Relaxed) == false { 686 | thread::sleep(Duration::from_millis(10)); 687 | continue; 688 | } 689 | 690 | let mut mining_lock = mining.write().unwrap(); 691 | if (*mining_lock).0 <= -1 { 692 | 693 | // log and exit thread. 694 | 695 | let node_w = node.read().unwrap(); 696 | //info!("{} tx thread exited. height={},size_of_dag={},mining_lock={:?}. mined_blocks={}", 697 | // node_w.name, node_w.height, node_w.size_of_dag, *mining_lock, node_w.mined_blocks); 698 | drop(mining_lock); 699 | 700 | if node_w.name == "node0" { 701 | dag_print(&node_w.dag); 702 | let blue_selection = dag_blue_print(&node_w.dag); 703 | info!("k={}, {}", K, &blue_selection); 704 | } 705 | 706 | break; 707 | 708 | }else if (*mining_lock).0 == 0 { 709 | drop(mining_lock); 710 | continue; 711 | } 712 | 713 | let node_w = node.read().unwrap(); 714 | if node_w.height+1 < (*mining_lock).1 as u64 { 715 | //info!("{} mining skip because low height: {}, need: {}", node_w.name, node_w.height, (*mining_lock).1); 716 | drop(mining_lock); 717 | drop(node_w); 718 | continue; 719 | } 720 | 721 | (*mining_lock).0 -= 1; 722 | if (*mining_lock).0 == 0 { 723 | new_mining_start_clone.store(false, Ordering::Relaxed); 724 | } 725 | 726 | drop(mining_lock); 727 | drop(node_w); 728 | 729 | let mut node_w = node.write().unwrap(); 730 | debug!("{} start mining on height: {}", node_w.name, node_w.height+1); 731 | 732 | let mut blocks_generated_w = blocks_generated.write().unwrap(); 733 | *blocks_generated_w += 1; 734 | let block_name = format!("{:04}", blocks_generated_w); 735 | drop(blocks_generated_w); 736 | 737 | let mut score_stpq = get_stpq(&node_w.tips); 738 | score_stpq.truncate((K+1) as usize); 739 | let references_str = score_stpq.iter().map(|&(ref s,_,_)| s.as_ref()).collect(); 740 | node_add_block(&block_name, &references_str, &mut node_w, K, true); 741 | 742 | // propagate this new mined block 743 | { 744 | let new_mined_block = &node_w.dag.get(&block_name).unwrap().read().unwrap(); 745 | let prev_names = new_mined_block.prev.iter().map(|(k,_)|{k.clone()}).collect::>(); 746 | 747 | let new_block_raw = BlockRaw{ 748 | name:block_name.clone().to_string(), 749 | height: new_mined_block.height, 750 | size_of_past_set: new_mined_block.size_of_past_set, 751 | prev: prev_names, 752 | }; 753 | 754 | dispatcher_tx_clone.send(new_block_raw).unwrap(); 755 | } 756 | 757 | latest_block_hash_clone.store(block_name.parse::().unwrap(), Ordering::Relaxed); 758 | info!("{} new mined block: {}. height={},size_of_dag={}. mined_blocks={}", node_w.name, block_name, node_w.height, node_w.size_of_dag, node_w.mined_blocks); 759 | 760 | node_w.mined_blocks += 1; 761 | 762 | drop(node_w); 763 | 764 | // if node_w.name == "node0" { 765 | // dag_print(&node_w.dag); 766 | // } 767 | } 768 | 769 | //info!("node {} tx thread exited", number); 770 | 771 | }); 772 | 773 | handles.push(handle); 774 | } 775 | 776 | 777 | // wait a while for nodes thread start-up. 778 | thread::sleep(Duration::from_millis(100)); 779 | 780 | let start = PreciseTime::now(); 781 | 782 | // block dispatcher thread 783 | let _dispatcher_handle = thread::spawn(move || { 784 | 785 | let mut to_be_dispatched: HashMap = HashMap::new(); 786 | let mut dispatched: HashMap> = HashMap::new(); 787 | 788 | let mut latest_block_hash_copy: isize; 789 | 'dis_outer: loop { 790 | let the_receive = dispatcher_rx.recv(); 791 | if the_receive.is_err() {break;} 792 | let new_block = the_receive.unwrap() as BlockRaw; 793 | 794 | info!("dispatcher recv block: {}. remaining queue size={}", new_block.name, to_be_dispatched.len()); 795 | 796 | let mut is_dispatched: HashMap = HashMap::new(); 797 | for i in 0..TOTAL_NODES{ is_dispatched.insert(i,false);} 798 | 799 | dispatched.insert(new_block.name.clone(), is_dispatched); 800 | to_be_dispatched.insert(new_block.name.clone(), new_block); 801 | 802 | latest_block_hash_copy = latest_block_hash.load(Ordering::Relaxed); 803 | 804 | // dispatching 805 | let mut finished_block_list: Vec = Vec::new(); 806 | let mut new_block_arriving = false; 807 | for (name,block) in &to_be_dispatched { 808 | 809 | let mut is_dispatched_clone; 810 | { 811 | let is_dispatched = dispatched.get(name).unwrap(); 812 | is_dispatched_clone = is_dispatched.clone(); 813 | for (i, _) in is_dispatched { 814 | let number: usize = *i as usize; 815 | thread_mpsc[number].send(block.clone()).unwrap(); // this is supposed to be a blocking slow call, to simulate block sending via network. 816 | is_dispatched_clone.remove(&i); 817 | if latest_block_hash.load(Ordering::Relaxed) != latest_block_hash_copy { 818 | new_block_arriving = true; 819 | break; 820 | } 821 | } 822 | } 823 | 824 | if is_dispatched_clone.len() == 0 { finished_block_list.push(name.clone()); } 825 | 826 | dispatched.insert(name.clone(), is_dispatched_clone); 827 | 828 | if new_block_arriving == true { break; } 829 | } 830 | 831 | for finished_block in &finished_block_list { 832 | to_be_dispatched.remove(finished_block); 833 | } 834 | } 835 | 836 | info!("dispatcher thread exited."); 837 | 838 | }); 839 | 840 | // main controller loop 841 | let mut acc = 0; 842 | let mut height = 0; 843 | loop { 844 | 845 | let mut mining = mining_token_ring.write().unwrap(); 846 | if (*mining).0 > 0 { 847 | // miner too slow? 848 | drop(mining); 849 | //println!("miner too slow?"); 850 | thread::sleep(Duration::from_millis(10)); 851 | continue; 852 | } 853 | 854 | height += 1; 855 | if acc + blocks_one_time <= blocks_generating { 856 | (*mining).0 += blocks_one_time; 857 | acc += blocks_one_time; 858 | }else{ 859 | (*mining).0 += blocks_generating-acc; 860 | acc += blocks_generating-acc; 861 | } 862 | (*mining).1 = height; 863 | debug!("test_nodes_sync(): start mining {} blocks at height {}. mining_lock={:?}", blocks_one_time, height, *mining); 864 | drop(mining); 865 | 866 | new_mining_start.store(true, Ordering::Relaxed); 867 | 868 | thread::sleep(Duration::from_millis(10)); 869 | 870 | { 871 | let blocks_generated_r = blocks_generated.read().unwrap(); 872 | if *blocks_generated_r >= blocks_generating { 873 | drop(blocks_generated_r); 874 | 875 | // wait a while for nodes complete propagation. 876 | println!("\npreparing to terminate. wait 1 second for nodes complete propagation....\n"); 877 | thread::sleep(Duration::from_millis(1000)); 878 | 879 | let mut mining = mining_token_ring.write().unwrap(); 880 | (*mining).0 = -1; // ask nodes stop and exit. 881 | drop(mining); 882 | 883 | new_mining_start.store(true, Ordering::Relaxed); 884 | 885 | break; 886 | } 887 | } 888 | } 889 | 890 | for handle in handles { 891 | handle.join().unwrap(); 892 | } 893 | 894 | let propagation = block_token_ring.read().unwrap(); 895 | println!("test_nodes_sync(): done. block propagation hashmap remaining size: {}", propagation.len()); 896 | 897 | let end = PreciseTime::now(); 898 | let d = start.to(end); 899 | let total_time_used = d.num_milliseconds() as f64; 900 | 901 | println!("total time used: {} (ms)", total_time_used-1000.0); 902 | 903 | assert_eq!(2 + 2, 4); 904 | } 905 | } 906 | -------------------------------------------------------------------------------- /godag/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /godag/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "godag" 3 | version = "0.1.0" 4 | authors = ["Gary YU "] 5 | 6 | [dependencies] 7 | blockdag = { path = "../blockdag" } 8 | log = "0.4.0" 9 | env_logger = "0.5.9" -------------------------------------------------------------------------------- /godag/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The rust-dag Authors 2 | // This file is part of the rust-dag library. 3 | // 4 | // The rust-dag library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The rust-dag library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with the rust-dag library. If not, see . 16 | 17 | #[macro_use] 18 | extern crate log; 19 | extern crate env_logger; 20 | 21 | fn main() { 22 | env_logger::init(); 23 | 24 | info!("starting up"); 25 | println!("Hello, world!"); 26 | } 27 | -------------------------------------------------------------------------------- /pics/Fig.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyyu/rust-dag/d1e427807a0cf5a8ad4163bcf7fffab1da1d15bb/pics/Fig.3.png -------------------------------------------------------------------------------- /pics/Fig.4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyyu/rust-dag/d1e427807a0cf5a8ad4163bcf7fffab1da1d15bb/pics/Fig.4.jpg -------------------------------------------------------------------------------- /pics/Fig.X1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garyyu/rust-dag/d1e427807a0cf5a8ad4163bcf7fffab1da1d15bb/pics/Fig.X1.png --------------------------------------------------------------------------------