Merge branch 'master' of github.com:ethcore/parity-bitcoin into session

This commit is contained in:
debris 2016-10-21 09:40:22 +02:00
commit 8bb2603d25
10 changed files with 568 additions and 500 deletions

71
Cargo.lock generated
View File

@ -32,7 +32,7 @@ version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"odds 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"odds 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -86,7 +86,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -108,7 +108,7 @@ dependencies = [
"chain 0.1.0",
"elastic-array 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.3.0",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)",
"serialization 0.1.0",
@ -143,8 +143,8 @@ version = "0.5.6"
source = "git+https://github.com/ethcore/rust-secp256k1#f998f9a8c18227af200f0f7fdadf8a6560d391ff"
dependencies = [
"arrayvec 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -176,7 +176,7 @@ dependencies = [
[[package]]
name = "gcc"
version = "0.3.35"
version = "0.3.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -224,7 +224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -242,7 +242,7 @@ name = "memchr"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -264,6 +264,7 @@ dependencies = [
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"serialization 0.1.0",
"test-data 0.1.0",
]
[[package]]
@ -273,7 +274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
@ -300,7 +301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -312,7 +313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -323,7 +324,7 @@ name = "nodrop"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"odds 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"odds 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -331,7 +332,7 @@ name = "num_cpus"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -339,12 +340,12 @@ name = "num_cpus"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "odds"
version = "0.2.22"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -361,7 +362,7 @@ dependencies = [
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"message 0.1.0",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
@ -370,7 +371,7 @@ dependencies = [
[[package]]
name = "parking_lot"
version = "0.3.5"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -383,7 +384,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -402,7 +403,7 @@ name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -435,19 +436,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rocksdb"
version = "0.4.5"
source = "git+https://github.com/ethcore/rust-rocksdb#ffc7c82380fe8569f85ae6743f7f620af2d4a679"
source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58"
dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
]
[[package]]
name = "rocksdb-sys"
version = "0.3.0"
source = "git+https://github.com/ethcore/rust-rocksdb#ffc7c82380fe8569f85ae6743f7f620af2d4a679"
source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58"
dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -455,8 +456,8 @@ name = "rust-crypto"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
@ -525,7 +526,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -534,6 +535,8 @@ name = "test-data"
version = "0.1.0"
dependencies = [
"chain 0.1.0",
"primitives 0.1.0",
"serialization 0.1.0",
]
[[package]]
@ -542,7 +545,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -559,7 +562,7 @@ version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -603,7 +606,7 @@ dependencies = [
"db 0.1.0",
"ethcore-devtools 1.3.0",
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"serialization 0.1.0",
"test-data 0.1.0",
@ -655,12 +658,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum eth-secp256k1 0.5.6 (git+https://github.com/ethcore/rust-secp256k1)" = "<none>"
"checksum futures 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd34f72c0fffc9d2f6c570fd392bf99b9c5cd1481d79809e1cc2320befc0af0"
"checksum futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bb982bb25cd8fa5da6a8eb3a460354c984ff1113da82bcb4f0b0862b5795db82"
"checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312"
"checksum gcc 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "41337e9dc80ebadf36b4f252bf7440f61bcf34f99caa170e50dcd0f9a0cdb5d8"
"checksum heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8c80e194758495a9109566134dc06e42ea0423987d6ceca016edaa90381b3549"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
"checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
@ -671,9 +674,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbadd3f4c98dea0bd3d9b4be4c0cdaf1ab57035cb2e41fce3983db5add7cc5"
"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
"checksum num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8890e6084723d57d0df8d2720b0d60c6ee67d6c93e7169630e4371e88765dcad"
"checksum odds 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "308eb922caa165a2c4be8004abf87822fc4b444ab339f70fc172236b1905efb0"
"checksum odds 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e04630a62b3f1cc8c58b4d8f2555a40136f02b420e158242936ef286a72d33a0"
"checksum owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d91377085359426407a287ab16884a0111ba473aa6844ff01d4ec20ce3d75e7"
"checksum parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc5847584161f273e69edc63c1a86254a22f570a0b5dd87aa6f9773f6f7d125"
"checksum parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e1435e7a2a00dfebededd6c6bdbd54008001e94b4a2aadd6aef0dc4c56317621"
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
"checksum rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "655df67c314c30fa3055a365eae276eb88aa4f3413a352a1ab32c1320eda41ea"

View File

@ -31,7 +31,7 @@ pub const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = (1 << 22);
pub const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000ffff;
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Default)]
pub struct OutPoint {
pub hash: H256,
pub index: u32,
@ -71,7 +71,7 @@ impl OutPoint {
}
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Default, Clone)]
pub struct TransactionInput {
pub previous_output: OutPoint,
pub script_sig: Bytes,
@ -182,7 +182,7 @@ impl TransactionOutput {
}
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Default, Clone)]
pub struct Transaction {
pub version: i32,
pub inputs: Vec<TransactionInput>,

View File

@ -8,3 +8,4 @@ heapsize = "0.3"
chain = { path = "../chain" }
primitives = { path = "../primitives" }
serialization = { path = "../serialization" }
test-data = { path = "../test-data" }

View File

@ -2,6 +2,7 @@ extern crate chain;
extern crate heapsize;
extern crate primitives;
extern crate serialization as ser;
extern crate test_data;
pub mod memory_pool;

View File

@ -685,46 +685,16 @@ impl HeapSizeOf for MemoryPool {
#[cfg(test)]
mod tests {
use std::cmp::Ordering;
use hash::H256;
use chain::Transaction;
use heapsize::HeapSizeOf;
use super::{MemoryPool, OrderingStrategy};
use test_data::{ChainBuilder, TransactionBuilder};
// output_value = 898126612, size = 225, miner_score ~ 3991673.83
const RAW_TRANSACTION1: &'static str = "01000000017e4e1bfa4cc16a46593390b9f627db9a3b7c3b1802daa826fc0c477c067ea4f1000000006a47304402203cca1b01b307d3dba3d4f819ef4e9ccf839fa7ef901fc39d2b1d6e33c159a0b0022009d135bd47b8465a69f4db7145af34e0f063e926d95d9c21fb4e8cbc2052838c0121039c01d413f0e296cb766b408c528d3526e75a0f63cfc44c1147160613a12e6cb7feffffff02c8f27535000000001976a914e54788b730b91eb9b29917fa10ddbc97996a987988ac4c601200000000001976a91421e8ed0ddc9a365c10fa3130c91c36237a45848888aca7a00600";
// output_value = 423675406, size = 225, miner_score ~ 1883001.80
const RAW_TRANSACTION2: &'static str = "0100000001efaf295b354d8063336a03652664e31b63666f6fbe51b377ad3bdd7b65678a43000000006a47304402206100084828cfc2b71881f1a99447658d5844043f69c1f9bd6c95cb0e11197d4002207c8e23b6233e7317fe0db3e12c8a4291efe671e02c4bbeeb3534e208bb9a3a75012103e091c9c970427a709646990ca16d4d418efc9e5c46ae794c3d09023a7e0e1c57feffffff0226662e19000000001976a914ffad82403bc2a1dd3789b7e653d352515ae86b7288ace85f1200000000001976a914c2f8a6513ebcf6f61edca10199442e33108d540988aca7a00600";
// output_value = 668388826, size = 225, miner_score ~ 2970617.00
const RAW_TRANSACTION3: &'static str = "01000000012eee0922c7385e6a11d4f92da65e16b205b2cdfe294c3140c3bc0427f6c11794000000006a47304402207aab34b1c9bb5464c3c1ddf9fee042d8755b81ed1e8c35b895ee2d7da17a23ac02205dfd9c8d14f44951c9e8c3a70f8820a6b113046db1ca25d52a31a4b68d62e07901210306a47c3c0ce5ad78616ad0695113ee4d7a848155fd9f4a1eb7aeed756e174211feffffff024c601200000000001976a914ae829d4d1a8945dc165a57f1149b4656e48c161988ac8e6dc427000000001976a9146c4f1f52adec5211f456acc12917fe902949b08088aca7a00600";
// output_value = 256505044, size = 226, miner_score ~ 1134978.07
const RAW_TRANSACTION4: &'static str = "01000000012969032b2a920c03fa71eeea5250d0f6259b130a15ed695f79d957e47b9b2d8b000000006b483045022100b34c8a714b295b84686211b37daaa65ef79cf0ce1dc7d7a4e133a5b08a308f6f02201abca9e08bddb56e205bd1c5e689419926031ec955d8c89671a16a7076dce0ec0121020db95d68c760d1e0a5090dbf0ed2cbfd1225c3bc46d4e31e272bcc14b42a9643feffffff021896370f000000001976a914552b2549642c22462dc0e82ea25500dea6bb5e2188acbc5e1200000000001976a914dca40d275f5eb00cefab813925a1b07b9b77159188aca7a00600";
const RAW_TRANSACTION1_HASH: &'static str = "af9d5d566b6c914fc0de758a5f18731f5570ac59d1f0c5d1516f0f2dda2c3f79";
const RAW_TRANSACTION2_HASH: &'static str = "e97719095d91821f691dcbebdf5fb82c4eff8dd33d0c3cc6690aae37ed82a01e";
const RAW_TRANSACTION3_HASH: &'static str = "2d3833b35efc8f2b9d1c2140505b207fd71155178ad604e03364448f7007fc04";
const RAW_TRANSACTION4_HASH: &'static str = "4a15e0b41b1a47381f2f2baa16087688d1cd9078416960deed1faae852a469ce";
fn construct_memory_pool() -> MemoryPool {
let transaction1: Transaction = RAW_TRANSACTION1.into();
let transaction2: Transaction = RAW_TRANSACTION2.into();
let transaction3: Transaction = RAW_TRANSACTION3.into();
let transaction4: Transaction = RAW_TRANSACTION4.into();
let transaction1_hash = RAW_TRANSACTION1_HASH.into();
let transaction4_hash = RAW_TRANSACTION4_HASH.into();
assert_eq!(transaction1.hash(), transaction1_hash);
assert_eq!(transaction2.hash(), RAW_TRANSACTION2_HASH.into());
assert_eq!(transaction3.hash(), RAW_TRANSACTION3_HASH.into());
assert_eq!(transaction4.hash(), transaction4_hash);
// hash of t4 must be lesser than hash of t4
assert_eq!(transaction4_hash.cmp(&transaction1_hash), Ordering::Less);
fn to_memory_pool(chain: &mut ChainBuilder) -> MemoryPool {
let mut pool = MemoryPool::new();
pool.insert_verified(RAW_TRANSACTION1.into());
pool.insert_verified(RAW_TRANSACTION2.into());
pool.insert_verified(RAW_TRANSACTION3.into());
pool.insert_verified(RAW_TRANSACTION4.into());
for transaction in chain.transactions.iter().cloned() {
pool.insert_verified(transaction);
}
pool
}
@ -734,11 +704,11 @@ mod tests {
let size1 = pool.heap_size_of_children();
pool.insert_verified(RAW_TRANSACTION1.into());
pool.insert_verified(Transaction::default());
let size2 = pool.heap_size_of_children();
assert!(size2 > size1);
pool.insert_verified(RAW_TRANSACTION2.into());
pool.insert_verified(Transaction::default());
let size3 = pool.heap_size_of_children();
assert!(size3 > size2);
}
@ -746,11 +716,11 @@ mod tests {
#[test]
fn test_memory_pool_insert_same_transaction() {
let mut pool = MemoryPool::new();
pool.insert_verified(RAW_TRANSACTION1.into());
pool.insert_verified(Transaction::default());
assert_eq!(pool.get_transactions_ids().len(), 1);
// insert the same transaction again
pool.insert_verified(RAW_TRANSACTION1.into());
pool.insert_verified(Transaction::default());
assert_eq!(pool.get_transactions_ids().len(), 1);
}
@ -760,13 +730,11 @@ mod tests {
assert_eq!(pool.read_with_strategy(OrderingStrategy::ByTimestamp), None);
assert_eq!(pool.read_n_with_strategy(100, OrderingStrategy::ByTimestamp), vec![]);
let t: Transaction = "00000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000011e000000000000000000000000".into();
let thash = t.hash();
pool.insert_verified(t);
assert_eq!(pool.read_with_strategy(OrderingStrategy::ByTimestamp), Some(thash.clone()));
assert_eq!(pool.read_n_with_strategy(100, OrderingStrategy::ByTimestamp), vec![thash.clone()]);
assert_eq!(pool.read_with_strategy(OrderingStrategy::ByTimestamp), Some(thash.clone()));
assert_eq!(pool.read_n_with_strategy(100, OrderingStrategy::ByTimestamp), vec![thash.clone()]);
pool.insert_verified(Transaction::default());
assert_eq!(pool.read_with_strategy(OrderingStrategy::ByTimestamp), Some(Transaction::default().hash()));
assert_eq!(pool.read_n_with_strategy(100, OrderingStrategy::ByTimestamp), vec![Transaction::default().hash()]);
assert_eq!(pool.read_with_strategy(OrderingStrategy::ByTimestamp), Some(Transaction::default().hash()));
assert_eq!(pool.read_n_with_strategy(100, OrderingStrategy::ByTimestamp), vec![Transaction::default().hash()]);
}
#[test]
@ -775,19 +743,15 @@ mod tests {
assert_eq!(pool.remove_with_strategy(OrderingStrategy::ByTimestamp), None);
assert_eq!(pool.remove_n_with_strategy(100, OrderingStrategy::ByTimestamp), vec![]);
let raw_transaction = "00000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000011e000000000000000000000000";
let transaction: Transaction = raw_transaction.into();
let hash = transaction.hash();
pool.insert_verified(transaction);
pool.insert_verified(Transaction::default());
let removed = pool.remove_with_strategy(OrderingStrategy::ByTimestamp);
assert!(removed.is_some());
assert_eq!(removed.unwrap().hash(), hash);
assert_eq!(removed.unwrap(), Transaction::default());
pool.insert_verified(raw_transaction.into());
pool.insert_verified(Transaction::default());
let removed = pool.remove_n_with_strategy(100, OrderingStrategy::ByTimestamp);
assert_eq!(removed.len(), 1);
assert_eq!(removed[0].hash(), hash);
assert_eq!(removed[0], Transaction::default());
assert_eq!(pool.remove_with_strategy(OrderingStrategy::ByTimestamp), None);
assert_eq!(pool.remove_n_with_strategy(100, OrderingStrategy::ByTimestamp), vec![]);
@ -795,350 +759,300 @@ mod tests {
#[test]
fn test_memory_pool_remove_by_hash() {
let mut pool = construct_memory_pool();
let mut pool = MemoryPool::new();
let pool_transactions = pool.get_transactions_ids();
assert_eq!(pool_transactions.len(), 4);
// check pool transactions
let ref hash_to_remove = pool_transactions[0];
assert!(*hash_to_remove == RAW_TRANSACTION1_HASH.into()
|| *hash_to_remove == RAW_TRANSACTION2_HASH.into()
|| *hash_to_remove == RAW_TRANSACTION3_HASH.into()
|| *hash_to_remove == RAW_TRANSACTION4_HASH.into());
assert_eq!(pool.get_transactions_ids().len(), 4);
pool.insert_verified(Transaction::default());
assert_eq!(pool.get_transactions_ids().len(), 1);
// remove and check remaining transactions
let removed = pool.remove_by_hash(&hash_to_remove);
let removed = pool.remove_by_hash(&Transaction::default().hash());
assert!(removed.is_some());
assert_eq!(removed.unwrap().hash(), *hash_to_remove);
assert_eq!(pool.get_transactions_ids().len(), 3);
assert_eq!(removed.unwrap(), Transaction::default());
assert_eq!(pool.get_transactions_ids().len(), 0);
// remove non-existant transaction
let nonexistant_hash: H256 = "0000000000000000000000000000000000000000000000000000000000000000".into();
assert_eq!(pool.remove_by_hash(&nonexistant_hash), None);
assert_eq!(pool.get_transactions_ids().len(), 3);
assert_eq!(pool.remove_by_hash(&TransactionBuilder::with_version(1).hash()), None);
assert_eq!(pool.get_transactions_ids().len(), 0);
}
#[test]
fn test_memory_pool_insert_parent_after_child() {
let parent_transaction: Transaction = "00000000000164000000000000000000000000".into();
let child_transaction: Transaction = "0000000001545ac9cffeaa3ee074f08a5306e703cb30883192ed9b10ee9ddb76824e4985070000000000000000000000000000".into();
let grandchild_transaction: Transaction = "0000000001cc1d8279403880bfdd7682c28ed8441a138f96ae1dc5fd90bc928b88d48107a90000000000000000000164000000000000000000000000".into();
let parent_transaction_hash = parent_transaction.hash();
let child_transaction_hash = child_transaction.hash();
let grandchild_transaction_hash = grandchild_transaction.hash();
let chain = &mut ChainBuilder::new();
TransactionBuilder::with_output(100).store(chain)
.to_input(0).add_output(100).store(chain)
.to_input(0).add_output(100).store(chain);
// insert child, then parent
let mut pool = MemoryPool::new();
pool.insert_verified(grandchild_transaction); // timestamp 0
pool.insert_verified(child_transaction); // timestamp 1
pool.insert_verified(parent_transaction); // timestamp 2
pool.insert_verified(chain.at(2)); // timestamp 0
pool.insert_verified(chain.at(1)); // timestamp 1
pool.insert_verified(chain.at(0)); // timestamp 2
// check that parent transaction was removed before child trnasaction
let transactions = pool.remove_n_with_strategy(3, OrderingStrategy::ByTimestamp);
assert_eq!(transactions.len(), 3);
assert_eq!(transactions[0].hash(), parent_transaction_hash);
assert_eq!(transactions[1].hash(), child_transaction_hash);
assert_eq!(transactions[2].hash(), grandchild_transaction_hash);
assert_eq!(transactions[0], chain.at(0));
assert_eq!(transactions[1], chain.at(1));
assert_eq!(transactions[2], chain.at(2));
}
#[test]
fn test_memory_pool_insert_parent_before_child() {
let parent_transaction: Transaction = "00000000000164000000000000000000000000".into();
let child_transaction: Transaction = "0000000001545ac9cffeaa3ee074f08a5306e703cb30883192ed9b10ee9ddb76824e4985070000000000000000000164000000000000000000000000".into();
let grandchild_transaction: Transaction = "0000000001cc1d8279403880bfdd7682c28ed8441a138f96ae1dc5fd90bc928b88d48107a90000000000000000000164000000000000000000000000".into();
let parent_transaction_hash = parent_transaction.hash();
let child_transaction_hash = child_transaction.hash();
let grandchild_transaction_hash = grandchild_transaction.hash();
let chain = &mut ChainBuilder::new();
TransactionBuilder::with_output(100).store(chain)
.to_input(0).add_output(100).store(chain)
.to_input(0).add_output(100).store(chain);
// insert child, then parent
let mut pool = MemoryPool::new();
pool.insert_verified(parent_transaction); // timestamp 0
pool.insert_verified(child_transaction); // timestamp 1
pool.insert_verified(grandchild_transaction); // timestamp 2
// insert parent, then child
let mut pool = to_memory_pool(chain);
// check that parent transaction was removed before child trnasaction
let transactions = pool.remove_n_with_strategy(3, OrderingStrategy::ByTimestamp);
assert_eq!(transactions.len(), 3);
assert_eq!(transactions[0].hash(), parent_transaction_hash);
assert_eq!(transactions[1].hash(), child_transaction_hash);
assert_eq!(transactions[2].hash(), grandchild_transaction_hash);
assert_eq!(transactions[0], chain.at(0));
assert_eq!(transactions[1], chain.at(1));
assert_eq!(transactions[2], chain.at(2));
}
#[test]
fn test_memory_pool_insert_child_after_remove_by_hash() {
let raw_parent_transaction = "00000000000164000000000000000000000000";
let raw_child_transaction = "0000000001545ac9cffeaa3ee074f08a5306e703cb30883192ed9b10ee9ddb76824e4985070000000000000000000164000000000000000000000000";
let raw_grandchild_transaction = "0000000001cc1d8279403880bfdd7682c28ed8441a138f96ae1dc5fd90bc928b88d48107a90000000000000000000164000000000000000000000000";
let parent_transaction: Transaction = raw_parent_transaction.into();
let child_transaction: Transaction = raw_child_transaction.into();
let grandchild_transaction: Transaction = raw_grandchild_transaction.into();
let parent_transaction_hash = parent_transaction.hash();
let child_transaction_hash = child_transaction.hash();
let grandchild_transaction_hash = grandchild_transaction.hash();
let chain = &mut ChainBuilder::new();
TransactionBuilder::with_output(100).store(chain)
.to_input(0).add_output(100).store(chain)
.to_input(0).add_output(100).store(chain);
// insert child, then parent
let mut pool = MemoryPool::new();
pool.insert_verified(parent_transaction);
pool.insert_verified(child_transaction);
pool.insert_verified(grandchild_transaction);
// insert parent, then child
let mut pool = to_memory_pool(chain);
// remove child transaction & make sure that other transactions are still there
pool.remove_by_hash(&child_transaction_hash);
pool.remove_by_hash(&chain.hash(1));
assert_eq!(pool.get_transactions_ids().len(), 2);
// insert child transaction back to the pool & assert transactions are removed in correct order
pool.insert_verified(raw_child_transaction.into());
pool.insert_verified(chain.at(1));
let transactions = pool.remove_n_with_strategy(3, OrderingStrategy::ByTransactionScore);
assert_eq!(transactions.len(), 3);
assert_eq!(transactions[0].hash(), parent_transaction_hash);
assert_eq!(transactions[1].hash(), child_transaction_hash);
assert_eq!(transactions[2].hash(), grandchild_transaction_hash);
assert_eq!(transactions[0], chain.at(0));
assert_eq!(transactions[1], chain.at(1));
assert_eq!(transactions[2], chain.at(2));
}
#[test]
fn test_memory_pool_get_information() {
let mut pool = construct_memory_pool();
let pool_sizes = [901, 676, 451, 226, 0];
let removals = [RAW_TRANSACTION1_HASH, RAW_TRANSACTION2_HASH, RAW_TRANSACTION3_HASH, RAW_TRANSACTION4_HASH];
// check pool information after removing each transaction
for i in 0..pool_sizes.len() {
let expected_pool_count = 5 - i - 1;
let expected_pool_size = pool_sizes[i];
let info = pool.information();
assert_eq!(info.transactions_count, expected_pool_count);
assert_eq!(info.transactions_size_in_bytes, expected_pool_size);
let chain = &mut ChainBuilder::new();
TransactionBuilder::with_output(10).store(chain)
.to_input(0).add_output(20).store(chain)
.to_input(0).add_output(30).store(chain)
.to_input(0).add_output(40).store(chain);
let mut pool = MemoryPool::new();
if expected_pool_size != 0 {
pool.remove_by_hash(&removals[i].into());
}
let mut transactions_size = 0;
for transaction_index in 0..4 {
pool.insert_verified(chain.at(transaction_index));
transactions_size += chain.size(transaction_index);
let info = pool.information();
assert_eq!(info.transactions_count, transaction_index + 1);
assert_eq!(info.transactions_size_in_bytes, transactions_size);
}
}
#[test]
fn test_memory_pool_timestamp_ordering_strategy() {
let mut pool = construct_memory_pool();
let chain = &mut ChainBuilder::new();
TransactionBuilder::with_output(10).store(chain)
.set_output(20).store(chain)
.set_output(30).store(chain)
.set_output(40).store(chain);
let mut pool = to_memory_pool(chain);
// remove transactions [4, 1, 2] (timestamps: [0, 0, 1])
// remove transactions [0, 3, 1] (timestamps: [0, 0, 1]) {conflict resolved by hash}
let transactions = pool.remove_n_with_strategy(3, OrderingStrategy::ByTimestamp);
assert_eq!(transactions.len(), 3);
assert_eq!(transactions[0].hash(), RAW_TRANSACTION4_HASH.into());
assert_eq!(transactions[1].hash(), RAW_TRANSACTION1_HASH.into());
assert_eq!(transactions[2].hash(), RAW_TRANSACTION2_HASH.into());
assert_eq!(transactions[0], chain.at(0));
assert_eq!(transactions[1], chain.at(3));
assert_eq!(transactions[2], chain.at(1));
assert_eq!(pool.get_transactions_ids().len(), 1);
// remove transactions [3] (timestamps: [2])
// remove transactions [2] (timestamps: [2])
let transactions = pool.remove_n_with_strategy(3, OrderingStrategy::ByTimestamp);
assert_eq!(transactions.len(), 1);
assert_eq!(transactions[0].hash(), RAW_TRANSACTION3_HASH.into());
assert_eq!(transactions[0], chain.at(2));
}
#[test]
fn test_memory_pool_transaction_score_ordering_strategy() {
let mut pool = construct_memory_pool();
let chain = &mut ChainBuilder::new();
TransactionBuilder::with_output(10).store(chain)
.set_output(40).store(chain)
.set_output(30).store(chain)
.set_output(20).store(chain);
let mut pool = to_memory_pool(chain);
let transactions = pool.remove_n_with_strategy(4, OrderingStrategy::ByTransactionScore);
assert_eq!(transactions.len(), 4);
assert_eq!(transactions[0].hash(), RAW_TRANSACTION1_HASH.into());
assert_eq!(transactions[1].hash(), RAW_TRANSACTION3_HASH.into());
assert_eq!(transactions[2].hash(), RAW_TRANSACTION2_HASH.into());
assert_eq!(transactions[3].hash(), RAW_TRANSACTION4_HASH.into());
assert_eq!(pool.get_transactions_ids().len(), 0);
assert_eq!(transactions[0], chain.at(1));
assert_eq!(transactions[1], chain.at(2));
assert_eq!(transactions[2], chain.at(3));
assert_eq!(transactions[3], chain.at(0));
}
#[test]
fn test_memory_pool_transaction_score_ordering_strategy_with_virtual_fee() {
let mut pool = construct_memory_pool();
let chain = &mut ChainBuilder::new();
TransactionBuilder::with_output(10).store(chain)
.set_output(40).store(chain)
.set_output(30).store(chain)
.set_output(20).store(chain);
let mut pool = to_memory_pool(chain);
// increase miner score of transaction 4 to move it to position #1
pool.set_virtual_fee(&RAW_TRANSACTION4_HASH.into(), 1000000000);
// decrease miner score of transaction 3 to move it to position #4
pool.set_virtual_fee(&RAW_TRANSACTION3_HASH.into(), -500000000);
// increase miner score of transaction 3 to move it to position #1
pool.set_virtual_fee(&chain.hash(3), 100);
// decrease miner score of transaction 1 to move it to position #4
pool.set_virtual_fee(&chain.hash(1), -30);
let transactions = pool.remove_n_with_strategy(4, OrderingStrategy::ByTransactionScore);
assert_eq!(transactions.len(), 4);
assert_eq!(transactions[0].hash(), RAW_TRANSACTION4_HASH.into());
assert_eq!(transactions[1].hash(), RAW_TRANSACTION1_HASH.into());
assert_eq!(transactions[2].hash(), RAW_TRANSACTION2_HASH.into());
assert_eq!(transactions[3].hash(), RAW_TRANSACTION3_HASH.into());
assert_eq!(pool.remove_n_with_strategy(1, OrderingStrategy::ByTransactionScore).len(), 0);
assert_eq!(transactions[0], chain.at(3));
assert_eq!(transactions[1], chain.at(2));
assert_eq!(transactions[2], chain.at(0));
assert_eq!(transactions[3], chain.at(1));
}
#[test]
fn test_memory_pool_package_score_ordering_strategy() {
// sizes of all transactions are equal to 60
// chain1:
// parent: fee = 30
// child: fee = 50
// chain2:
// parent: fee = 35
// child: fee = 10
// grandchild: fee: 100
let chain1_parent: Transaction = "00000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000011e000000000000000000000000".into();
let chain1_child: Transaction = "0000000001160f027c10384f1c6ebfe5d4c554cebe944d3c66f4ea1c07fab2de09eb42bfb10000000000000000000132000000000000000000000000".into();
let chain2_parent: Transaction = "000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000123000000000000000000000000".into();
let chain2_child: Transaction = "00000000018dc8362908a6286b3fb74399346cfefe56aec955fa3438f00c7c3ce4dea963ab000000000000000000010a000000000000000000000000".into();
let chain2_grandchild: Transaction = "00000000010448122df969ee00da3f4070915bdae9d900e32a57ba2ecfe99146e1eaf347900000000000000000000164000000000000000000000000".into();
let chain1_parent_hash = chain1_parent.hash();
let chain1_child_hash = chain1_child.hash();
let chain2_parent_hash = chain2_parent.hash();
let chain2_child_hash = chain2_child.hash();
let chain2_grandchild_hash = chain2_grandchild.hash();
let chain = &mut ChainBuilder::new();
// all transactions of same size
TransactionBuilder::with_default_input(0).set_output(30).store(chain) // transaction0
.to_input(0).set_output(50).store(chain) // transaction0 -> transaction1
.set_default_input(0).set_output(35).store(chain) // transaction2
.to_input(0).set_output(10).store(chain) // transaction2 -> transaction3
.to_input(0).set_output(100).store(chain); // transaction2 -> transaction3 -> transaction4
let mut pool = MemoryPool::new();
// compared by simple miner score:
// score({ chain1_parent }) = 30/60
// compared by simple transaction score:
// score({ transaction0 }) = 30/60
// <
// score({ chain2_parent }) = 35/60
let expected = vec![chain2_parent_hash.clone(), chain1_parent_hash.clone()];
pool.insert_verified(chain1_parent);
pool.insert_verified(chain2_parent);
// score({ transaction2 }) = 35/60
let expected = vec![chain.hash(2), chain.hash(0)];
pool.insert_verified(chain.at(0));
pool.insert_verified(chain.at(2));
assert_eq!(pool.read_n_with_strategy(2, OrderingStrategy::ByPackageScore), expected);
// { chain1_parent, chain1_child } now have bigger score than { chain2_parent }:
// score({ chain1_parent, chain1_child }) = (30 + 50) / 120 ~ 0.667
// { transaction0, transaction1 } now have bigger score than { transaction2 }:
// score({ transaction0, transaction1 }) = (30 + 50) / 120 ~ 0.667
// >
// score({ chain2_parent }) = 35/60 ~ 0.583
// score({ transaction2 }) = 35/60 ~ 0.583
// => chain1 is boosted
// => so transaction with lesser individual score (but with bigger package score) is mined first
pool.insert_verified(chain1_child);
let expected = vec![chain1_parent_hash.clone(), chain1_child_hash.clone(), chain2_parent_hash.clone()];
pool.insert_verified(chain.at(1));
let expected = vec![chain.hash(0), chain.hash(1), chain.hash(2)];
assert_eq!(pool.read_n_with_strategy(3, OrderingStrategy::ByPackageScore), expected);
// { chain1_parent, chain1_child } still have bigger score than { chain2_parent, chain2_child }
// score({ chain1_parent, chain1_child }) = (30 + 35) / 120 ~ 0.625
// { transaction0, transaction1 } still have bigger score than { transaction2, transaction3 }
// score({ transaction0, transaction1 }) = (30 + 35) / 120 ~ 0.625
// >
// score({ chain2_parent, chain2_child }) = (35 + 10) / 120 ~ 0.375
// score({ transaction2, transaction3 }) = (35 + 10) / 120 ~ 0.375
// => chain2 is not boosted
pool.insert_verified(chain2_child);
let expected = vec![chain1_parent_hash.clone(), chain1_child_hash.clone(),
chain2_parent_hash.clone(), chain2_child_hash.clone()];
pool.insert_verified(chain.at(3));
let expected = vec![chain.hash(0), chain.hash(1), chain.hash(2), chain.hash(3)];
assert_eq!(pool.read_n_with_strategy(4, OrderingStrategy::ByPackageScore), expected);
// { chain1_parent, chain1_child } now have lesser score than { chain2_parent, chain2_child, chain2_grandchild }
// score({ chain1_parent, chain1_child }) = (30 + 35) / 120 ~ 0.625
// { transaction0, transaction1 } now have lesser score than { transaction2, transaction3, transaction4 }
// score({ transaction0, transaction1 }) = (30 + 35) / 120 ~ 0.625
// <
// score({ chain2_parent, chain2_child, chain2_grandchild }) = (35 + 10 + 100) / 180 ~ 0.806
// score({ transaction2, transaction3, transaction4 }) = (35 + 10 + 100) / 180 ~ 0.806
// => chain2 is boosted
pool.insert_verified(chain2_grandchild);
let expected = vec![chain2_parent_hash.clone(), chain2_child_hash.clone(), chain2_grandchild_hash.clone(),
chain1_parent_hash.clone(), chain1_child_hash.clone()];
pool.insert_verified(chain.at(4));
let expected = vec![chain.hash(2), chain.hash(3), chain.hash(4), chain.hash(0), chain.hash(1)];
assert_eq!(pool.read_n_with_strategy(5, OrderingStrategy::ByPackageScore), expected);
// add virtual fee to the chain1_child so that chain1 is back to the position #1
pool.set_virtual_fee(&chain1_child_hash, 500i64);
let expected = vec![chain1_parent_hash.clone(), chain1_child_hash.clone(), chain2_parent_hash.clone(),
chain2_child_hash.clone(), chain2_grandchild_hash.clone()];
// add virtual fee to the transaction1 so that chain1 is back to the position #1
pool.set_virtual_fee(&chain.hash(1), 500i64);
let expected = vec![chain.hash(0), chain.hash(1), chain.hash(2), chain.hash(3), chain.hash(4)];
assert_eq!(pool.read_n_with_strategy(5, OrderingStrategy::ByPackageScore), expected);
}
#[test]
fn test_memory_pool_package_score_ordering_strategy_opposite_insert_order() {
// sizes of all transactions are equal to 60
// chain1:
// parent: fee = 17
// child: fee = 50
// grandchild: fee = 7
// chain2:
// parent: fee = 20
let chain1_parent: Transaction = "000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000111000000000000000000000000".into();
let chain1_child: Transaction = "0000000001213fb22ef427d846506b3b4a1474db4c520fce1036d7150e10fb244d6809c1a10000000000000000000132000000000000000000000000".into();
let chain1_grandchild: Transaction = "0000000001fb7c7a67c8b2e915b4dd562b151fa63098184dc310c37c36a8ea56f81c6e645a0000000000000000000107000000000000000000000000".into();
let chain2_parent: Transaction = "000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000114000000000000000000000000".into();
let chain1_parent_hash = chain1_parent.hash();
let chain1_child_hash = chain1_child.hash();
let chain1_grandchild_hash = chain1_grandchild.hash();
let chain2_parent_hash = chain2_parent.hash();
let chain = &mut ChainBuilder::new();
// all transactions of same size
TransactionBuilder::with_default_input(0).set_output(17).store(chain) // transaction0
.to_input(0).set_output(50).store(chain) // transaction0 -> transaction1
.to_input(0).set_output(7).store(chain) // transaction0 -> transaction1 -> transaction2
.set_default_input(0).set_output(20).store(chain); // transaction3
let mut pool = MemoryPool::new();
// chain1_parent is not linked to the chain1_grandchild
// => they are in separate chains now
// => chain2 has greater score than both of these chains
pool.insert_verified(chain2_parent);
pool.insert_verified(chain1_parent);
pool.insert_verified(chain1_grandchild);
let expected = vec![chain2_parent_hash.clone(), chain1_parent_hash.clone(), chain1_grandchild_hash.clone()];
pool.insert_verified(chain.at(3));
pool.insert_verified(chain.at(0));
pool.insert_verified(chain.at(2));
let expected = vec![chain.hash(3), chain.hash(0), chain.hash(2)];
assert_eq!(pool.read_n_with_strategy(3, OrderingStrategy::ByPackageScore), expected);
// insert the missing transaction to link together chain1
// => it now will have better score than chain2
pool.insert_verified(chain1_child);
let expected = vec![chain1_parent_hash.clone(), chain1_child_hash.clone(), chain2_parent_hash.clone(),
chain1_grandchild_hash.clone()];
pool.insert_verified(chain.at(1));
let expected = vec![chain.hash(0), chain.hash(1), chain.hash(3), chain.hash(2)];
assert_eq!(pool.read_n_with_strategy(4, OrderingStrategy::ByPackageScore), expected);
}
#[test]
fn test_memory_pool_complex_transactions_tree_opposite_insert_order() {
// all transaction have equal size
// level0 transactions:
// level00: fee = 10
// level01: fee = 20
// level02: fee = 30
// level1 transactions:
// level00 -> level10: fee = 40
// level00 + level01 -> level11: fee = 50
// level2 transactions:
// level02 + level10 + level11 -> level20: fee = 60
let level00: Transaction = "0000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000".into();
let level01: Transaction = "00000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000114000000000000000000000000".into();
let level02: Transaction = "0000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011e000000000000000000000000".into();
let level10: Transaction = "0000000003f0c6441fcf6ec5feff2ec1d4791f3378f0ee3ca763f037465ecbde2defb7dbbe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128000000000000000000000000".into();
let level11: Transaction = "0000000003f0c6441fcf6ec5feff2ec1d4791f3378f0ee3ca763f037465ecbde2defb7dbbe0000000000000000004e4ae7a98cc93a19f42df8dd0439578c4984650782160058c120d797f457a49b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000".into();
let level20: Transaction = "0000000003f7028778f8f0eb8b3b7f082c07842d9c58231286626f891d1b2b1aec562f186e0000000000000000001bcdef7650948fe1203aa1995ff61dd2610ac76a6f5b26399907319d40e6ba0500000000000000000059137aa9303e3b33e82e401a529c28dece1bc6785a001c82f9a062ce69a65fee000000000000000000013c000000000000000000000000".into();
let level00_hash = level00.hash();
let level01_hash = level01.hash();
let level02_hash = level02.hash();
let level10_hash = level10.hash();
let level11_hash = level11.hash();
let level20_hash = level20.hash();
let chain = &mut ChainBuilder::new();
// all transactions of same size (=> 3 inputs)
// construct level0
TransactionBuilder::with_default_input(0).add_default_input(0).add_default_input(0).set_output(10).store(chain) // transaction0
.set_default_input(0).add_default_input(0).add_default_input(0).set_output(20).store(chain) // transaction1
.set_default_input(0).add_default_input(0).add_default_input(0).set_output(30).store(chain) // transaction2
// construct level1
.set_default_input(0).add_default_input(0).add_input(&chain.at(0), 0).set_output(40).store(chain) // transaction0 -> transaction3
.set_default_input(0).add_input(&chain.at(0), 0).add_input(&chain.at(1), 0).set_output(50).store(chain) // transaction0 + transaction1 -> transaction4
// construct level3
.set_input(&chain.at(2), 0).add_input(&chain.at(3), 0).add_input(&chain.at(4), 0).set_output(60).store(chain); // transaction2 + transaction3 + transaction4 -> transaction5
let mut pool = MemoryPool::new();
// insert level1 + level2. There are two chains:
// score({ level10, level20 }) = 40 + 60
// score({ level11, level20 }) = 50 + 60
// And three transactions:
// score(level10) = 40
// score(level11) = 50
// score(level20) = 60
pool.insert_verified(level20);
pool.insert_verified(level10);
pool.insert_verified(level11);
let expected = vec![level11_hash.clone(), level10_hash.clone(), level20_hash.clone()];
// score({ transaction3, transaction5 }) = 40 + 60
// score({ transaction4, transaction5 }) = 50 + 60
pool.insert_verified(chain.at(5));
pool.insert_verified(chain.at(3));
pool.insert_verified(chain.at(4));
let expected = vec![chain.hash(4), chain.hash(3), chain.hash(5)];
assert_eq!(pool.read_n_with_strategy(3, OrderingStrategy::ByTransactionScore), expected);
assert_eq!(pool.read_n_with_strategy(3, OrderingStrategy::ByPackageScore), expected);
// insert another one transaction from the chain. Three chains:
// score({ level10, level20 }) = 40 + 60
// score({ level11, level20 }) = 50 + 60
// score({ level02, level20 }) = 30 + 60
pool.insert_verified(level02);
let expected = vec![level11_hash.clone(), level10_hash.clone(), level02_hash.clone(), level20_hash.clone()];
// score({ transaction3, transaction5 }) = 40 + 60
// score({ transaction4, transaction5 }) = 50 + 60
// score({ transaction2, transaction5 }) = 30 + 60
pool.insert_verified(chain.at(2));
let expected = vec![chain.hash(4), chain.hash(3), chain.hash(2), chain.hash(5)];
assert_eq!(pool.read_n_with_strategy(4, OrderingStrategy::ByTransactionScore), expected);
assert_eq!(pool.read_n_with_strategy(4, OrderingStrategy::ByPackageScore), expected);
// insert another one transaction from the chain. Three chains:
// score({ level10, level20 }) = 40 + 60 / 2 = 0.5
// score({ level01, level11, level20 }) = 20 + 50 + 60 / 3 ~ 0.333
// score({ level02, level20 }) = 30 + 60 / 2 = 0.45
// but second chain will be removed first anyway because previous #1 ({ level11, level20}) noew depends on level 01
pool.insert_verified(level01);
let expected = vec![level10_hash.clone(), level02_hash.clone(), level01_hash.clone(), level11_hash.clone(), level20_hash.clone()];
// score({ transaction3, transaction5 }) = 40 + 60 / 2 = 0.5
// score({ transaction1, transaction4, transaction5 }) = 20 + 50 + 60 / 3 ~ 0.333
// score({ transaction2, transaction5 }) = 30 + 60 / 2 = 0.45
// but second chain will be removed first anyway because previous #1 ({ transaction4, transaction5}) now depends on level 01
pool.insert_verified(chain.at(1));
let expected = vec![chain.hash(3), chain.hash(2), chain.hash(1), chain.hash(4), chain.hash(5)];
assert_eq!(pool.read_n_with_strategy(5, OrderingStrategy::ByTransactionScore), expected);
assert_eq!(pool.read_n_with_strategy(5, OrderingStrategy::ByPackageScore), expected);
// insert another one transaction from the chain. Four chains:
// score({ level00, level10, level20 }) = (10 + 40 + 60) / (60 + 60 + 142) ~ 0.420
// score({ level00, level11, level20 }) = (10 + 50 + 60) / (60 + 60 + 142) ~ 0.458
// score({ level10, level11, level20 }) = (20 + 50 + 60) / (60 + 60 + 142) ~ 0.496
// score({ level02, level20 }) = (30 + 60) / (60 + 142) ~ 0.445
pool.insert_verified(level00);
let expected = vec![level02_hash.clone(), level01_hash.clone(), level00_hash.clone(),
level11_hash.clone(), level10_hash.clone(), level20_hash.clone()];
// score({ transaction0, transaction3, transaction5 }) = (10 + 40 + 60) / (60 + 60 + 142) ~ 0.420
// score({ transaction0, transaction4, transaction5 }) = (10 + 50 + 60) / (60 + 60 + 142) ~ 0.458
// score({ transaction1, transaction3, transaction5 }) = (20 + 50 + 60) / (60 + 60 + 142) ~ 0.496
// score({ transaction2, transaction5 }) = (30 + 60) / (60 + 142) ~ 0.445
pool.insert_verified(chain.at(0));
let expected = vec![chain.hash(2), chain.hash(1), chain.hash(0), chain.hash(4), chain.hash(3), chain.hash(5)];
assert_eq!(pool.read_n_with_strategy(6, OrderingStrategy::ByTransactionScore), expected);
assert_eq!(pool.read_n_with_strategy(6, OrderingStrategy::ByPackageScore), expected);
}

View File

@ -5,3 +5,5 @@ authors = ["Nikolay Volf <nikvolf@gmail.com>"]
[dependencies]
chain = { path = "../chain" }
primitives = { path = "../primitives" }
serialization = { path = "../serialization" }

View File

@ -0,0 +1,125 @@
use primitives::hash::H256;
use ser::Serializable;
use primitives::bytes::Bytes;
use chain::{Transaction, TransactionInput, TransactionOutput, OutPoint};
#[derive(Debug, Default, Clone)]
pub struct ChainBuilder {
pub transactions: Vec<Transaction>,
}
#[derive(Debug, Default, Clone)]
pub struct TransactionBuilder {
pub transaction: Transaction,
}
impl ChainBuilder {
pub fn new() -> ChainBuilder {
ChainBuilder {
transactions: Vec::new(),
}
}
pub fn at(&self, transaction_index: usize) -> Transaction {
self.transactions[transaction_index].clone()
}
pub fn hash(&self, transaction_index: usize) -> H256 {
self.transactions[transaction_index].hash()
}
pub fn size(&self, transaction_index: usize) -> usize {
self.transactions[transaction_index].serialized_size()
}
}
impl Into<Transaction> for TransactionBuilder {
fn into(self) -> Transaction {
self.transaction
}
}
impl TransactionBuilder {
pub fn with_version(version: i32) -> TransactionBuilder {
let builder = TransactionBuilder::default();
builder.set_version(version)
}
pub fn with_output(value: u64) -> TransactionBuilder {
let builder = TransactionBuilder::default();
builder.add_output(value)
}
pub fn with_default_input(output_index: u32) -> TransactionBuilder {
let builder = TransactionBuilder::default();
builder.add_input(&Transaction::default(), output_index)
}
pub fn to_input(self, output_index: u32) -> TransactionBuilder {
let builder = TransactionBuilder::default();
builder.add_input(&self.transaction, output_index)
}
pub fn set_version(mut self, version: i32) -> TransactionBuilder {
self.transaction.version = version;
self
}
pub fn add_output(mut self, value: u64) -> TransactionBuilder {
self.transaction.outputs.push(TransactionOutput {
value: value,
script_pubkey: Bytes::new_with_len(0),
});
self
}
pub fn set_output(mut self, value: u64) -> TransactionBuilder {
self.transaction.outputs = vec![TransactionOutput {
value: value,
script_pubkey: Bytes::new_with_len(0),
}];
self
}
pub fn add_default_input(self, output_index: u32) -> TransactionBuilder {
self.add_input(&Transaction::default(), output_index)
}
pub fn add_input(mut self, transaction: &Transaction, output_index: u32) -> TransactionBuilder {
self.transaction.inputs.push(TransactionInput {
previous_output: OutPoint {
hash: transaction.hash(),
index: output_index,
},
script_sig: Bytes::new_with_len(0),
sequence: 0,
});
self
}
pub fn set_default_input(self, output_index: u32) -> TransactionBuilder {
self.set_input(&Transaction::default(), output_index)
}
pub fn set_input(mut self, transaction: &Transaction, output_index: u32) -> TransactionBuilder {
self.transaction.inputs = vec![TransactionInput {
previous_output: OutPoint {
hash: transaction.hash(),
index: output_index,
},
script_sig: Bytes::new_with_len(0),
sequence: 0,
}];
self
}
pub fn store(self, chain: &mut ChainBuilder) -> Self {
chain.transactions.push(self.transaction.clone());
self
}
pub fn hash(self) -> H256 {
self.transaction.hash()
}
}

View File

@ -1,9 +1,17 @@
//! Various chain-specific test dummies
extern crate chain;
extern crate primitives;
extern crate serialization as ser;
use chain::Block;
pub mod chain_builder;
pub use chain_builder::{ChainBuilder, TransactionBuilder};
pub fn block1() -> Block {
let block: Block = "01000000ba8b9cda965dd8e536670f9ddec10e53aab14b20bacad27b9137190000000000190760b278fe7b8565fda3b968b918d5fd997f993b23674c0af3b6fde300b38f33a5914ce6ed5b1b01e32f570201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704e6ed5b1b014effffffff0100f2052a01000000434104b68a50eaa0287eff855189f949c1c6e5f58b37c88231373d8a59809cbae83059cc6469d65c665ccfd1cfeb75c6e8e19413bba7fbff9bc762419a76d87b16086eac000000000100000001a6b97044d03da79c005b20ea9c0e1a6d9dc12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac00000000".into();
block

View File

@ -8,72 +8,75 @@ digraph dependencies {
N6[label="miner",shape=box];
N7[label="p2p",shape=box];
N8[label="script",shape=box];
N9[label="aho-corasick",shape=box];
N10[label="memchr",shape=box];
N11[label="ansi_term",shape=box];
N12[label="arrayvec",shape=box];
N13[label="nodrop",shape=box];
N14[label="odds",shape=box];
N15[label="base58",shape=box];
N16[label="bitcrypto",shape=box];
N17[label="primitives",shape=box];
N18[label="rust-crypto",shape=box];
N19[label="bitflags v0.4.0",shape=box];
N20[label="bitflags v0.7.0",shape=box];
N21[label="byteorder",shape=box];
N22[label="cfg-if",shape=box];
N23[label="chain",shape=box];
N24[label="heapsize",shape=box];
N25[label="rustc-serialize",shape=box];
N26[label="serialization",shape=box];
N27[label="libc",shape=box];
N28[label="strsim",shape=box];
N29[label="term_size",shape=box];
N30[label="unicode-segmentation",shape=box];
N31[label="unicode-width",shape=box];
N32[label="vec_map",shape=box];
N33[label="yaml-rust",shape=box];
N34[label="crossbeam",shape=box];
N35[label="elastic-array",shape=box];
N36[label="ethcore-devtools",shape=box];
N37[label="parking_lot",shape=box];
N38[label="rocksdb",shape=box];
N39[label="deque",shape=box];
N40[label="rand",shape=box];
N41[label="log",shape=box];
N42[label="regex",shape=box];
N43[label="eth-secp256k1",shape=box];
N44[label="gcc",shape=box];
N45[label="futures",shape=box];
N46[label="futures-cpupool",shape=box];
N47[label="num_cpus v1.1.0",shape=box];
N48[label="rayon",shape=box];
N49[label="kernel32-sys",shape=box];
N50[label="winapi",shape=box];
N51[label="winapi-build",shape=box];
N52[label="lazy_static",shape=box];
N53[label="lazycell",shape=box];
N54[label="mio",shape=box];
N55[label="miow",shape=box];
N56[label="net2",shape=box];
N57[label="nix",shape=box];
N58[label="slab",shape=box];
N59[label="ws2_32-sys",shape=box];
N60[label="rustc_version",shape=box];
N61[label="semver",shape=box];
N62[label="void",shape=box];
N63[label="num_cpus v0.2.13",shape=box];
N64[label="owning_ref",shape=box];
N65[label="time",shape=box];
N66[label="tokio-core",shape=box];
N67[label="parking_lot_core",shape=box];
N68[label="smallvec",shape=box];
N69[label="regex-syntax",shape=box];
N70[label="thread_local",shape=box];
N71[label="utf8-ranges",shape=box];
N72[label="rocksdb-sys",shape=box];
N73[label="scoped-tls",shape=box];
N74[label="thread-id",shape=box];
N9[label="verification",shape=box];
N10[label="aho-corasick",shape=box];
N11[label="memchr",shape=box];
N12[label="ansi_term",shape=box];
N13[label="arrayvec",shape=box];
N14[label="nodrop",shape=box];
N15[label="odds",shape=box];
N16[label="base58",shape=box];
N17[label="bitcrypto",shape=box];
N18[label="primitives",shape=box];
N19[label="rust-crypto",shape=box];
N20[label="bitflags v0.4.0",shape=box];
N21[label="bitflags v0.7.0",shape=box];
N22[label="byteorder",shape=box];
N23[label="cfg-if",shape=box];
N24[label="chain",shape=box];
N25[label="heapsize",shape=box];
N26[label="rustc-serialize",shape=box];
N27[label="serialization",shape=box];
N28[label="libc",shape=box];
N29[label="strsim",shape=box];
N30[label="term_size",shape=box];
N31[label="unicode-segmentation",shape=box];
N32[label="unicode-width",shape=box];
N33[label="vec_map",shape=box];
N34[label="yaml-rust",shape=box];
N35[label="crossbeam",shape=box];
N36[label="elastic-array",shape=box];
N37[label="ethcore-devtools",shape=box];
N38[label="parking_lot",shape=box];
N39[label="rocksdb",shape=box];
N40[label="test-data",shape=box];
N41[label="deque",shape=box];
N42[label="rand",shape=box];
N43[label="log",shape=box];
N44[label="regex",shape=box];
N45[label="eth-secp256k1",shape=box];
N46[label="gcc",shape=box];
N47[label="futures",shape=box];
N48[label="futures-cpupool",shape=box];
N49[label="num_cpus v1.1.0",shape=box];
N50[label="rayon",shape=box];
N51[label="kernel32-sys",shape=box];
N52[label="winapi",shape=box];
N53[label="winapi-build",shape=box];
N54[label="lazy_static",shape=box];
N55[label="lazycell",shape=box];
N56[label="linked-hash-map",shape=box];
N57[label="mio",shape=box];
N58[label="miow",shape=box];
N59[label="net2",shape=box];
N60[label="nix",shape=box];
N61[label="slab",shape=box];
N62[label="ws2_32-sys",shape=box];
N63[label="rustc_version",shape=box];
N64[label="semver",shape=box];
N65[label="void",shape=box];
N66[label="num_cpus v0.2.13",shape=box];
N67[label="owning_ref",shape=box];
N68[label="time",shape=box];
N69[label="tokio-core",shape=box];
N70[label="parking_lot_core",shape=box];
N71[label="smallvec",shape=box];
N72[label="regex-syntax",shape=box];
N73[label="thread_local",shape=box];
N74[label="utf8-ranges",shape=box];
N75[label="rocksdb-sys",shape=box];
N76[label="scoped-tls",shape=box];
N77[label="thread-id",shape=box];
N0 -> N1[label="",style=dashed];
N0 -> N2[label="",style=dashed];
N0 -> N3[label="",style=dashed];
@ -82,153 +85,164 @@ digraph dependencies {
N0 -> N6[label="",style=dashed];
N0 -> N7[label="",style=dashed];
N0 -> N8[label="",style=dashed];
N1 -> N11[label="",style=dashed];
N1 -> N20[label="",style=dashed];
N1 -> N27[label="",style=dashed];
N0 -> N9[label="",style=dashed];
N1 -> N12[label="",style=dashed];
N1 -> N21[label="",style=dashed];
N1 -> N28[label="",style=dashed];
N1 -> N29[label="",style=dashed];
N1 -> N30[label="",style=dashed];
N1 -> N31[label="",style=dashed];
N1 -> N32[label="",style=dashed];
N1 -> N33[label="",style=dashed];
N2 -> N17[label="",style=dashed];
N2 -> N21[label="",style=dashed];
N2 -> N23[label="",style=dashed];
N2 -> N26[label="",style=dashed];
N2 -> N35[label="",style=dashed];
N1 -> N34[label="",style=dashed];
N2 -> N18[label="",style=dashed];
N2 -> N22[label="",style=dashed];
N2 -> N24[label="",style=dashed];
N2 -> N27[label="",style=dashed];
N2 -> N36[label="",style=dashed];
N2 -> N37[label="",style=dashed];
N2 -> N38[label="",style=dashed];
N3 -> N41[label="",style=dashed];
N3 -> N42[label="",style=dashed];
N4 -> N15[label="",style=dashed];
N2 -> N39[label="",style=dashed];
N2 -> N40[label="",style=dashed];
N3 -> N43[label="",style=dashed];
N3 -> N44[label="",style=dashed];
N4 -> N16[label="",style=dashed];
N4 -> N17[label="",style=dashed];
N4 -> N25[label="",style=dashed];
N4 -> N40[label="",style=dashed];
N4 -> N43[label="",style=dashed];
N4 -> N52[label="",style=dashed];
N5 -> N16[label="",style=dashed];
N4 -> N18[label="",style=dashed];
N4 -> N26[label="",style=dashed];
N4 -> N42[label="",style=dashed];
N4 -> N45[label="",style=dashed];
N4 -> N54[label="",style=dashed];
N5 -> N17[label="",style=dashed];
N5 -> N21[label="",style=dashed];
N5 -> N23[label="",style=dashed];
N5 -> N26[label="",style=dashed];
N6 -> N17[label="",style=dashed];
N6 -> N23[label="",style=dashed];
N5 -> N18[label="",style=dashed];
N5 -> N22[label="",style=dashed];
N5 -> N24[label="",style=dashed];
N5 -> N27[label="",style=dashed];
N6 -> N18[label="",style=dashed];
N6 -> N24[label="",style=dashed];
N6 -> N26[label="",style=dashed];
N6 -> N25[label="",style=dashed];
N6 -> N27[label="",style=dashed];
N7 -> N5[label="",style=dashed];
N7 -> N16[label="",style=dashed];
N7 -> N17[label="",style=dashed];
N7 -> N37[label="",style=dashed];
N7 -> N40[label="",style=dashed];
N7 -> N41[label="",style=dashed];
N7 -> N45[label="",style=dashed];
N7 -> N46[label="",style=dashed];
N7 -> N65[label="",style=dashed];
N7 -> N66[label="",style=dashed];
N7 -> N18[label="",style=dashed];
N7 -> N38[label="",style=dashed];
N7 -> N42[label="",style=dashed];
N7 -> N43[label="",style=dashed];
N7 -> N47[label="",style=dashed];
N7 -> N48[label="",style=dashed];
N7 -> N68[label="",style=dashed];
N7 -> N69[label="",style=dashed];
N8 -> N4[label="",style=dashed];
N8 -> N16[label="",style=dashed];
N8 -> N17[label="",style=dashed];
N8 -> N23[label="",style=dashed];
N8 -> N26[label="",style=dashed];
N9 -> N10[label="",style=dashed];
N10 -> N27[label="",style=dashed];
N12 -> N13[label=""];
N12 -> N14[label=""];
N8 -> N18[label="",style=dashed];
N8 -> N24[label="",style=dashed];
N8 -> N27[label="",style=dashed];
N9 -> N2[label="",style=dashed];
N9 -> N18[label="",style=dashed];
N9 -> N24[label="",style=dashed];
N9 -> N27[label="",style=dashed];
N9 -> N37[label="",style=dashed];
N9 -> N38[label="",style=dashed];
N9 -> N40[label="",style=dashed];
N9 -> N56[label="",style=dashed];
N10 -> N11[label="",style=dashed];
N11 -> N28[label="",style=dashed];
N13 -> N14[label=""];
N16 -> N17[label="",style=dashed];
N16 -> N18[label="",style=dashed];
N17 -> N24[label="",style=dashed];
N17 -> N25[label="",style=dashed];
N13 -> N15[label=""];
N14 -> N15[label=""];
N17 -> N18[label="",style=dashed];
N17 -> N19[label="",style=dashed];
N18 -> N25[label="",style=dashed];
N18 -> N27[label="",style=dashed];
N18 -> N40[label="",style=dashed];
N18 -> N44[label="",style=dashed];
N18 -> N65[label="",style=dashed];
N23 -> N16[label="",style=dashed];
N23 -> N17[label="",style=dashed];
N23 -> N24[label="",style=dashed];
N23 -> N25[label="",style=dashed];
N23 -> N26[label="",style=dashed];
N24 -> N49[label="",style=dashed];
N26 -> N17[label="",style=dashed];
N26 -> N21[label="",style=dashed];
N29 -> N27[label="",style=dashed];
N29 -> N49[label="",style=dashed];
N29 -> N50[label="",style=dashed];
N36 -> N40[label="",style=dashed];
N37 -> N64[label="",style=dashed];
N37 -> N67[label="",style=dashed];
N38 -> N27[label="",style=dashed];
N38 -> N72[label="",style=dashed];
N39 -> N40[label="",style=dashed];
N40 -> N27[label="",style=dashed];
N42 -> N9[label="",style=dashed];
N42 -> N10[label="",style=dashed];
N42 -> N69[label="",style=dashed];
N42 -> N70[label="",style=dashed];
N42 -> N71[label="",style=dashed];
N43 -> N12[label="",style=dashed];
N43 -> N25[label="",style=dashed];
N43 -> N27[label="",style=dashed];
N43 -> N40[label="",style=dashed];
N43 -> N44[label="",style=dashed];
N44 -> N48[label="",style=dashed];
N45 -> N41[label="",style=dashed];
N46 -> N34[label="",style=dashed];
N46 -> N45[label="",style=dashed];
N46 -> N47[label="",style=dashed];
N47 -> N27[label="",style=dashed];
N48 -> N39[label="",style=dashed];
N48 -> N40[label="",style=dashed];
N48 -> N63[label="",style=dashed];
N49 -> N50[label="",style=dashed];
N49 -> N51[label="",style=dashed];
N54 -> N27[label="",style=dashed];
N54 -> N41[label="",style=dashed];
N54 -> N49[label="",style=dashed];
N54 -> N50[label="",style=dashed];
N54 -> N53[label=""];
N54 -> N55[label=""];
N54 -> N56[label=""];
N54 -> N57[label=""];
N54 -> N58[label="",style=dashed];
N55 -> N49[label=""];
N55 -> N50[label=""];
N55 -> N56[label=""];
N55 -> N59[label=""];
N56 -> N22[label=""];
N56 -> N27[label=""];
N56 -> N49[label=""];
N56 -> N50[label=""];
N56 -> N59[label=""];
N57 -> N19[label=""];
N57 -> N22[label=""];
N57 -> N27[label=""];
N18 -> N26[label="",style=dashed];
N19 -> N26[label="",style=dashed];
N19 -> N28[label="",style=dashed];
N19 -> N42[label="",style=dashed];
N19 -> N46[label="",style=dashed];
N19 -> N68[label="",style=dashed];
N24 -> N17[label="",style=dashed];
N24 -> N18[label="",style=dashed];
N24 -> N25[label="",style=dashed];
N24 -> N26[label="",style=dashed];
N24 -> N27[label="",style=dashed];
N25 -> N51[label="",style=dashed];
N27 -> N18[label="",style=dashed];
N27 -> N22[label="",style=dashed];
N30 -> N28[label="",style=dashed];
N30 -> N51[label="",style=dashed];
N30 -> N52[label="",style=dashed];
N37 -> N42[label="",style=dashed];
N38 -> N67[label="",style=dashed];
N38 -> N70[label="",style=dashed];
N39 -> N28[label="",style=dashed];
N39 -> N75[label="",style=dashed];
N40 -> N24[label="",style=dashed];
N41 -> N42[label="",style=dashed];
N42 -> N28[label="",style=dashed];
N44 -> N10[label="",style=dashed];
N44 -> N11[label="",style=dashed];
N44 -> N72[label="",style=dashed];
N44 -> N73[label="",style=dashed];
N44 -> N74[label="",style=dashed];
N45 -> N13[label="",style=dashed];
N45 -> N26[label="",style=dashed];
N45 -> N28[label="",style=dashed];
N45 -> N42[label="",style=dashed];
N45 -> N46[label="",style=dashed];
N46 -> N50[label="",style=dashed];
N47 -> N43[label="",style=dashed];
N48 -> N35[label="",style=dashed];
N48 -> N47[label="",style=dashed];
N48 -> N49[label="",style=dashed];
N49 -> N28[label="",style=dashed];
N50 -> N41[label="",style=dashed];
N50 -> N42[label="",style=dashed];
N50 -> N66[label="",style=dashed];
N51 -> N52[label="",style=dashed];
N51 -> N53[label="",style=dashed];
N57 -> N28[label="",style=dashed];
N57 -> N43[label="",style=dashed];
N57 -> N51[label="",style=dashed];
N57 -> N52[label="",style=dashed];
N57 -> N55[label=""];
N57 -> N58[label=""];
N57 -> N59[label=""];
N57 -> N60[label=""];
N57 -> N61[label=""];
N57 -> N62[label=""];
N59 -> N50[label=""];
N57 -> N61[label="",style=dashed];
N58 -> N51[label=""];
N58 -> N52[label=""];
N58 -> N59[label=""];
N58 -> N62[label=""];
N59 -> N23[label=""];
N59 -> N28[label=""];
N59 -> N51[label=""];
N60 -> N61[label=""];
N63 -> N27[label="",style=dashed];
N65 -> N27[label="",style=dashed];
N65 -> N49[label="",style=dashed];
N65 -> N50[label="",style=dashed];
N66 -> N41[label="",style=dashed];
N66 -> N45[label="",style=dashed];
N66 -> N54[label="",style=dashed];
N66 -> N58[label="",style=dashed];
N66 -> N73[label="",style=dashed];
N67 -> N27[label="",style=dashed];
N67 -> N40[label="",style=dashed];
N67 -> N49[label="",style=dashed];
N67 -> N50[label="",style=dashed];
N67 -> N68[label="",style=dashed];
N70 -> N74[label="",style=dashed];
N72 -> N27[label="",style=dashed];
N72 -> N44[label="",style=dashed];
N74 -> N27[label="",style=dashed];
N74 -> N49[label="",style=dashed];
N59 -> N52[label=""];
N59 -> N62[label=""];
N60 -> N20[label=""];
N60 -> N23[label=""];
N60 -> N28[label=""];
N60 -> N63[label=""];
N60 -> N64[label=""];
N60 -> N65[label=""];
N62 -> N52[label=""];
N62 -> N53[label=""];
N63 -> N64[label=""];
N66 -> N28[label="",style=dashed];
N68 -> N28[label="",style=dashed];
N68 -> N51[label="",style=dashed];
N68 -> N52[label="",style=dashed];
N69 -> N43[label="",style=dashed];
N69 -> N47[label="",style=dashed];
N69 -> N57[label="",style=dashed];
N69 -> N61[label="",style=dashed];
N69 -> N76[label="",style=dashed];
N70 -> N28[label="",style=dashed];
N70 -> N42[label="",style=dashed];
N70 -> N51[label="",style=dashed];
N70 -> N52[label="",style=dashed];
N70 -> N71[label="",style=dashed];
N73 -> N77[label="",style=dashed];
N75 -> N28[label="",style=dashed];
N75 -> N46[label="",style=dashed];
N77 -> N28[label="",style=dashed];
N77 -> N51[label="",style=dashed];
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 KiB

After

Width:  |  Height:  |  Size: 531 KiB