Просмотр исходного кода

Merge pull request #8 from mileschet/feature/lisp

Feature/lisp
ada 5 лет назад
Родитель
Сommit
ce52ac7ac3
47 измененных файлов с 3921 добавлено и 785 удалено
  1. 27 19
      Cargo.toml
  2. 8 2
      lisp/core.rs
  3. 39 0
      lisp/jubjub-add.lisp
  4. 0 70
      lisp/jubjub.lisp
  5. 25 6
      lisp/lisp.rs
  6. 1 1
      lisp/run.sh
  7. 9 2
      lisp/types.rs
  8. 24 0
      scripts/jsonrpc_client.py
  9. 29 0
      scripts/reorder-logs.py
  10. 111 0
      scripts/zk/4.6.2-multi-variable-operand-polynomial.py
  11. 139 0
      scripts/zk/4.8-example-computation.py
  12. 111 0
      src/async_serial.rs
  13. 376 0
      src/bin/dfi.rs
  14. 1 1
      src/bin/jubjub.rs
  15. 53 54
      src/bls_extensions.rs
  16. 52 0
      src/error.rs
  17. 5 0
      src/lib.rs
  18. 110 0
      src/net/acceptor.rs
  19. 189 0
      src/net/channel.rs
  20. 29 0
      src/net/connector.rs
  21. 28 0
      src/net/error.rs
  22. 38 0
      src/net/hosts.rs
  23. 131 0
      src/net/message_subscriber.rs
  24. 468 0
      src/net/messages.rs
  25. 26 0
      src/net/mod.rs
  26. 98 0
      src/net/p2p.rs
  27. 11 0
      src/net/protocols/mod.rs
  28. 87 0
      src/net/protocols/protocol_address.rs
  29. 60 0
      src/net/protocols/protocol_jobs_manager.rs
  30. 97 0
      src/net/protocols/protocol_ping.rs
  31. 59 0
      src/net/protocols/protocol_seed.rs
  32. 89 0
      src/net/protocols/protocol_version.rs
  33. 124 0
      src/net/sessions/inbound_session.rs
  34. 9 0
      src/net/sessions/mod.rs
  35. 129 0
      src/net/sessions/outbound_session.rs
  36. 124 0
      src/net/sessions/seed_session.rs
  37. 72 0
      src/net/sessions/session.rs
  38. 19 0
      src/net/settings.rs
  39. 6 0
      src/net/utility.rs
  40. 677 622
      src/serial.rs
  41. 7 0
      src/system/mod.rs
  42. 50 0
      src/system/stoppable_task.rs
  43. 79 0
      src/system/subscriber.rs
  44. 4 0
      src/system/types.rs
  45. 89 0
      src/utility.rs
  46. 1 6
      src/vm.rs
  47. 1 2
      src/vm_serial.rs

+ 27 - 19
Cargo.toml

@@ -27,40 +27,48 @@ rand_xorshift = "0.2"
 blake2s_simd = "0.5"
 bitvec = "0.18"
 bimap = "0.5.2"
+async-trait = "0.1.42"
+multimap = "0.8.2"
 
 hex = "0.4.2"
+num_enum = "0.5.0"
+
+lazy_static = "1.4.0"
+itertools = "0.8.0"
+fnv = "1.0.6"
+regex = "1"
 
 simplelog = "0.7.4"
 clap = "3.0.0-beta.1"
 failure = "0.1.8"
 failure_derive = "0.1.8"
+log = "0.4"
+ctrlc = "3.1.7"
+serde_json = "1.0.61"
+owning_ref = "0.4.1"
 
-regex = "1"
-
-lazy_static = "1.4.0"
-itertools = "0.8.0"
-fnv = "1.0.6"
+smol = "1.2.4"
+futures = "0.3.5"
+async-channel = "1.4.2"
+async-executor = "1.4.0"
+async-dup = "1.1.0"
+async-std = "1.6.2"
+easy-parallel = "3.1.0"
 
-[[bin]]
-name = "basic"
-path = "src/old/basic_minimal.rs"
+jsonrpc-core = "16.0.0"
+http-types = "2.9.0"
+async-h1 = "2.3.0"
+async-native-tls = "0.3.3"
 
 [[bin]]
-name = "mimc"
-path = "src/bin/mimc.rs"
+name = "lisp"
+path = "lisp/lisp.rs"
 
 [[bin]]
 name = "zkvm"
 path = "src/bin/zkvm.rs"
 
 [[bin]]
-name = "mint"
-path = "src/bin/mint.rs"
+name = "dfi"
+path = "src/bin/dfi.rs"
 
-[[bin]]
-name = "jubjub"
-path = "src/bin/jubjub.rs"
-
-[[bin]]
-name = "lisp"
-path = "lisp/lisp.rs"

+ 8 - 2
lisp/core.rs

@@ -267,6 +267,7 @@ fn sub_scalar(a: MalArgs) -> MalRet {
 }
 
 fn mul_scalar(a: MalArgs) -> MalRet {
+    println!("{:?}", a);
     match (a[0].clone(), a[1].clone()) {
         (ZKScalar(mut a0), ZKScalar(a1)) => {
             // let (mut s0, s1) = (Scalar::from_string(&a0), Scalar::from_string(&a1));
@@ -357,15 +358,20 @@ fn scalar_from(a: MalArgs) -> MalRet {
 
 fn add_scalar(a: MalArgs) -> MalRet {
     match (a[0].clone(), a[1].clone()) {
+        (ZKScalar(a0), ZKScalar(a1)) => {
+            let (mut z0, z1) = (a0.clone(), a1.clone());
+            z0.add_assign(z1);
+            Ok(ZKScalar(z0))
+        },
         (Str(a0), Str(a1)) => {
             let (mut s0, s1) = (
                 bls12_381::Scalar::from_string(&a0),
                 bls12_381::Scalar::from_string(&a1),
             );
             s0.add_assign(s1);
-            Ok(Str(std::string::ToString::to_string(&s0)[2..].to_string()))
+            Ok(ZKScalar(s0))
         }
-        _ => error("expected (scalar, scalar"),
+        _ => error(&format!("add scalar expected (scalar, scalar)\n {:?}", a).to_string()),
     }
 }
 

+ 39 - 0
lisp/jubjub-add.lisp

@@ -0,0 +1,39 @@
+(println "jubjub-add.lisp")
+;; Compute U = (u1 + v1) * (v2 - EDWARDS_A*u2)
+;;           = (u1 + v1) * (u2 + v2)
+( (let* [
+      EDWARDS_D (alloc-const "EDWARDS_D" (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))
+      u1 (alloc "u1" (scalar "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e"))
+      v1 (alloc "v1" (scalar "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891"))
+      u2 (alloc "u2" (scalar "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e"))
+      v2 (alloc "v2" (scalar "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891"))
+      U (alloc-input "U" (* (+ u1 u2) (+ v1 v2)))
+      A (alloc-input "A" (* v2 u1))
+      B (alloc-input "B" (* u2 v1))
+      C (alloc-input "C" (* EDWARDS_D (* A B)))
+      ]
+(prove
+ (setup 
+  (
+  (enforce  
+    (
+     (scalar::one u1)
+     (scalar::one v1)
+    )
+    (
+     (scalar::one u2)
+     (scalar::one v2)
+    )
+    (scalar::one U)
+  )
+  (enforce
+    (EDWARDS_D A)
+    (scalar::one B)
+    (scalar::one C)
+  )
+  )
+ )
+)
+)
+ )
+;; (println 'verify  (MyCircuit (scalar 27)))

+ 0 - 70
lisp/jubjub.lisp

@@ -1,70 +0,0 @@
-;; public params
-(def! a_u "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e")
-(def! a_v "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891")
-(def! b_u "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e")
-(def! b_v "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891")
-(def! a "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000")
-(def! d "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1")
-(def! one "0000000000000000000000000000000000000000000000000000000000000001")
-(defzk! circuit ())
-;; U should be evaluated just once
-(def! U (fn* [x1 y1 x2 y2] (* (+ x1 y1) (+ x2 y2))))
-(def! A (fn* [x1 y2] (* y2 x1)))
-(def! B (fn* [y1 x2] (* x2 y1)))
-(def! C (fn* [x1 y1 x2 y2] (* d (A x1 y2) (B y1 x2))))
-(def! P.x (fn* [x1 y1 x2 y2] (/ (+ (A x1 y2) (B y1 x2)) (+ one (C x1 y1 x2 y2)))))
-(def! P.y (fn* [x1 y1 x2 y2] (/ (- (U x1 y1 x2 y2) (A x1 y2) (B y1 x2)) (+ one (C x1 y1 x2 y2)))))
-
-
-
-;; lc0 = bellman::LinearCombination::<Scalar>::zero();
-;; (lc0-args LinearCombination<Scalar>)
-
-;; (cs! circuit (lc0-args) (lc1-args) (lc2-args))
-
-;; (lc-add-coeff 1 1)
-
-(def! jubjub-add (fn* [x1 y1 x2 y2] (cs! circuit (
-                    (add lc0 x1)
-                    (add lc0 y1)
-                    (add lc1 x2)
-                    (add lc1 y2)
-                    (add lc2 (U x1 y1 x2 y2))
-                    enforce
-;; Compute P.x = (A + B) / (1 + C)
-                    (add-one lc0)
-                    (add lc0 (C x1 y1 x2 y2))
-                    (add lc1 (P.x x1 y1 x2 y2))
-                    (add lc1 (A x1 y2))
-                    (add lc1 (B y1 x2))
-                    enforce
-;; Compute P.y = (U - A - B) / (1 - C)                    
-                    (add-one lc0)
-                    (sub lc0 (C x1 y1 x2 y2))
-                    (add lc1 (P.y x1 y1 x2 y2))
-                    (add lc2 (U x1 y1 x2 y2))
-                    (sub lc2 (A x1 y2))
-                    (sub lc2 (B y1 x2))
-                    enforce 
-                    ))))
-(def! circuit (jubjub-add a_u a_v b_u b_v))
-;;(println circuit)
-(def! circuit (cs! circuit (
-                    (public (P.x a_u a_v b_u b_v)) 
-                    (public (P.y a_u a_v b_u b_v)) 
-                    (add lc0 (P.x a_u a_v b_u b_v))
-                    (add-one lc1)
-                    (add lc2 (P.x a_u a_v b_u b_v))
-                    enforce
-                    (add lc0 (P.y a_u a_v b_u b_v))
-                    (add-one lc1)
-                    (add lc2 (P.y a_u a_v b_u b_v))
-                    enforce
-                  )))
-;;(println circuit)
-;; contract exection
-(def! circuit (cs! circuit (
-                            (params [a_u a_v b_u b_v])
-                            )))
-
-(println circuit)

+ 25 - 6
lisp/lisp.rs

@@ -302,6 +302,23 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
                         ast = eval(a1.clone(), env.clone())?;
                         prove(a1.clone(), env.clone())
                     }
+                    Sym(ref a0sym) if a0sym == "alloc-const" => {
+                        let a1 = l[1].clone();
+                        let value = eval(l[2].clone(), env.clone())?;
+                        let result = eval(value.clone(), env.clone())?;
+                        let allocs = get_allocations(&env, "AllocationsConst");
+                        let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
+                        for (k, v) in allocs.iter() {
+                            new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
+                        }
+                        new_hm.insert(a1.pr_str(false), result.clone());
+                        env_set(
+                            &env,
+                            Sym("AllocationsConst".to_string()),
+                            Hash(Rc::new(new_hm), Rc::new(Nil)),
+                        )?;
+                        Ok(result.clone())
+                    }
                     Sym(ref a0sym) if a0sym == "alloc-input" => {
                         let a1 = l[1].clone();
                         let value = eval(l[2].clone(), env.clone())?;
@@ -311,13 +328,13 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
                         for (k, v) in allocs.iter() {
                             new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
                         }
-                        new_hm.insert(a1.pr_str(false), result);
+                        new_hm.insert(a1.pr_str(false), result.clone());
                         env_set(
                             &env,
                             Sym("AllocationsInput".to_string()),
                             Hash(Rc::new(new_hm), Rc::new(Nil)),
                         )?;
-                        Ok(Nil)
+                        Ok(result.clone())
                     }
                     Sym(ref a0sym) if a0sym == "alloc" => {
                         let a1 = l[1].clone();
@@ -328,13 +345,13 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
                         for (k, v) in allocs.iter() {
                             new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
                         }
-                        new_hm.insert(a1.pr_str(false), result);
+                        new_hm.insert(a1.pr_str(false), result.clone());
                         env_set(
                             &env,
                             Sym("Allocations".to_string()),
                             Hash(Rc::new(new_hm), Rc::new(Nil)),
                         )?;
-                        Ok(Nil)
+                        Ok(result.clone())
                     }
                     //Sym(ref a0sym) if a0sym == "verify" => {
                     Sym(ref a0sym) if a0sym == "enforce" => {
@@ -503,10 +520,11 @@ pub fn setup(_ast: MalVal, env: Env) -> Result<PreparedVerifyingKey<Bls12>, MalE
     // be generated securely using a multiparty computation.
     let allocs_input = get_allocations(&env, "AllocationsInput");
     let allocs = get_allocations(&env, "Allocations");
+    let allocs_const = get_allocations(&env, "AllocationsConst");
     let enforce_allocs = get_enforce_allocs(&env);
 
     let c = LispCircuit {
-        params: vec![],
+        params: allocs_const.as_ref().clone(),
         allocs: allocs.as_ref().clone(),
         alloc_inputs: allocs_input.as_ref().clone(),
         constraints: enforce_allocs,
@@ -528,9 +546,10 @@ pub fn prove(_ast: MalVal, env: Env) -> MalRet {
     let allocs_input = get_allocations(&env, "AllocationsInput");
     let allocs = get_allocations(&env, "Allocations");
     let enforce_allocs = get_enforce_allocs(&env);
+    let allocs_const = get_allocations(&env, "AllocationsConst");
 
     let circuit = LispCircuit {
-        params: vec![],
+        params:  allocs_const.as_ref().clone(),
         allocs: allocs.as_ref().clone(),
         alloc_inputs: allocs_input.as_ref().clone(),
         constraints: enforce_allocs,

+ 1 - 1
lisp/run.sh

@@ -1,2 +1,2 @@
 #export RUST_BACKTRACE=full
-cargo run --bin lisp load new-cs.lisp
+cargo run --bin lisp load jubjub-add.lisp

+ 9 - 2
lisp/types.rs

@@ -32,7 +32,7 @@ pub struct EnforceAllocation {
 
 #[derive(Debug, Clone)]
 pub struct LispCircuit {
-    pub params: Vec<Option<Scalar>>,
+    pub params: FnvHashMap<String, MalVal>,
     pub allocs: FnvHashMap<String, MalVal>,
     pub alloc_inputs: FnvHashMap<String, MalVal>,
     pub constraints: Vec<EnforceAllocation>,
@@ -76,6 +76,7 @@ impl Circuit<bls12_381::Scalar> for LispCircuit {
             let mut right = bellman::LinearCombination::<Scalar>::zero();
             let mut output = bellman::LinearCombination::<Scalar>::zero();
             for values in alloc_value.left.iter() {
+                println!("values {:?}", values);
                 let (a, b) = values;
                 let mut val_b = CS::one();
                 if b != "cs::one" {
@@ -85,7 +86,13 @@ impl Circuit<bls12_381::Scalar> for LispCircuit {
                     left = left + (coeff, val_b);
                 } else if a == "scalar::one::neg" {
                     left = left + (coeff.neg(), val_b);
-                } 
+                } else {
+                  if let Some(value) = self.params.get(a) {
+                    if let MalVal::ZKScalar(val) = value {
+                      left = left + (*val, val_b);
+                    }
+                  }
+                }
             }
 
             for values in alloc_value.right.iter() {

+ 24 - 0
scripts/jsonrpc_client.py

@@ -0,0 +1,24 @@
+import requests
+import json
+
+
+def main():
+    url = "http://localhost:8000/"
+
+    # Example echo method
+    payload = {
+        "method": "stop",
+        #"method": "get_info",
+        "params": [],
+        "jsonrpc": "2.0",
+        "id": 0,
+    }
+    response = requests.post(url, json=payload).json()
+
+    print(response)
+    #assert response["result"] == "Hello World!"
+    assert response["jsonrpc"]
+
+if __name__ == "__main__":
+    main()
+

+ 29 - 0
scripts/reorder-logs.py

@@ -0,0 +1,29 @@
+import datetime as dt
+
+def isotime_to_ms(isotime):
+    ms = dt.timedelta(microseconds=1)
+    time = dt.time.fromisoformat(isotime)
+    ms_time = (dt.datetime.combine(dt.date.min, time) - dt.datetime.min) / ms
+    return ms_time
+
+def line_time(line):
+    return isotime_to_ms(line.split()[1])
+
+lines = []
+filenames = {"Client": "/tmp/a.txt", "Server": "/tmp/b.txt"}
+
+for label, filename in filenames.items():
+    with open(filename) as file:
+        file_lines = file.read().split("\n")
+        # Cleanup a bit
+        file_lines = [line for line in file_lines if line and line[0].isdigit()]
+        # Attach the label to each line
+        file_lines = ["%s: %s" % (label, line) for line in file_lines]
+        lines.extend(file_lines)
+
+lines.sort(key=line_time)
+for line in lines:
+    # Now remove timestamps and other info we don't need
+    line = line.split()
+    line = line[0] + " " + " ".join(line[4:])
+    print(line)

+ 111 - 0
scripts/zk/4.6.2-multi-variable-operand-polynomial.py

@@ -0,0 +1,111 @@
+from bls_py import bls12381
+from bls_py import pairing
+from bls_py import ec
+from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
+from finite_fields.modp import IntegersModP
+from finite_fields.polynomial import polynomialsOver
+import random
+
+n = bls12381.n
+
+g1 = ec.generator_Fq(bls12381)
+g2 = ec.generator_Fq2(bls12381)
+
+mod_field = IntegersModP(n)
+poly = polynomialsOver(mod_field).factory
+
+def lagrange(points):
+    result = poly([0])
+    for i, (x_i, y_i) in enumerate(points):
+        p = poly([y_i])
+        for j, (x_j, y_j) in enumerate(points):
+            if i == j:
+                continue
+            p *= poly([-x_j, 1]) / (x_i - x_j)
+        #print(poly)
+        #print(poly(1), poly(2), poly(3))
+        result += p
+    return result
+
+l_a_points = [
+    (1, 1), (2, 1), (3, 0)
+]
+l_a = lagrange(l_a_points)
+#print(l_a)
+
+l_d_points = [
+    (1, 0), (2, 0), (3, 1)
+]
+l_d = lagrange(l_d_points)
+#print(l_d)
+
+# a x b = r_1
+# a x c = r_2
+# d x c = r_3
+
+# a = 3
+# d = 2
+L = 3*l_a + 2*l_d
+#print(L)
+
+def poly_call(poly, x):
+    result = mod_field(0)
+    for degree, coeff in enumerate(poly):
+        result += coeff * (x**degree)
+    return result.n
+
+assert poly_call(L, 1) == 3
+assert poly_call(L, 2) == 3
+assert poly_call(L, 3) == 2
+
+def rand_scalar():
+    return random.randrange(1, bls12381.q)
+
+#################################
+# Verifier (trusted setup)
+#################################
+
+# samples a random value (a secret)
+toxic_scalar = rand_scalar()
+# calculate the shift
+alpha_shift = rand_scalar()
+
+l_a_s = poly_call(l_a, toxic_scalar)
+l_d_s = poly_call(l_d, toxic_scalar)
+
+enc_a_s = g1 * l_a_s
+enc_a_s_alpha = enc_a_s * alpha_shift
+
+enc_d_s = g1 * l_d_s
+enc_d_s_alpha = enc_d_s * alpha_shift
+
+# Proving key is enc_* values above
+
+# Actual values of s are toxic waste and discarded
+
+verify_key = g2 * alpha_shift
+
+#################################
+# Prover
+#################################
+
+a = 3
+d = 2
+assigned_a = enc_a_s * a
+assigned_d = enc_d_s * d
+
+assigned_a_shift = enc_a_s_alpha * a
+assigned_d_shift = enc_d_s_alpha * d
+
+operand = assigned_a + assigned_d
+operand_shift = assigned_a_shift + assigned_d_shift
+
+# proof  = operand, operand_shift
+
+#################################
+# Verifier
+#################################
+
+e = pairing.ate_pairing
+assert e(operand_shift, g2) == e(operand, verify_key)
+

+ 139 - 0
scripts/zk/4.8-example-computation.py

@@ -0,0 +1,139 @@
+# Algorithm:
+# if w { a * b } else { a + b }
+
+# Equation:
+# f(w, a, b) = w(ab) + (1 - w)(a + b) = v
+
+# w(ab) + a + b - w(ab) = v
+# w(ab - a - b) = v - a - b
+
+# Constraints:
+# 1: [1 a] [1 b] [1 m]
+# 2: [1 w] [1 m, -1 a, -1 b] = [1 v, -1 a, -1 b]
+# 3: [1 w] [1 w] [1 w]
+
+# f(1, 4, 2) = 8
+
+from bls_py import bls12381
+from bls_py import pairing
+from bls_py import ec
+from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
+from finite_fields.modp import IntegersModP
+from finite_fields.polynomial import polynomialsOver
+import random
+
+n = bls12381.n
+
+g1 = ec.generator_Fq(bls12381)
+g2 = ec.generator_Fq2(bls12381)
+
+mod_field = IntegersModP(n)
+poly = polynomialsOver(mod_field).factory
+
+def lagrange(points):
+    result = poly([0])
+    for i, (x_i, y_i) in enumerate(points):
+        p = poly([y_i])
+        for j, (x_j, y_j) in enumerate(points):
+            if i == j:
+                continue
+            p *= poly([-x_j, 1]) / (x_i - x_j)
+        #print(poly)
+        #print(poly(1), poly(2), poly(3))
+        result += p
+    return result
+
+left_variables = {
+    "a": lagrange([
+        (1, 1), (2, 0), (3, 0)
+    ]),
+    "w": lagrange([
+        (1, 0), (2, 1), (3, 1)
+    ])
+}
+
+right_variables = {
+    "m": lagrange([
+        (1, 0), (2, 1), (3, 0)
+    ]),
+    "a": lagrange([
+        (1, 0), (2, -1), (3, 0)
+    ]),
+    "b": lagrange([
+        (1, 1), (2, -1), (3, 0)
+    ]),
+    "w": lagrange([
+        (1, 0), (2, 0), (3, 1)
+    ]),
+}
+
+out_variables = {
+    "m": lagrange([
+        (1, 1), (2, 0), (3, 0)
+    ]),
+    "v": lagrange([
+        (1, 0), (2, 1), (3, 0)
+    ]),
+    "a": lagrange([
+        (1, 0), (2, -1), (3, 0)
+    ]),
+    "b": lagrange([
+        (1, 0), (2, -1), (3, 0)
+    ]),
+    "w": lagrange([
+        (1, 0), (2, 0), (3, 1)
+    ]),
+}
+
+private_inputs = {
+    "w": 1,
+    "a": 3,
+    "b": 2
+}
+
+private_inputs["m"] = private_inputs["a"] * private_inputs["b"]
+private_inputs["v"] = \
+    private_inputs["w"] * (
+        private_inputs["m"] - private_inputs["a"] - private_inputs["b"]) \
+    + private_inputs["a"] + private_inputs["b"]
+assert private_inputs["v"] == 6
+
+left_variable_poly = (
+    private_inputs["a"] * left_variables["a"]
+    + private_inputs["w"] * left_variables["w"]
+)
+right_variable_poly = (
+    private_inputs["m"] * right_variables["m"]
+    + private_inputs["a"] * right_variables["a"]
+    + private_inputs["b"] * right_variables["b"]
+    + private_inputs["w"] * right_variables["w"]
+)
+out_variable_poly = (
+    private_inputs["m"] * out_variables["m"]
+    + private_inputs["v"] * out_variables["v"]
+    + private_inputs["a"] * out_variables["a"]
+    + private_inputs["b"] * out_variables["b"]
+    + private_inputs["w"] * out_variables["w"]
+)
+
+# (x - 1)(x - 2)(x - 3)
+target_poly = poly([-1, 1]) * poly([-2, 1]) * poly([-3, 1])
+
+def poly_call(poly, x):
+    result = mod_field(0)
+    for degree, coeff in enumerate(poly):
+        result += coeff * (x**degree)
+    return result.n
+
+assert poly_call(target_poly, 1) == 0
+assert poly_call(target_poly, 2) == 0
+assert poly_call(target_poly, 3) == 0
+
+main_poly = left_variable_poly * right_variable_poly - out_variable_poly
+cofactor_poly = main_poly / target_poly
+
+assert (
+    left_variable_poly * right_variable_poly == \
+    cofactor_poly * target_poly + out_variable_poly
+)
+

+ 111 - 0
src/async_serial.rs

@@ -0,0 +1,111 @@
+use futures::prelude::*;
+
+use crate::endian;
+use crate::error::{Error, Result};
+use crate::serial::VarInt;
+
+impl VarInt {
+    pub async fn encode_async<W: AsyncWrite + Unpin>(&self, stream: &mut W) -> Result<usize> {
+        match self.0 {
+            0..=0xFC => {
+                AsyncWriteExt::write_u8(stream, self.0 as u8).await?;
+                Ok(1)
+            }
+            0xFD..=0xFFFF => {
+                AsyncWriteExt::write_u8(stream, 0xFD).await?;
+                AsyncWriteExt::write_u16(stream, self.0 as u16).await?;
+                Ok(3)
+            }
+            0x10000..=0xFFFFFFFF => {
+                AsyncWriteExt::write_u8(stream, 0xFE).await?;
+                AsyncWriteExt::write_u32(stream, self.0 as u32).await?;
+                Ok(5)
+            }
+            _ => {
+                AsyncWriteExt::write_u8(stream, 0xFF).await?;
+                AsyncWriteExt::write_u64(stream, self.0 as u64).await?;
+                Ok(9)
+            }
+        }
+    }
+
+    pub async fn decode_async<R: AsyncRead + Unpin>(stream: &mut R) -> Result<Self> {
+        let n = AsyncReadExt::read_u8(stream).await?;
+        match n {
+            0xFF => {
+                let x = AsyncReadExt::read_u64(stream).await?;
+                if x < 0x100000000 {
+                    Err(Error::NonMinimalVarInt)
+                } else {
+                    Ok(VarInt(x))
+                }
+            }
+            0xFE => {
+                let x = AsyncReadExt::read_u32(stream).await?;
+                if x < 0x10000 {
+                    Err(Error::NonMinimalVarInt)
+                } else {
+                    Ok(VarInt(x as u64))
+                }
+            }
+            0xFD => {
+                let x = AsyncReadExt::read_u16(stream).await?;
+                if x < 0xFD {
+                    Err(Error::NonMinimalVarInt)
+                } else {
+                    Ok(VarInt(x as u64))
+                }
+            }
+            n => Ok(VarInt(n as u64)),
+        }
+    }
+}
+
+macro_rules! async_encoder_fn {
+    ($name:ident, $val_type:ty, $writefn:ident) => {
+        #[inline]
+        pub async fn $name<W: AsyncWrite + Unpin>(stream: &mut W, v: $val_type) -> Result<()> {
+            stream
+                .write_all(&endian::$writefn(v))
+                .await
+                .map_err(Error::Io)
+        }
+    };
+}
+
+macro_rules! async_decoder_fn {
+    ($name:ident, $val_type:ty, $readfn:ident, $byte_len: expr) => {
+        pub async fn $name<R: AsyncRead + Unpin>(stream: &mut R) -> Result<$val_type> {
+            assert_eq!(::std::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22
+            let mut val = [0; $byte_len];
+            stream.read_exact(&mut val[..]).await.map_err(Error::Io)?;
+            Ok(endian::$readfn(&val))
+        }
+    };
+}
+
+pub struct AsyncReadExt {}
+
+impl AsyncReadExt {
+    async_decoder_fn!(read_u64, u64, slice_to_u64_le, 8);
+    async_decoder_fn!(read_u32, u32, slice_to_u32_le, 4);
+    async_decoder_fn!(read_u16, u16, slice_to_u16_le, 2);
+
+    pub async fn read_u8<R: AsyncRead + Unpin>(stream: &mut R) -> Result<u8> {
+        let mut slice = [0u8; 1];
+        stream.read_exact(&mut slice).await?;
+        Ok(slice[0])
+    }
+}
+
+pub struct AsyncWriteExt {}
+
+impl AsyncWriteExt {
+    async_encoder_fn!(write_u64, u64, u64_to_array_le);
+    async_encoder_fn!(write_u32, u32, u32_to_array_le);
+    async_encoder_fn!(write_u16, u16, u16_to_array_le);
+
+    pub async fn write_u8<W: AsyncWrite + Unpin>(stream: &mut W, v: u8) -> Result<()> {
+        stream.write_all(&[v]).await.map_err(Error::Io)
+    }
+}

+ 376 - 0
src/bin/dfi.rs

@@ -0,0 +1,376 @@
+#[macro_use]
+extern crate clap;
+use async_executor::Executor;
+use async_native_tls::TlsAcceptor;
+use async_std::sync::Mutex;
+use easy_parallel::Parallel;
+use http_types::{Request, Response, StatusCode};
+use serde_json::json;
+use smol::Async;
+use std::net::SocketAddr;
+use std::net::TcpListener;
+use std::sync::Arc;
+
+use sapvi::{net, Result};
+
+/// Listens for incoming connections and serves them.
+async fn listen(
+    executor: Arc<Executor<'_>>,
+    rpc: Arc<RpcInterface>,
+    listener: Async<TcpListener>,
+    tls: Option<TlsAcceptor>,
+) -> Result<()> {
+    // Format the full host address.
+    let host = match &tls {
+        None => format!("http://{}", listener.get_ref().local_addr()?),
+        Some(_) => format!("https://{}", listener.get_ref().local_addr()?),
+    };
+    println!("Listening on {}", host);
+
+    loop {
+        // Accept the next connection.
+        let (stream, _) = listener.accept().await?;
+
+        // Spawn a background task serving this connection.
+        let task = match &tls {
+            None => {
+                let stream = async_dup::Arc::new(stream);
+                let rpc = rpc.clone();
+                executor.spawn(async move {
+                    if let Err(err) = async_h1::accept(stream, move |req| {
+                        let rpc = rpc.clone();
+                        rpc.serve(req)
+                    })
+                    .await
+                    {
+                        println!("Connection error: {:#?}", err);
+                    }
+                })
+            }
+            Some(tls) => {
+                // In case of HTTPS, establish a secure TLS connection first.
+                match tls.accept(stream).await {
+                    Ok(stream) => {
+                        let _stream = async_dup::Arc::new(async_dup::Mutex::new(stream));
+                        executor.spawn(async move {
+                            /*if let Err(err) = async_h1::accept(stream, serve).await {
+                                println!("Connection error: {:#?}", err);
+                            }*/
+                            unimplemented!();
+                        })
+                    }
+                    Err(err) => {
+                        println!("Failed to establish secure TLS connection: {:#?}", err);
+                        continue;
+                    }
+                }
+            }
+        };
+
+        // Detach the task to let it run in the background.
+        task.detach();
+    }
+}
+
+struct RpcInterface {
+    p2p: Arc<net::P2p>,
+    started: Mutex<bool>,
+    stop_send: async_channel::Sender<()>,
+    stop_recv: async_channel::Receiver<()>,
+}
+
+impl RpcInterface {
+    fn new(p2p: Arc<net::P2p>) -> Arc<Self> {
+        let (stop_send, stop_recv) = async_channel::unbounded::<()>();
+
+        Arc::new(Self {
+            p2p,
+            started: Mutex::new(false),
+            stop_send,
+            stop_recv,
+        })
+    }
+
+    async fn serve(self: Arc<Self>, mut req: Request) -> http_types::Result<Response> {
+        println!("Serving {}", req.url());
+
+        let request = req.body_string().await?;
+
+        let mut io = jsonrpc_core::IoHandler::new();
+        io.add_sync_method("say_hello", |_| {
+            Ok(jsonrpc_core::Value::String("Hello World!".into()))
+        });
+
+        let self2 = self.clone();
+        io.add_method("get_info", move |_| {
+            let self2 = self2.clone();
+            async move {
+                Ok(json!({
+                    "started": *self2.started.lock().await,
+                    "connections": self2.p2p.connections_count().await
+                }))
+            }
+        });
+
+        let stop_send = self.stop_send.clone();
+        io.add_method("stop", move |_| {
+            let stop_send = stop_send.clone();
+            async move {
+                let _ = stop_send.send(()).await;
+                Ok(jsonrpc_core::Value::Null)
+            }
+        });
+
+        let response = io
+            .handle_request_sync(&request)
+            .ok_or(sapvi::Error::BadOperationType)?;
+
+        let mut res = Response::new(StatusCode::Ok);
+        res.insert_header("Content-Type", "text/plain");
+        res.set_body(response);
+        Ok(res)
+    }
+
+    async fn wait_for_quit(self: Arc<Self>) -> Result<()> {
+        Ok(self.stop_recv.recv().await?)
+    }
+}
+
+async fn start(executor: Arc<Executor<'_>>, options: ProgramOptions) -> Result<()> {
+    let p2p = net::P2p::new(options.network_settings);
+
+    let rpc = RpcInterface::new(p2p.clone());
+    let http = listen(
+        executor.clone(),
+        rpc.clone(),
+        Async::<TcpListener>::bind(([127, 0, 0, 1], options.rpc_port))?,
+        None,
+    );
+
+    let http_task = executor.spawn(http);
+
+    *rpc.started.lock().await = true;
+
+    p2p.clone().start(executor.clone()).await?;
+    p2p.run(executor).await?;
+
+    rpc.wait_for_quit().await?;
+
+    http_task.cancel().await;
+
+    Ok(())
+}
+
+/*
+async fn start2(executor: Arc<Executor<'_>>, options: ProgramOptions) -> Result<()> {
+    let connections = Arc::new(Mutex::new(HashMap::new()));
+
+    let stored_addrs = Arc::new(Mutex::new(Vec::new()));
+
+    let executor2 = executor.clone();
+    let stored_addrs2 = stored_addrs.clone();
+
+    let mut server_task = None;
+    if let Some(accept_addr) = options.accept_addr {
+        let accept_addr = accept_addr.clone();
+
+        let protocol = ServerProtocol::new(connections.clone(), accept_addr, stored_addrs2);
+        server_task = Some(executor.spawn(async move {
+            protocol.start(executor2).await?;
+            Ok::<(), sapvi::Error>(())
+        }));
+    }
+
+    let mut seed_protocols = Vec::with_capacity(options.seed_addrs.len());
+
+    // Normally we query this from a server
+    let accept_addr = options.accept_addr.clone();
+
+    for seed_addr in options.seed_addrs.iter() {
+        let protocol = SeedProtocol::new(seed_addr.clone(), accept_addr, stored_addrs.clone());
+        protocol.clone().start(executor.clone()).await;
+        seed_protocols.push(protocol);
+    }
+
+    debug!("Waiting for seed node queries to finish...");
+
+    for seed_protocol in seed_protocols {
+        seed_protocol.await_finish().await;
+    }
+
+    debug!("Seed nodes queried.");
+
+    let mut client_slots = vec![];
+    for i in 0..options.connection_slots {
+        debug!("Starting connection slot {}", i);
+
+        let client = Channel::new(
+            connections.clone(),
+            accept_addr.clone(),
+            stored_addrs.clone(),
+        );
+        client.clone().start(executor.clone()).await;
+        client_slots.push(client);
+    }
+
+    for remote_addr in options.manual_connects {
+        debug!("Starting connection (manual) to {}", remote_addr);
+
+        let client = Channel::new(
+            connections.clone(),
+            accept_addr.clone(),
+            stored_addrs.clone(),
+        );
+        client
+            .clone()
+            .start_manual(remote_addr, executor.clone())
+            .await;
+        client_slots.push(client);
+    }
+
+    let rpc = RpcInterface::new();
+    let http = listen(
+        executor.clone(),
+        rpc.clone(),
+        Async::<TcpListener>::bind(([127, 0, 0, 1], 8000))?,
+        None,
+    );
+
+    let http_task = executor.spawn(http);
+
+    rpc.stop_recv.recv().await?;
+
+    http_task.cancel().await;
+
+    match server_task {
+        None => {}
+        Some(server_task) => {
+            server_task.cancel().await;
+        }
+    }
+    Ok(())
+}
+*/
+
+struct ProgramOptions {
+    network_settings: net::Settings,
+    log_path: Box<std::path::PathBuf>,
+    rpc_port: u16,
+}
+
+impl ProgramOptions {
+    fn load() -> Result<ProgramOptions> {
+        let app = clap_app!(dfi =>
+            (version: "0.1.0")
+            (author: "Amir Taaki <amir@dyne.org>")
+            (about: "Dark node")
+            (@arg ACCEPT: -a --accept +takes_value "Accept address")
+            (@arg SEED_NODES: -s --seeds ... "Seed nodes")
+            (@arg CONNECTS: -c --connect ... "Manual connections")
+            (@arg CONNECT_SLOTS: --slots +takes_value "Connection slots")
+            (@arg LOG_PATH: --log +takes_value "Logfile path")
+            (@arg DISABLE_SEED: -D --disable_seed "Disable seed process")
+            (@arg RPC_PORT: -r --rpc +takes_value "RPC port")
+        )
+        .get_matches();
+
+        let accept_addr = if let Some(accept_addr) = app.value_of("ACCEPT") {
+            Some(accept_addr.parse()?)
+        } else {
+            None
+        };
+
+        let mut seed_addrs: Vec<SocketAddr> = vec![];
+        if let Some(seeds) = app.values_of("SEED_NODES") {
+            for seed in seeds {
+                seed_addrs.push(seed.parse()?);
+            }
+        }
+
+        let mut manual_connects: Vec<SocketAddr> = vec![];
+        if let Some(connections) = app.values_of("CONNECTS") {
+            for connect in connections {
+                manual_connects.push(connect.parse()?);
+            }
+        }
+
+        let connection_slots = if let Some(connection_slots) = app.value_of("CONNECT_SLOTS") {
+            connection_slots.parse()?
+        } else {
+            0
+        };
+
+        let log_path = Box::new(
+            if let Some(log_path) = app.value_of("LOG_PATH") {
+                std::path::Path::new(log_path)
+            } else {
+                std::path::Path::new("/tmp/darkfid.log")
+            }
+            .to_path_buf(),
+        );
+
+        let skip_seed_sync = if app.is_present("DISABLE_SEED") {
+            true
+        } else {
+            false
+        };
+
+        let rpc_port = if let Some(rpc_port) = app.value_of("RPC_PORT") {
+            rpc_port.parse()?
+        } else {
+            8000
+        };
+
+        Ok(ProgramOptions {
+            network_settings: net::Settings {
+                inbound: accept_addr,
+                outbound_connections: connection_slots,
+                connect_timeout_seconds: 10,
+                channel_handshake_seconds: 4,
+                channel_heartbeat_seconds: 10,
+                external_addr: accept_addr,
+                peers: manual_connects,
+                seeds: seed_addrs,
+                skip_seed_sync,
+            },
+            log_path,
+            rpc_port,
+        })
+    }
+}
+
+fn main() -> Result<()> {
+    use simplelog::*;
+
+    let options = ProgramOptions::load()?;
+
+    let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
+
+    CombinedLogger::init(vec![
+        TermLogger::new(LevelFilter::Debug, logger_config, TerminalMode::Mixed).unwrap(),
+        WriteLogger::new(
+            LevelFilter::Debug,
+            Config::default(),
+            std::fs::File::create(options.log_path.as_path()).unwrap(),
+        ),
+    ])
+    .unwrap();
+
+    let ex = Arc::new(Executor::new());
+    let (signal, shutdown) = async_channel::unbounded::<()>();
+    let ex2 = ex.clone();
+
+    let (_, result) = Parallel::new()
+        // Run four executor threads.
+        .each(0..3, |_| smol::future::block_on(ex.run(shutdown.recv())))
+        // Run the main future on the current thread.
+        .finish(|| {
+            smol::future::block_on(async move {
+                start(ex2, options).await?;
+                drop(signal);
+                Ok::<(), sapvi::Error>(())
+            })
+        });
+
+    result
+}

+ 1 - 1
src/bin/jubjub.rs

@@ -1,5 +1,5 @@
 use bls12_381::Scalar;
-use sapvi::{BlsStringConversion, Encodable, Decodable, ZKContract, ZKProof};
+use sapvi::{BlsStringConversion, Decodable, Encodable, ZKContract, ZKProof};
 use std::fs::File;
 use std::time::Instant;
 

+ 53 - 54
src/bls_extensions.rs

@@ -1,82 +1,81 @@
 use bls12_381 as bls;
-
 use std::io;
 
 use crate::error::{Error, Result};
 use crate::serial::{Decodable, Encodable, ReadExt, WriteExt};
 
 macro_rules! from_slice {
-    ($data:expr, $len:literal) => {{
-        let mut array = [0; $len];
-        // panics if not enough data
-        let bytes = &$data[..array.len()];
-        array.copy_from_slice(bytes);
-        array
-    }};
+($data:expr, $len:literal) => {{
+let mut array = [0; $len];
+// panics if not enough data
+let bytes = &$data[..array.len()];
+array.copy_from_slice(bytes);
+array
+}};
 }
 
 pub trait BlsStringConversion {
-    fn to_string(&self) -> String;
-    fn from_string(object: &str) -> Self;
+fn to_string(&self) -> String;
+fn from_string(object: &str) -> Self;
 }
 
 impl BlsStringConversion for bls::Scalar {
-    fn to_string(&self) -> String {
-        let mut bytes = self.to_bytes();
-        bytes.reverse();
-        hex::encode(bytes)
-    }
-    fn from_string(object: &str) -> Self {
-        let mut bytes = from_slice!(&hex::decode(object).unwrap(), 32);
-        bytes.reverse();
-        bls::Scalar::from_bytes(&bytes).unwrap()
-    }
+fn to_string(&self) -> String {
+let mut bytes = self.to_bytes();
+bytes.reverse();
+hex::encode(bytes)
+}
+fn from_string(object: &str) -> Self {
+let mut bytes = from_slice!(&hex::decode(object).unwrap(), 32);
+bytes.reverse();
+bls::Scalar::from_bytes(&bytes).unwrap()
+}
 }
 
 macro_rules! serialization_bls {
-    ($type:ty, $to_x:ident, $from_x:ident, $size:literal) => {
-        impl Encodable for $type {
-            fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-                let data = self.$to_x();
-                assert_eq!(data.len(), $size);
-                s.write_slice(&data)?;
-                Ok(data.len())
-            }
-        }
+($type:ty, $to_x:ident, $from_x:ident, $size:literal) => {
+impl Encodable for $type {
+fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+let data = self.$to_x();
+assert_eq!(data.len(), $size);
+s.write_slice(&data)?;
+Ok(data.len())
+}
+}
 
-        impl Decodable for $type {
-            fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-                let mut slice = [0u8; $size];
-                d.read_slice(&mut slice)?;
-                let result = Self::$from_x(&slice);
-                if bool::from(result.is_none()) {
-                    return Err(Error::ParseFailed("$t conversion from slice failed"));
-                }
-                Ok(result.unwrap())
-            }
-        }
-    };
+impl Decodable for $type {
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+let mut slice = [0u8; $size];
+d.read_slice(&mut slice)?;
+let result = Self::$from_x(&slice);
+if bool::from(result.is_none()) {
+return Err(Error::ParseFailed("$t conversion from slice failed"));
+}
+Ok(result.unwrap())
+}
+}
+};
 }
 
 serialization_bls!(bls::Scalar, to_bytes, from_bytes, 32);
 
 macro_rules! make_serialize_deserialize_test {
-    ($name:ident, $type:ty, $default_func:ident) => {
-        #[test]
-        fn $name() {
-            let point = <$type>::$default_func();
+($name:ident, $type:ty, $default_func:ident) => {
+#[test]
+fn $name() {
+let point = <$type>::$default_func();
 
-            let mut data: Vec<u8> = vec![];
-            let result = point.encode(&mut data);
-            assert!(result.is_ok());
+let mut data: Vec<u8> = vec![];
+let result = point.encode(&mut data);
+assert!(result.is_ok());
 
-            let point2 = <$type>::decode(&data[..]);
-            assert!(point2.is_ok());
-            let point2 = point2.unwrap();
+let point2 = <$type>::decode(&data[..]);
+assert!(point2.is_ok());
+let point2 = point2.unwrap();
 
-            assert_eq!(point, point2);
-        }
-    };
+assert_eq!(point, point2);
+}
+};
 }
 
 make_serialize_deserialize_test!(serial_test_scalar, bls::Scalar, zero);

+ 52 - 0
src/error.rs

@@ -1,5 +1,6 @@
 use std::fmt;
 
+use crate::net::error::NetError;
 use crate::vm::ZKVMError;
 
 pub type Result<T> = std::result::Result<T, Error>;
@@ -20,6 +21,7 @@ pub enum Error {
     NonMinimalVarInt,
     /// Parsing error
     ParseFailed(&'static str),
+    ParseIntError,
     AsyncChannelError,
     MalformedPacket,
     AddrParseError,
@@ -31,6 +33,12 @@ pub enum Error {
     VMError(ZKVMError),
     BadContract,
     Groth16Error(bellman::SynthesisError),
+    OperationFailed,
+    ConnectFailed,
+    ConnectTimeout,
+    ChannelStopped,
+    ChannelTimeout,
+    ServiceStopped,
 }
 
 impl std::error::Error for Error {}
@@ -54,6 +62,7 @@ impl fmt::Display for Error {
             Error::Io(ref err) => fmt::Display::fmt(err, f),
             Error::NonMinimalVarInt => f.write_str("non-minimal varint"),
             Error::ParseFailed(ref err) => write!(f, "parse failed: {}", err),
+            Error::ParseIntError => f.write_str("Parse int error"),
             Error::AsyncChannelError => f.write_str("async_channel error"),
             Error::MalformedPacket => f.write_str("Malformed packet"),
             Error::AddrParseError => f.write_str("Unable to parse address"),
@@ -65,6 +74,12 @@ impl fmt::Display for Error {
             Error::VMError(_) => f.write_str("VM error"),
             Error::BadContract => f.write_str("Contract is poorly defined"),
             Error::Groth16Error(ref err) => write!(f, "groth16 error: {}", err),
+            Error::OperationFailed => f.write_str("Operation failed"),
+            Error::ConnectFailed => f.write_str("Connection failed"),
+            Error::ConnectTimeout => f.write_str("Connection timed out"),
+            Error::ChannelStopped => f.write_str("Channel stopped"),
+            Error::ChannelTimeout => f.write_str("Channel timed out"),
+            Error::ServiceStopped => f.write_str("Service stopped"),
         }
     }
 }
@@ -86,3 +101,40 @@ impl From<bellman::SynthesisError> for Error {
         Error::Groth16Error(err)
     }
 }
+
+impl<T> From<async_channel::SendError<T>> for Error {
+    fn from(_err: async_channel::SendError<T>) -> Error {
+        Error::AsyncChannelError
+    }
+}
+
+impl From<async_channel::RecvError> for Error {
+    fn from(_err: async_channel::RecvError) -> Error {
+        Error::AsyncChannelError
+    }
+}
+
+impl From<std::net::AddrParseError> for Error {
+    fn from(_err: std::net::AddrParseError) -> Error {
+        Error::AddrParseError
+    }
+}
+
+impl From<std::num::ParseIntError> for Error {
+    fn from(_err: std::num::ParseIntError) -> Error {
+        Error::ParseIntError
+    }
+}
+
+impl From<NetError> for Error {
+    fn from(err: NetError) -> Error {
+        match err {
+            NetError::OperationFailed => Error::OperationFailed,
+            NetError::ConnectFailed => Error::ConnectFailed,
+            NetError::ConnectTimeout => Error::ConnectTimeout,
+            NetError::ChannelStopped => Error::ChannelStopped,
+            NetError::ChannelTimeout => Error::ChannelTimeout,
+            NetError::ServiceStopped => Error::ServiceStopped,
+        }
+    }
+}

+ 5 - 0
src/lib.rs

@@ -2,15 +2,20 @@ use bellman::groth16;
 use bls12_381::{Bls12, Scalar};
 use std::collections::{HashMap, HashSet};
 
+pub mod async_serial;
 pub mod bls_extensions;
 pub mod endian;
 pub mod error;
+pub mod net;
 pub mod serial;
+pub mod system;
+pub mod utility;
 pub mod vm;
 pub mod vm_serial;
 
 pub use crate::bls_extensions::BlsStringConversion;
 pub use crate::error::{Error, Result};
+pub use crate::net::p2p::P2p;
 pub use crate::serial::{Decodable, Encodable};
 pub use crate::vm::{
     AllocType, ConstraintInstruction, CryptoOperation, VariableIndex, VariableRef, ZKVMCircuit,

+ 110 - 0
src/net/acceptor.rs

@@ -0,0 +1,110 @@
+use log::*;
+use smol::{Async, Executor};
+use std::net::{SocketAddr, TcpListener};
+use std::sync::Arc;
+
+use crate::net::error::{NetError, NetResult};
+use crate::net::{Channel, ChannelPtr, SettingsPtr};
+use crate::system::{StoppableTask, StoppableTaskPtr, Subscriber, SubscriberPtr, Subscription};
+
+pub type AcceptorPtr = Arc<Acceptor>;
+
+pub struct Acceptor {
+    channel_subscriber: SubscriberPtr<NetResult<ChannelPtr>>,
+    task: StoppableTaskPtr,
+    settings: SettingsPtr,
+}
+
+impl Acceptor {
+    pub fn new(settings: SettingsPtr) -> Arc<Self> {
+        Arc::new(Self {
+            channel_subscriber: Subscriber::new(),
+            task: StoppableTask::new(),
+            settings,
+        })
+    }
+
+    pub fn start(
+        self: Arc<Self>,
+        accept_addr: SocketAddr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        let listener = Self::setup(accept_addr)?;
+
+        // Start detached task and return instantly
+        self.accept(listener, executor);
+
+        Ok(())
+    }
+
+    pub async fn stop(&self) {
+        // Send stop signal
+        self.task.stop().await;
+    }
+
+    pub async fn subscribe(self: Arc<Self>) -> Subscription<NetResult<ChannelPtr>> {
+        self.channel_subscriber.clone().subscribe().await
+    }
+
+    fn setup(accept_addr: SocketAddr) -> NetResult<Async<TcpListener>> {
+        let listener = match Async::<TcpListener>::bind(accept_addr) {
+            Ok(l) => l,
+            Err(err) => {
+                error!("Bind listener failed: {}", err);
+                return Err(NetError::OperationFailed);
+            }
+        };
+        let local_addr = match listener.get_ref().local_addr() {
+            Ok(a) => a,
+            Err(err) => {
+                error!("Failed to get local address: {}", err);
+                return Err(NetError::OperationFailed);
+            }
+        };
+        info!("Listening on {}", local_addr);
+
+        Ok(listener)
+    }
+
+    fn accept(self: Arc<Self>, listener: Async<TcpListener>, executor: Arc<Executor<'_>>) {
+        self.task.clone().start(
+            self.clone().run_accept_loop(listener),
+            |result| self.handle_stop(result),
+            NetError::ServiceStopped,
+            executor,
+        );
+    }
+
+    async fn run_accept_loop(self: Arc<Self>, listener: Async<TcpListener>) -> NetResult<()> {
+        loop {
+            let channel = self.tick_accept(&listener).await?;
+            let channel_result = Arc::new(Ok(channel));
+            self.channel_subscriber.notify(channel_result).await;
+        }
+    }
+
+    async fn handle_stop(self: Arc<Self>, result: NetResult<()>) {
+        match result {
+            Ok(()) => panic!("Acceptor task should never complete without error status"),
+            Err(err) => {
+                // Send this error to all channel subscribers
+                let result = Arc::new(Err(err));
+                self.channel_subscriber.notify(result).await;
+            }
+        }
+    }
+
+    async fn tick_accept(&self, listener: &Async<TcpListener>) -> NetResult<ChannelPtr> {
+        let (stream, peer_addr) = match listener.accept().await {
+            Ok((s, a)) => (s, a),
+            Err(err) => {
+                error!("Error listening for connections: {}", err);
+                return Err(NetError::ServiceStopped);
+            }
+        };
+        info!("Accepted client: {}", peer_addr);
+
+        let channel = Channel::new(stream, peer_addr, self.settings.clone());
+        Ok(channel)
+    }
+}

+ 189 - 0
src/net/channel.rs

@@ -0,0 +1,189 @@
+use async_std::sync::Mutex;
+use futures::io::{ReadHalf, WriteHalf};
+use futures::AsyncReadExt;
+use log::*;
+use smol::{Async, Executor};
+
+use std::net::{SocketAddr, TcpStream};
+
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::Arc;
+
+use crate::error;
+use crate::net::error::{NetError, NetResult};
+use crate::net::message_subscriber::{
+    MessageSubscriber, MessageSubscriberPtr, MessageSubscription,
+};
+use crate::net::messages;
+use crate::net::settings::SettingsPtr;
+use crate::system::{StoppableTask, StoppableTaskPtr, Subscriber, SubscriberPtr, Subscription};
+
+pub type ChannelPtr = Arc<Channel>;
+
+pub struct Channel {
+    reader: Mutex<ReadHalf<Async<TcpStream>>>,
+    writer: Mutex<WriteHalf<Async<TcpStream>>>,
+    address: SocketAddr,
+    message_subscriber: MessageSubscriberPtr,
+    stop_subscriber: SubscriberPtr<NetError>,
+    receive_task: StoppableTaskPtr,
+    stopped: AtomicBool,
+    settings: SettingsPtr,
+}
+
+impl Channel {
+    pub fn new(stream: Async<TcpStream>, address: SocketAddr, settings: SettingsPtr) -> Arc<Self> {
+        let (reader, writer) = stream.split();
+        let reader = Mutex::new(reader);
+        let writer = Mutex::new(writer);
+        Arc::new(Self {
+            reader,
+            writer,
+            address,
+            message_subscriber: MessageSubscriber::new(),
+            stop_subscriber: Subscriber::new(),
+            receive_task: StoppableTask::new(),
+            stopped: AtomicBool::new(false),
+            settings,
+        })
+    }
+
+    pub fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
+        debug!(target: "net", "Channel::start() [START, address={}]", self.address());
+        let self2 = self.clone();
+        self.receive_task.clone().start(
+            self.clone().receive_loop(),
+            // Ignore stop handler
+            |result| self2.handle_stop(result),
+            NetError::ServiceStopped,
+            executor,
+        );
+        debug!(target: "net", "Channel::start() [END, address={}]", self.address());
+    }
+
+    pub async fn stop(&self) {
+        debug!(target: "net", "Channel::stop() [START, address={}]", self.address());
+        assert_eq!(self.stopped.load(Ordering::Relaxed), false);
+        self.stopped.store(false, Ordering::Relaxed);
+        let stop_err = Arc::new(NetError::ChannelStopped);
+        self.stop_subscriber.notify(stop_err).await;
+        self.receive_task.stop().await;
+        debug!(target: "net", "Channel::stop() [END, address={}]", self.address());
+    }
+
+    pub async fn subscribe_stop(&self) -> Subscription<NetError> {
+        debug!(target: "net",
+            "Channel::subscribe_stop() [START, address={}]",
+            self.address()
+        );
+        // TODO: this should check the stopped status
+        // Call to receive should return ChannelStopped on newly created sub
+        let sub = self.stop_subscriber.clone().subscribe().await;
+        debug!(target: "net",
+            "Channel::subscribe_stop() [END, address={}]",
+            self.address()
+        );
+        sub
+    }
+
+    pub async fn send(self: Arc<Self>, message: messages::Message) -> NetResult<()> {
+        let packet_type = message.packet_type();
+        debug!(target: "net",
+            "Channel::send() [START, pkt_type={:?}, address={}]",
+            packet_type,
+            self.address()
+        );
+        if self.stopped.load(Ordering::Relaxed) {
+            return Err(NetError::ChannelStopped);
+        }
+
+        // Catch failure and stop channel, return a net error
+        let result = match messages::send_message(&mut *self.writer.lock().await, message).await {
+            Ok(()) => Ok(()),
+            Err(err) => {
+                error!("Channel send error for [{}]: {}", self.address(), err);
+                self.stop().await;
+                Err(NetError::ChannelStopped)
+            }
+        };
+        debug!(target: "net",
+            "Channel::send() [END, pkt_type={:?}, address={}]",
+            packet_type,
+            self.address()
+        );
+        result
+    }
+
+    pub async fn subscribe_msg(
+        self: Arc<Self>,
+        packet_type: messages::PacketType,
+    ) -> MessageSubscription {
+        debug!(target: "net",
+            "Channel::subscribe_msg() [START, pkt_type={:?}, address={}]",
+            packet_type,
+            self.address()
+        );
+        let sub = self.message_subscriber.clone().subscribe(packet_type).await;
+        debug!(target: "net",
+            "Channel::subscribe_msg() [END, pkt_type={:?}, address={}]",
+            packet_type,
+            self.address()
+        );
+        sub
+    }
+
+    pub fn address(&self) -> SocketAddr {
+        self.address
+    }
+
+    fn is_eof_error(err: &error::Error) -> bool {
+        match err {
+            error::Error::Io(io_err) => io_err.kind() == std::io::ErrorKind::UnexpectedEof,
+            _ => false,
+        }
+    }
+
+    async fn receive_loop(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net",
+            "Channel::receive_loop() [START, address={}]",
+            self.address()
+        );
+        let reader = &mut *self.reader.lock().await;
+
+        loop {
+            let message_result = messages::receive_message(reader).await;
+            let message = match message_result {
+                Ok(message) => Arc::new(message),
+                Err(err) => {
+                    if Self::is_eof_error(&err) {
+                        info!("Channel {} disconnected", self.address());
+                    } else {
+                        error!("Read error on channel: {}", err);
+                    }
+                    debug!(target: "net",
+                        "Channel::receive_loop() stopping channel {}",
+                        self.address()
+                    );
+                    self.stop().await;
+                    return Err(NetError::ChannelStopped);
+                }
+            };
+
+            // Send result to our subscribers
+            self.message_subscriber.notify(Ok(message)).await;
+        }
+    }
+
+    async fn handle_stop(self: Arc<Self>, result: NetResult<()>) {
+        debug!(target: "net", "Channel::handle_stop() [START, address={}]", self.address());
+        match result {
+            Ok(()) => panic!("Channel task should never complete without error status"),
+            Err(err) => {
+                // Send this error to all channel subscribers
+                let result = Err(err);
+                self.message_subscriber.notify(result).await;
+            }
+        }
+        debug!(target: "net", "Channel::handle_stop() [END, address={}]", self.address());
+    }
+}

+ 29 - 0
src/net/connector.rs

@@ -0,0 +1,29 @@
+use futures::FutureExt;
+use smol::Async;
+use std::net::{SocketAddr, TcpStream};
+
+use crate::net::error::{NetError, NetResult};
+use crate::net::utility::sleep;
+use crate::net::{Channel, ChannelPtr, SettingsPtr};
+
+pub struct Connector {
+    settings: SettingsPtr,
+}
+
+impl Connector {
+    pub fn new(settings: SettingsPtr) -> Self {
+        Self { settings }
+    }
+
+    pub async fn connect(&self, hostaddr: SocketAddr) -> NetResult<ChannelPtr> {
+        futures::select! {
+            stream_result = Async::<TcpStream>::connect(hostaddr).fuse() => {
+                match stream_result {
+                    Ok(stream) => Ok(Channel::new(stream, hostaddr, self.settings.clone())),
+                    Err(_) => Err(NetError::ConnectFailed)
+                }
+            }
+            _ = sleep(self.settings.connect_timeout_seconds).fuse() => Err(NetError::ConnectTimeout)
+        }
+    }
+}

+ 28 - 0
src/net/error.rs

@@ -0,0 +1,28 @@
+use std::fmt;
+
+pub type NetResult<T> = std::result::Result<T, NetError>;
+
+#[derive(Debug, Copy, Clone)]
+pub enum NetError {
+    OperationFailed,
+    ConnectFailed,
+    ConnectTimeout,
+    ChannelStopped,
+    ChannelTimeout,
+    ServiceStopped,
+}
+
+impl std::error::Error for NetError {}
+
+impl fmt::Display for NetError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
+        match *self {
+            NetError::OperationFailed => f.write_str("Operation failed"),
+            NetError::ConnectFailed => f.write_str("Connection failed"),
+            NetError::ConnectTimeout => f.write_str("Connection timed out"),
+            NetError::ChannelStopped => f.write_str("Channel stopped"),
+            NetError::ChannelTimeout => f.write_str("Channel timed out"),
+            NetError::ServiceStopped => f.write_str("Service stopped"),
+        }
+    }
+}

+ 38 - 0
src/net/hosts.rs

@@ -0,0 +1,38 @@
+use async_std::sync::Mutex;
+use rand::seq::SliceRandom;
+use std::net::SocketAddr;
+use std::sync::Arc;
+
+use crate::net::SettingsPtr;
+
+pub type HostsPtr = Arc<Hosts>;
+
+pub struct Hosts {
+    addrs: Mutex<Vec<SocketAddr>>,
+    settings: SettingsPtr,
+}
+
+impl Hosts {
+    pub fn new(settings: SettingsPtr) -> Arc<Self> {
+        Arc::new(Self {
+            addrs: Mutex::new(Vec::new()),
+            settings,
+        })
+    }
+
+    pub async fn store(&self, addrs: Vec<SocketAddr>) {
+        self.addrs.lock().await.extend(addrs)
+    }
+
+    pub async fn load_single(&self) -> Option<SocketAddr> {
+        self.addrs
+            .lock()
+            .await
+            .choose(&mut rand::thread_rng())
+            .cloned()
+    }
+
+    pub async fn load_all(&self) -> Vec<SocketAddr> {
+        self.addrs.lock().await.clone()
+    }
+}

+ 131 - 0
src/net/message_subscriber.rs

@@ -0,0 +1,131 @@
+use async_std::sync::Mutex;
+use rand::Rng;
+use std::collections::HashMap;
+use std::sync::Arc;
+
+use crate::net::error::NetResult;
+use crate::net::messages::{Message, PacketType};
+
+pub type MessageSubscriberPtr = Arc<MessageSubscriber>;
+
+pub type MessageResult = NetResult<Arc<Message>>;
+pub type MessageSubscriptionID = u64;
+
+macro_rules! receive_message {
+    ($sub:expr, $message_type:path) => {{
+        let wrapped_message = owning_ref::OwningRef::new($sub.receive().await?);
+
+        wrapped_message.map(|msg| match msg {
+            $message_type(msg_detail) => msg_detail,
+            _ => {
+                panic!("Filter for receive sub invalid!");
+            }
+        })
+    }};
+}
+
+pub struct MessageSubscription {
+    id: MessageSubscriptionID,
+    filter: PacketType,
+    recv_queue: async_channel::Receiver<MessageResult>,
+    parent: Arc<MessageSubscriber>,
+}
+
+impl MessageSubscription {
+    fn is_relevant_message(&self, message_result: &MessageResult) -> bool {
+        match message_result {
+            Ok(message) => {
+                let packet_type = message.packet_type();
+
+                // Apply the filter
+                packet_type == self.filter
+            }
+            Err(_) => {
+                // Propagate all errors
+                true
+            }
+        }
+    }
+
+    pub async fn receive(&self) -> MessageResult {
+        loop {
+            let message_result = self.recv_queue.recv().await;
+
+            match message_result {
+                Ok(message_result) => {
+                    if self.clone().is_relevant_message(&message_result) {
+                        return message_result;
+                    }
+                }
+                Err(err) => {
+                    panic!("MessageSubscription::receive() recv_queue failed! {}", err);
+                }
+            }
+        }
+    }
+
+    // Must be called manually since async Drop is not possible in Rust
+    pub async fn unsubscribe(&self) {
+        self.parent.clone().unsubscribe(self.id).await
+    }
+}
+
+pub struct MessageSubscriber {
+    subs: Mutex<HashMap<MessageSubscriptionID, async_channel::Sender<MessageResult>>>,
+}
+
+impl MessageSubscriber {
+    pub fn new() -> Arc<Self> {
+        Arc::new(Self {
+            subs: Mutex::new(HashMap::new()),
+        })
+    }
+
+    pub fn random_id() -> MessageSubscriptionID {
+        let mut rng = rand::thread_rng();
+        rng.gen()
+    }
+
+    pub async fn subscribe(self: Arc<Self>, packet_type: PacketType) -> MessageSubscription {
+        let (sender, recvr) = async_channel::unbounded();
+
+        let sub_id = Self::random_id();
+
+        self.subs.lock().await.insert(sub_id, sender);
+
+        MessageSubscription {
+            id: sub_id,
+            filter: packet_type,
+            recv_queue: recvr,
+            parent: self.clone(),
+        }
+    }
+
+    async fn unsubscribe(self: Arc<Self>, sub_id: MessageSubscriptionID) {
+        self.subs.lock().await.remove(&sub_id);
+    }
+
+    pub async fn notify(&self, message_result: NetResult<Arc<Message>>) {
+        let mut garbage_ids = Vec::new();
+
+        for (sub_id, sub) in &*self.subs.lock().await {
+            match sub.send(message_result.clone()).await {
+                Ok(()) => {}
+                Err(_err) => {
+                    // Automatically clean out closed channels
+                    garbage_ids.push(*sub_id);
+                    //panic!("Error returned sending message in notify() call! {}", err);
+                }
+            }
+        }
+
+        self.collect_garbage(garbage_ids).await;
+    }
+
+    async fn collect_garbage(&self, ids: Vec<MessageSubscriptionID>) {
+        let mut subs = self.subs.lock().await;
+        for id in &ids {
+            subs.remove(id);
+        }
+    }
+}

+ 468 - 0
src/net/messages.rs

@@ -0,0 +1,468 @@
+use futures::prelude::*;
+use log::*;
+use num_enum::{IntoPrimitive, TryFromPrimitive};
+use smol::Executor;
+use smol::Timer;
+use std::convert::TryFrom;
+use std::io;
+use std::io::Cursor;
+use std::net::SocketAddr;
+use std::sync::Arc;
+use std::time::Duration;
+
+use crate::async_serial::{AsyncReadExt, AsyncWriteExt};
+use crate::error::{Error, Result};
+pub use crate::net::AsyncTcpStream;
+use crate::serial::{serialize, Decodable, Encodable, VarInt};
+
+const MAGIC_BYTES: [u8; 4] = [0xd9, 0xef, 0xb6, 0x7d];
+
+pub type Ciphertext = Vec<u8>;
+pub type CiphertextHash = [u8; 32];
+
+// Packets and Message because Rust doesn't allow value
+// aliasing from ADL type enums (which Message uses).
+#[derive(IntoPrimitive, TryFromPrimitive, Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[repr(u8)]
+pub enum PacketType {
+    Ping = 1,
+    Pong = 2,
+    GetAddrs = 3,
+    Addrs = 4,
+    Inv = 5,
+    GetSlabs = 6,
+    Slab = 7,
+    Version = 8,
+    Verack = 9,
+}
+
+pub enum Message {
+    Ping(PingMessage),
+    Pong(PongMessage),
+    GetAddrs(GetAddrsMessage),
+    Addrs(AddrsMessage),
+    Inv(InvMessage),
+    GetSlabs(GetSlabsMessage),
+    Slab(SlabMessage),
+    Version(VersionMessage),
+    Verack(VerackMessage),
+}
+
+pub struct PingMessage {
+    pub nonce: u32,
+}
+
+pub struct PongMessage {
+    pub nonce: u32,
+}
+
+pub struct GetAddrsMessage {}
+
+pub struct GetSlabsMessage {
+    pub slabs_hash: Vec<[u8; 32]>,
+}
+
+#[derive(Clone)]
+pub struct SlabMessage {
+    pub nonce: [u8; 12],
+    pub ciphertext: Ciphertext,
+}
+
+pub struct InvMessage {
+    pub slabs_hash: Vec<[u8; 32]>,
+}
+
+pub struct AddrsMessage {
+    pub addrs: Vec<SocketAddr>,
+}
+
+pub struct VersionMessage {}
+
+pub struct VerackMessage {}
+
+impl Encodable for PingMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.nonce.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for PingMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            nonce: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for PongMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.nonce.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for PongMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            nonce: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for GetSlabsMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.slabs_hash.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for GetSlabsMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            slabs_hash: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for SlabMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.nonce.encode(&mut s)?;
+        len += self.ciphertext.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for SlabMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            nonce: Decodable::decode(&mut d)?,
+            ciphertext: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for InvMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.slabs_hash.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for InvMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            slabs_hash: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for GetAddrsMessage {
+    fn encode<S: io::Write>(&self, mut _s: S) -> Result<usize> {
+        let len = 0;
+        Ok(len)
+    }
+}
+
+impl Decodable for GetAddrsMessage {
+    fn decode<D: io::Read>(mut _d: D) -> Result<Self> {
+        Ok(Self {})
+    }
+}
+
+impl Encodable for AddrsMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.addrs.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for AddrsMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            addrs: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for VersionMessage {
+    fn encode<S: io::Write>(&self, _s: S) -> Result<usize> {
+        Ok(0)
+    }
+}
+
+impl Decodable for VersionMessage {
+    fn decode<D: io::Read>(_d: D) -> Result<Self> {
+        Ok(Self {})
+    }
+}
+
+impl Encodable for VerackMessage {
+    fn encode<S: io::Write>(&self, _s: S) -> Result<usize> {
+        Ok(0)
+    }
+}
+
+impl Decodable for VerackMessage {
+    fn decode<D: io::Read>(_d: D) -> Result<Self> {
+        Ok(Self {})
+    }
+}
+
+impl Message {
+    pub fn packet_type(&self) -> PacketType {
+        match self {
+            Message::Ping(_message) => PacketType::Ping,
+            Message::Pong(_message) => PacketType::Pong,
+            Message::GetAddrs(_message) => PacketType::GetAddrs,
+            Message::Addrs(_message) => PacketType::Addrs,
+            Message::Inv(_message) => PacketType::Inv,
+            Message::GetSlabs(_message) => PacketType::GetSlabs,
+            Message::Slab(_message) => PacketType::Slab,
+            Message::Version(_message) => PacketType::Version,
+            Message::Verack(_message) => PacketType::Verack,
+        }
+    }
+
+    pub fn pack(&self) -> Result<Packet> {
+        match self {
+            Message::Ping(message) => {
+                let mut payload = Vec::new();
+                message.encode(&mut payload)?;
+                Ok(Packet {
+                    command: PacketType::Ping,
+                    payload,
+                })
+            }
+            Message::Pong(message) => {
+                let mut payload = Vec::new();
+                message.encode(&mut payload)?;
+                Ok(Packet {
+                    command: PacketType::Pong,
+                    payload,
+                })
+            }
+            Message::GetAddrs(message) => {
+                let mut payload = Vec::new();
+                message.encode(&mut payload)?;
+                Ok(Packet {
+                    command: PacketType::GetAddrs,
+                    payload,
+                })
+            }
+            Message::Addrs(message) => {
+                let mut payload = Vec::new();
+                message.encode(Cursor::new(&mut payload))?;
+                Ok(Packet {
+                    command: PacketType::Addrs,
+                    payload,
+                })
+            }
+            Message::Inv(message) => {
+                let payload = serialize(message);
+                Ok(Packet {
+                    command: PacketType::Inv,
+                    payload,
+                })
+            }
+            Message::GetSlabs(message) => {
+                let payload = serialize(message);
+                Ok(Packet {
+                    command: PacketType::GetSlabs,
+                    payload,
+                })
+            }
+            Message::Slab(message) => {
+                let payload = serialize(message);
+                Ok(Packet {
+                    command: PacketType::Slab,
+                    payload,
+                })
+            }
+            Message::Version(message) => {
+                let payload = serialize(message);
+                Ok(Packet {
+                    command: PacketType::Version,
+                    payload,
+                })
+            }
+            Message::Verack(message) => {
+                let payload = serialize(message);
+                Ok(Packet {
+                    command: PacketType::Verack,
+                    payload,
+                })
+            }
+        }
+    }
+
+    pub fn unpack(packet: Packet) -> Result<Self> {
+        let cursor = Cursor::new(packet.payload.clone());
+        match packet.command {
+            PacketType::Ping => Ok(Self::Ping(PingMessage::decode(cursor)?)),
+            PacketType::Pong => Ok(Self::Pong(PongMessage::decode(cursor)?)),
+            PacketType::GetAddrs => Ok(Self::GetAddrs(GetAddrsMessage::decode(cursor)?)),
+            PacketType::Addrs => Ok(Self::Addrs(AddrsMessage::decode(cursor)?)),
+            PacketType::Inv => Ok(Self::Inv(InvMessage::decode(cursor)?)),
+            PacketType::GetSlabs => Ok(Self::GetSlabs(GetSlabsMessage::decode(cursor)?)),
+            PacketType::Slab => Ok(Self::Slab(SlabMessage::decode(cursor)?)),
+            PacketType::Version => Ok(Self::Version(VersionMessage::decode(cursor)?)),
+            PacketType::Verack => Ok(Self::Verack(VerackMessage::decode(cursor)?)),
+        }
+    }
+
+    pub fn name(&self) -> &'static str {
+        match self {
+            Message::Ping(_) => "Ping",
+            Message::Pong(_) => "Pong",
+            Message::GetAddrs(_) => "GetAddrs",
+            Message::Addrs(_) => "Addrs",
+            Message::Inv(_) => "Inv",
+            Message::GetSlabs(_) => "GetSlabs",
+            Message::Slab(_) => "Slab",
+            Message::Version(_) => "Version",
+            Message::Verack(_) => "Verack",
+        }
+    }
+}
+
+// Packets are the base type read from the network
+// These are converted to messages and passed to event loop
+pub struct Packet {
+    pub command: PacketType,
+    pub payload: Vec<u8>,
+}
+
+pub async fn read_packet<R: AsyncRead + Unpin>(stream: &mut R) -> Result<Packet> {
+    // Packets have a 4 byte header of magic digits
+    // This is used for network debugging
+    let mut magic = [0u8; 4];
+    debug!(target: "net", "reading magic...");
+    stream.read_exact(&mut magic).await?;
+    debug!(target: "net", "read magic {:?}", magic);
+    if magic != MAGIC_BYTES {
+        return Err(Error::MalformedPacket);
+    }
+
+    // The type of the message
+    let command = AsyncReadExt::read_u8(stream).await?;
+    debug!(target: "net", "read command: {}", command);
+    let command = PacketType::try_from(command).map_err(|_| Error::MalformedPacket)?;
+
+    let payload_len = VarInt::decode_async(stream).await?.0 as usize;
+
+    // The message-dependent data (see message types)
+    let mut payload = vec![0u8; payload_len];
+    if payload_len > 0 {
+        stream.read_exact(&mut payload).await?;
+    }
+    debug!(target: "net", "read payload {} bytes", payload_len);
+
+    Ok(Packet { command, payload })
+}
+
+pub async fn send_packet<W: AsyncWrite + Unpin>(stream: &mut W, packet: Packet) -> Result<()> {
+    debug!(target: "net", "sending magic...");
+    stream.write_all(&MAGIC_BYTES).await?;
+    debug!(target: "net", "sent magic...");
+
+    AsyncWriteExt::write_u8(stream, packet.command as u8).await?;
+    debug!(target: "net", "sent command: {}", packet.command as u8);
+
+    assert_eq!(std::mem::size_of::<usize>(), std::mem::size_of::<u64>());
+    VarInt(packet.payload.len() as u64)
+        .encode_async(stream)
+        .await?;
+
+    if packet.payload.len() > 0 {
+        stream.write_all(&packet.payload).await?;
+    }
+    debug!(target: "net", "sent payload {} bytes", packet.payload.len() as u64);
+
+    Ok(())
+}
+
+pub async fn receive_message<R: AsyncRead + Unpin>(stream: &mut R) -> Result<Message> {
+    let packet = read_packet(stream).await?;
+    debug!(target: "net", "unpacking packet: {:?}", packet.command);
+    let message = Message::unpack(packet)?;
+    debug!(target: "net", "received Message::{}", message.name());
+    Ok(message)
+}
+
+pub async fn send_message<W: AsyncWrite + Unpin>(stream: &mut W, message: Message) -> Result<()> {
+    debug!(target: "net", "sending Message::{}", message.name());
+    let packet = message.pack()?;
+    send_packet(stream, packet).await
+}
+
+pub async fn sleep(seconds: u64) {
+    Timer::after(Duration::from_secs(seconds)).await;
+}
+
+// Used for ping pong loop timer
+pub struct InactivityTimer {
+    reset_sender: async_channel::Sender<()>,
+    timeout_receiver: async_channel::Receiver<()>,
+    task: smol::Task<()>,
+}
+
+impl InactivityTimer {
+    pub fn new(executor: Arc<Executor<'_>>) -> Self {
+        let (reset_sender, reset_receiver) = async_channel::bounded::<()>(1);
+        let (timeout_sender, timeout_receiver) = async_channel::bounded::<()>(1);
+
+        let task = executor.spawn(async {
+            match Self::_start(reset_receiver, timeout_sender).await {
+                Ok(()) => {}
+                Err(err) => error!("InactivityTimer fatal error {}", err),
+            }
+        });
+
+        Self {
+            reset_sender,
+            timeout_receiver,
+            task,
+        }
+    }
+
+    pub async fn stop(self) {
+        self.task.cancel().await;
+    }
+
+    // This loop basically waits for 10 secs. If it doesn't
+    // receive a signal that something happened then it will
+    // send a timeout signal. This will wakeup the main event loop
+    // and the connection will be dropped.
+    async fn _start(
+        reset_rx: async_channel::Receiver<()>,
+        timeout_sx: async_channel::Sender<()>,
+    ) -> Result<()> {
+        loop {
+            let is_awake = futures::select! {
+                _ = reset_rx.recv().fuse() => true,
+                _ = sleep(10).fuse() => false
+            };
+
+            if !is_awake {
+                warn!("InactivityTimer timeout");
+                timeout_sx.send(()).await?;
+            }
+        }
+    }
+
+    pub async fn reset(&self) -> Result<()> {
+        self.reset_sender.send(()).await?;
+        Ok(())
+    }
+
+    pub async fn wait_for_wakeup(&self) -> Result<()> {
+        Ok(self.timeout_receiver.recv().await?)
+    }
+}

+ 26 - 0
src/net/mod.rs

@@ -0,0 +1,26 @@
+use smol::Async;
+use std::net::TcpStream;
+
+pub mod acceptor;
+pub mod channel;
+pub mod connector;
+pub mod error;
+#[macro_use]
+pub mod message_subscriber;
+pub mod hosts;
+pub mod messages;
+pub mod p2p;
+pub mod protocols;
+pub mod sessions;
+pub mod settings;
+pub mod utility;
+
+pub type AsyncTcpStream = async_dup::Arc<Async<TcpStream>>;
+
+pub use acceptor::{Acceptor, AcceptorPtr};
+pub use channel::{Channel, ChannelPtr};
+pub use connector::Connector;
+pub use hosts::{Hosts, HostsPtr};
+pub use message_subscriber::{MessageSubscriber, MessageSubscription};
+pub use p2p::P2p;
+pub use settings::{Settings, SettingsPtr};

+ 98 - 0
src/net/p2p.rs

@@ -0,0 +1,98 @@
+use async_executor::Executor;
+use async_std::sync::Mutex;
+use log::*;
+use std::collections::HashMap;
+use std::net::SocketAddr;
+use std::sync::Arc;
+
+use crate::net::error::{NetError, NetResult};
+use crate::net::sessions::{InboundSession, OutboundSession, SeedSession};
+use crate::net::{Channel, ChannelPtr, Hosts, HostsPtr, Settings, SettingsPtr};
+use crate::system::{Subscriber, SubscriberPtr, Subscription};
+
+pub type Pending<T> = Mutex<HashMap<SocketAddr, Arc<T>>>;
+
+pub type P2pPtr = Arc<P2p>;
+
+pub struct P2p {
+    pending_channels: Pending<Channel>,
+    // Used internally
+    stop_subscriber: SubscriberPtr<NetError>,
+    hosts: HostsPtr,
+    settings: SettingsPtr,
+}
+
+impl P2p {
+    pub fn new(settings: Settings) -> Arc<Self> {
+        let settings = Arc::new(settings);
+        Arc::new(Self {
+            pending_channels: Mutex::new(HashMap::new()),
+            stop_subscriber: Subscriber::new(),
+            hosts: Hosts::new(settings.clone()),
+            settings,
+        })
+    }
+
+    /// Invoke startup and seeding sequence. Call from constructing thread.
+    pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
+        debug!(target: "net", "P2p::start() [BEGIN]");
+        // Start manual connections
+
+        // Start seed session
+        let seed = SeedSession::new(Arc::downgrade(&self));
+        // This will block until all seed queries have finished
+        seed.start(executor.clone()).await?;
+
+        debug!(target: "net", "P2p::start() [END]");
+        Ok(())
+    }
+
+    /// Synchronize the blockchain and then begin long running sessions,
+    /// call after start() is invoked.
+    pub async fn run(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
+        let inbound = InboundSession::new(Arc::downgrade(&self));
+        inbound.clone().start(executor.clone())?;
+
+        let outbound = OutboundSession::new(Arc::downgrade(&self));
+        outbound.clone().start(executor.clone()).await?;
+
+        let stop_sub = self.subscribe_stop().await;
+        // Wait for stop signal
+        stop_sub.receive().await;
+
+        // Stop the sessions
+        inbound.stop().await;
+        outbound.stop().await;
+
+        Ok(())
+    }
+
+    pub async fn store(self: Arc<Self>, channel: ChannelPtr) {
+        self.pending_channels
+            .lock()
+            .await
+            .insert(channel.address(), channel);
+    }
+    pub async fn remove(self: Arc<Self>, channel: ChannelPtr) {
+        self.pending_channels
+            .lock()
+            .await
+            .remove(&channel.address());
+    }
+
+    pub async fn connections_count(&self) -> usize {
+        self.pending_channels.lock().await.len()
+    }
+
+    pub fn settings(&self) -> SettingsPtr {
+        self.settings.clone()
+    }
+
+    pub fn hosts(&self) -> HostsPtr {
+        self.hosts.clone()
+    }
+
+    async fn subscribe_stop(&self) -> Subscription<NetError> {
+        self.stop_subscriber.clone().subscribe().await
+    }
+}

+ 11 - 0
src/net/protocols/mod.rs

@@ -0,0 +1,11 @@
+pub mod protocol_address;
+pub mod protocol_jobs_manager;
+pub mod protocol_ping;
+pub mod protocol_seed;
+pub mod protocol_version;
+
+pub use protocol_address::ProtocolAddress;
+pub use protocol_jobs_manager::{ProtocolJobsManager, ProtocolJobsManagerPtr};
+pub use protocol_ping::ProtocolPing;
+pub use protocol_seed::ProtocolSeed;
+pub use protocol_version::ProtocolVersion;

+ 87 - 0
src/net/protocols/protocol_address.rs

@@ -0,0 +1,87 @@
+use log::*;
+use smol::Executor;
+use std::sync::Arc;
+
+use crate::net::error::NetResult;
+use crate::net::message_subscriber::MessageSubscription;
+use crate::net::messages;
+use crate::net::protocols::{ProtocolJobsManager, ProtocolJobsManagerPtr};
+use crate::net::{ChannelPtr, HostsPtr, SettingsPtr};
+
+pub struct ProtocolAddress {
+    channel: ChannelPtr,
+
+    addrs_sub: MessageSubscription,
+    get_addrs_sub: MessageSubscription,
+
+    hosts: HostsPtr,
+    settings: SettingsPtr,
+
+    jobsman: ProtocolJobsManagerPtr,
+}
+
+impl ProtocolAddress {
+    pub async fn new(channel: ChannelPtr, hosts: HostsPtr, settings: SettingsPtr) -> Arc<Self> {
+        let addrs_sub = channel
+            .clone()
+            .subscribe_msg(messages::PacketType::Addrs)
+            .await;
+
+        let get_addrs_sub = channel
+            .clone()
+            .subscribe_msg(messages::PacketType::GetAddrs)
+            .await;
+
+        Arc::new(Self {
+            channel: channel.clone(),
+            addrs_sub,
+            get_addrs_sub,
+            hosts,
+            settings,
+            jobsman: ProtocolJobsManager::new("ProtocolAddress", channel),
+        })
+    }
+
+    pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
+        debug!(target: "net", "ProtocolAddress::start() [START]");
+        self.jobsman.clone().start(executor.clone());
+        self.jobsman
+            .clone()
+            .spawn(self.clone().handle_receive_addrs(), executor.clone())
+            .await;
+        self.jobsman
+            .clone()
+            .spawn(self.clone().handle_receive_get_addrs(), executor)
+            .await;
+
+        // Send get_address message
+        let get_addrs = messages::Message::GetAddrs(messages::GetAddrsMessage {});
+        let _ = self.channel.clone().send(get_addrs).await;
+        debug!(target: "net", "ProtocolAddress::start() [END]");
+    }
+
+    async fn handle_receive_addrs(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolAddress::handle_receive_addrs() [START]");
+        loop {
+            let addrs_msg = receive_message!(self.addrs_sub, messages::Message::Addrs);
+
+            debug!(target: "net", "ProtocolAddress::handle_receive_addrs() storing address in hosts");
+            self.hosts.store(addrs_msg.addrs.clone()).await;
+        }
+    }
+
+    async fn handle_receive_get_addrs(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolAddress::handle_receive_get_addrs() [START]");
+        loop {
+            let _get_addrs = receive_message!(self.get_addrs_sub, messages::Message::GetAddrs);
+
+            debug!(target: "net", "ProtocolAddress::handle_receive_get_addrs() received GetAddrs message");
+
+            let addrs = messages::Message::Addrs(messages::AddrsMessage {
+                addrs: self.hosts.load_all().await,
+            });
+            debug!(target: "net", "ProtocolAddress::handle_receive_get_addrs() sending Addrs message");
+            self.channel.clone().send(addrs).await?;
+        }
+    }
+}

+ 60 - 0
src/net/protocols/protocol_jobs_manager.rs

@@ -0,0 +1,60 @@
+use async_std::sync::Mutex;
+use futures::Future;
+use log::*;
+use smol::Task;
+use std::sync::Arc;
+
+use crate::net::error::NetResult;
+use crate::net::ChannelPtr;
+use crate::system::ExecutorPtr;
+
+pub type ProtocolJobsManagerPtr = Arc<ProtocolJobsManager>;
+
+pub struct ProtocolJobsManager {
+    name: &'static str,
+    channel: ChannelPtr,
+    tasks: Mutex<Vec<Task<NetResult<()>>>>,
+}
+
+impl ProtocolJobsManager {
+    pub fn new(name: &'static str, channel: ChannelPtr) -> Arc<Self> {
+        Arc::new(Self {
+            name,
+            channel,
+            tasks: Mutex::new(Vec::new()),
+        })
+    }
+
+    pub fn start(self: Arc<Self>, executor: ExecutorPtr<'_>) {
+        executor.spawn(self.handle_stop()).detach()
+    }
+
+    pub async fn spawn<'a, F>(&self, future: F, executor: ExecutorPtr<'a>)
+    where
+        F: Future<Output = NetResult<()>> + Send + 'a,
+    {
+        self.tasks.lock().await.push(executor.spawn(future))
+    }
+
+    async fn handle_stop(self: Arc<Self>) {
+        let stop_sub = self.channel.clone().subscribe_stop().await;
+
+        // Wait for the stop signal
+        // Not interested in the exact error
+        let _ = stop_sub.receive().await;
+
+        self.close_all_tasks().await
+    }
+
+    async fn close_all_tasks(self: Arc<Self>) {
+        debug!(target: "net",
+            "ProtocolJobsManager::close_all_tasks() [START, name={}, addr={}]",
+            self.name,
+            self.channel.address()
+        );
+        let tasks = std::mem::take(&mut *self.tasks.lock().await);
+        for task in tasks {
+            let _ = task.cancel().await;
+        }
+    }
+}

+ 97 - 0
src/net/protocols/protocol_ping.rs

@@ -0,0 +1,97 @@
+use log::*;
+use rand::Rng;
+use smol::Executor;
+use std::sync::Arc;
+
+use crate::net::error::{NetError, NetResult};
+use crate::net::messages;
+use crate::net::protocols::{ProtocolJobsManager, ProtocolJobsManagerPtr};
+use crate::net::utility::sleep;
+use crate::net::{ChannelPtr, SettingsPtr};
+
+pub struct ProtocolPing {
+    channel: ChannelPtr,
+    settings: SettingsPtr,
+
+    jobsman: ProtocolJobsManagerPtr,
+}
+
+impl ProtocolPing {
+    pub fn new(channel: ChannelPtr, settings: SettingsPtr) -> Arc<Self> {
+        Arc::new(Self {
+            channel: channel.clone(),
+            settings,
+            jobsman: ProtocolJobsManager::new("ProtocolPing", channel),
+        })
+    }
+
+    pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
+        debug!(target: "net", "ProtocolPing::start() [START]");
+        self.jobsman.clone().start(executor.clone());
+        self.jobsman
+            .clone()
+            .spawn(self.clone().run_ping_pong(), executor.clone())
+            .await;
+        self.jobsman
+            .clone()
+            .spawn(self.reply_to_ping(), executor)
+            .await;
+        debug!(target: "net", "ProtocolPing::start() [END]");
+    }
+
+    async fn run_ping_pong(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolPing::run_ping_pong() [START]");
+        let pong_sub = self
+            .channel
+            .clone()
+            .subscribe_msg(messages::PacketType::Pong)
+            .await;
+
+        loop {
+            // Wait channel_heartbeat amount of time
+            sleep(self.settings.channel_heartbeat_seconds).await;
+
+            // Create a random nonce
+            let nonce = Self::random_nonce();
+
+            // Send ping message
+            let ping = messages::Message::Ping(messages::PingMessage { nonce });
+            self.channel.clone().send(ping).await?;
+            debug!(target: "net", "ProtocolPing::run_ping_pong() send Ping message");
+
+            // Wait for pong, check nonce matches
+            let pong_msg = receive_message!(pong_sub, messages::Message::Pong);
+            if pong_msg.nonce != nonce {
+                error!("Wrong nonce for ping reply. Disconnecting from channel.");
+                self.channel.stop().await;
+                return Err(NetError::ChannelStopped);
+            }
+            debug!(target: "net", "ProtocolPing::run_ping_pong() received Pong message");
+        }
+    }
+
+    async fn reply_to_ping(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolPing::reply_to_ping() [START]");
+        let ping_sub = self
+            .channel
+            .clone()
+            .subscribe_msg(messages::PacketType::Ping)
+            .await;
+
+        loop {
+            // Wait for ping, reply with pong that has a matching nonce
+            let ping = receive_message!(ping_sub, messages::Message::Ping);
+            debug!(target: "net", "ProtocolPing::reply_to_ping() received Ping message");
+
+            // Send ping message
+            let pong = messages::Message::Pong(messages::PongMessage { nonce: ping.nonce });
+            self.channel.clone().send(pong).await?;
+            debug!(target: "net", "ProtocolPing::reply_to_ping() sent Pong reply");
+        }
+    }
+
+    fn random_nonce() -> u32 {
+        let mut rng = rand::thread_rng();
+        rng.gen()
+    }
+}

+ 59 - 0
src/net/protocols/protocol_seed.rs

@@ -0,0 +1,59 @@
+use log::*;
+use smol::Executor;
+use std::sync::Arc;
+
+use crate::net::error::NetResult;
+use crate::net::messages;
+use crate::net::{ChannelPtr, HostsPtr, SettingsPtr};
+
+pub struct ProtocolSeed {
+    channel: ChannelPtr,
+    hosts: HostsPtr,
+    settings: SettingsPtr,
+}
+
+impl ProtocolSeed {
+    pub fn new(channel: ChannelPtr, hosts: HostsPtr, settings: SettingsPtr) -> Arc<Self> {
+        Arc::new(Self {
+            channel,
+            hosts,
+            settings,
+        })
+    }
+
+    pub async fn start(self: Arc<Self>, _executor: Arc<Executor<'_>>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolSeed::start() [START]");
+        let addr_sub = self
+            .channel
+            .clone()
+            .subscribe_msg(messages::PacketType::Addrs)
+            .await;
+
+        // Send own address to the seed server
+        self.send_own_address().await?;
+
+        // Send get address message
+        let get_addr = messages::Message::GetAddrs(messages::GetAddrsMessage {});
+        self.channel.clone().send(get_addr).await?;
+
+        // Receive addresses
+        let addrs_msg = receive_message!(addr_sub, messages::Message::Addrs);
+        self.hosts.store(addrs_msg.addrs.clone()).await;
+
+        debug!(target: "net", "ProtocolSeed::start() [END]");
+        Ok(())
+    }
+
+    pub async fn send_own_address(&self) -> NetResult<()> {
+        match self.settings.external_addr {
+            Some(addr) => {
+                let addr = messages::Message::Addrs(messages::AddrsMessage { addrs: vec![addr] });
+                self.channel.clone().send(addr).await?;
+            }
+            None => {
+                // Do nothing if external address is not configured
+            }
+        }
+        Ok(())
+    }
+}

+ 89 - 0
src/net/protocols/protocol_version.rs

@@ -0,0 +1,89 @@
+use futures::FutureExt;
+use log::*;
+use smol::Executor;
+use std::sync::Arc;
+
+use crate::net::error::{NetError, NetResult};
+use crate::net::message_subscriber::MessageSubscription;
+use crate::net::messages;
+use crate::net::utility::sleep;
+use crate::net::{ChannelPtr, SettingsPtr};
+
+pub struct ProtocolVersion {
+    channel: ChannelPtr,
+    version_sub: MessageSubscription,
+    verack_sub: MessageSubscription,
+    settings: SettingsPtr,
+}
+
+impl ProtocolVersion {
+    pub async fn new(channel: ChannelPtr, settings: SettingsPtr) -> Arc<Self> {
+        let version_sub = channel
+            .clone()
+            .subscribe_msg(messages::PacketType::Version)
+            .await;
+
+        let verack_sub = channel
+            .clone()
+            .subscribe_msg(messages::PacketType::Verack)
+            .await;
+
+        Arc::new(Self {
+            channel,
+            version_sub,
+            verack_sub,
+            settings,
+        })
+    }
+
+    pub async fn run(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolVersion::run() [START]");
+        // Start timer
+        // Send version, wait for verack
+        // Wait for version, send verack
+        // Fin.
+        let result = futures::select! {
+            _ = self.clone().exchange_versions(executor).fuse() => Ok(()),
+            _ = sleep(self.settings.channel_handshake_seconds).fuse() => Err(NetError::ChannelTimeout)
+        };
+        debug!(target: "net", "ProtocolVersion::run() [END]");
+        result
+    }
+
+    async fn exchange_versions(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolVersion::exchange_versions() [START]");
+
+        let send = executor.spawn(self.clone().send_version());
+        let recv = executor.spawn(self.recv_version());
+
+        send.await.and(recv.await)?;
+        debug!(target: "net", "ProtocolVersion::exchange_versions() [END]");
+        Ok(())
+    }
+
+    async fn send_version(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolVersion::send_version() [START]");
+        let version = messages::Message::Version(messages::VersionMessage {});
+        self.channel.clone().send(version).await?;
+
+        // Wait for version acknowledgement
+        let _verack_msg = self.verack_sub.receive().await?;
+
+        debug!(target: "net", "ProtocolVersion::send_version() [END]");
+        Ok(())
+    }
+
+    async fn recv_version(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolVersion::recv_version() [START]");
+        let _version_msg = self.version_sub.receive().await?;
+
+        // Check the message is OK
+
+        // Send version acknowledgement
+        let verack = messages::Message::Verack(messages::VerackMessage {});
+        self.channel.clone().send(verack).await?;
+
+        debug!(target: "net", "ProtocolVersion::recv_version() [END]");
+        Ok(())
+    }
+}

+ 124 - 0
src/net/sessions/inbound_session.rs

@@ -0,0 +1,124 @@
+use async_executor::Executor;
+use log::*;
+use std::net::SocketAddr;
+use std::sync::{Arc, Weak};
+
+use crate::net::error::{NetError, NetResult};
+use crate::net::protocols::{ProtocolAddress, ProtocolPing};
+use crate::net::sessions::Session;
+use crate::net::{Acceptor, AcceptorPtr};
+use crate::net::{ChannelPtr, P2p};
+use crate::system::{StoppableTask, StoppableTaskPtr};
+
+pub struct InboundSession {
+    p2p: Weak<P2p>,
+    acceptor: AcceptorPtr,
+    accept_task: StoppableTaskPtr,
+}
+
+impl InboundSession {
+    pub fn new(p2p: Weak<P2p>) -> Arc<Self> {
+        let settings = {
+            let p2p = p2p.upgrade().unwrap();
+            p2p.settings()
+        };
+
+        let acceptor = Acceptor::new(settings);
+
+        Arc::new(Self {
+            p2p,
+            acceptor,
+            accept_task: StoppableTask::new(),
+        })
+    }
+
+    pub fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
+        match self.p2p().settings().inbound {
+            Some(accept_addr) => {
+                self.clone()
+                    .start_accept_session(accept_addr, executor.clone())?;
+            }
+            None => {
+                info!("Not configured for accepting incoming connections.");
+                return Ok(());
+            }
+        }
+
+        self.accept_task.clone().start(
+            self.clone().channel_sub_loop(executor.clone()),
+            // Ignore stop handler
+            |_| async {},
+            NetError::ServiceStopped,
+            executor,
+        );
+
+        Ok(())
+    }
+
+    pub async fn stop(&self) {
+        self.acceptor.stop().await;
+        self.accept_task.stop().await;
+    }
+
+    fn start_accept_session(
+        self: Arc<Self>,
+        accept_addr: SocketAddr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        info!("Starting inbound session on {}", accept_addr);
+        let result = self.acceptor.clone().start(accept_addr, executor);
+        if let Err(err) = result {
+            error!("Error starting listener: {}", err);
+        }
+        result
+    }
+
+    async fn channel_sub_loop(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
+        let channel_sub = self.acceptor.clone().subscribe().await;
+        loop {
+            let channel = (*channel_sub.receive().await).clone()?;
+            // Spawn a detached task to process the channel
+            // This will just perform the channel setup then exit.
+            executor
+                .spawn(self.clone().setup_channel(channel, executor.clone()))
+                .detach();
+        }
+    }
+
+    async fn setup_channel(
+        self: Arc<Self>,
+        channel: ChannelPtr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        info!("Connected inbound [{}]", channel.address());
+
+        self.clone()
+            .register_channel(channel.clone(), executor.clone())
+            .await?;
+
+        self.attach_protocols(channel, executor).await
+    }
+
+    async fn attach_protocols(
+        self: Arc<Self>,
+        channel: ChannelPtr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        let settings = self.p2p().settings().clone();
+        let hosts = self.p2p().hosts().clone();
+
+        let protocol_ping = ProtocolPing::new(channel.clone(), settings.clone());
+        let protocol_addr = ProtocolAddress::new(channel, hosts, settings).await;
+
+        protocol_ping.start(executor.clone()).await;
+        protocol_addr.start(executor).await;
+
+        Ok(())
+    }
+}
+
+impl Session for InboundSession {
+    fn p2p(&self) -> Arc<P2p> {
+        self.p2p.upgrade().unwrap()
+    }
+}

+ 9 - 0
src/net/sessions/mod.rs

@@ -0,0 +1,9 @@
+pub mod inbound_session;
+pub mod outbound_session;
+pub mod seed_session;
+pub mod session;
+
+pub use inbound_session::InboundSession;
+pub use outbound_session::OutboundSession;
+pub use seed_session::SeedSession;
+pub use session::Session;

+ 129 - 0
src/net/sessions/outbound_session.rs

@@ -0,0 +1,129 @@
+use async_executor::Executor;
+use async_std::sync::Mutex;
+use log::*;
+use std::net::SocketAddr;
+use std::sync::{Arc, Weak};
+
+use crate::net::error::{NetError, NetResult};
+use crate::net::protocols::{ProtocolAddress, ProtocolPing};
+use crate::net::sessions::Session;
+use crate::net::{ChannelPtr, Connector, P2p};
+use crate::system::{StoppableTask, StoppableTaskPtr};
+
+pub struct OutboundSession {
+    p2p: Weak<P2p>,
+    connect_slots: Mutex<Vec<StoppableTaskPtr>>,
+}
+
+impl OutboundSession {
+    pub fn new(p2p: Weak<P2p>) -> Arc<Self> {
+        Arc::new(Self {
+            p2p,
+            connect_slots: Mutex::new(Vec::new()),
+        })
+    }
+
+    pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
+        let slots_count = self.p2p().settings().outbound_connections;
+        let mut connect_slots = self.connect_slots.lock().await;
+
+        for i in 0..slots_count {
+            let task = StoppableTask::new();
+
+            task.clone().start(
+                self.clone().channel_connect_loop(i, executor.clone()),
+                // Ignore stop handler
+                |_| async {},
+                NetError::ServiceStopped,
+                executor.clone(),
+            );
+
+            connect_slots.push(task);
+        }
+
+        Ok(())
+    }
+
+    pub async fn stop(&self) {
+        let connect_slots = &*self.connect_slots.lock().await;
+
+        for slot in connect_slots {
+            slot.stop().await;
+        }
+    }
+
+    pub async fn channel_connect_loop(
+        self: Arc<Self>,
+        slot_number: u32,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        let connector = Connector::new(self.p2p().settings().clone());
+
+        loop {
+            let addr = self.load_address(slot_number).await?;
+            info!("Connecting to outbound [{}]", addr);
+
+            match connector.connect(addr).await {
+                Ok(channel) => {
+                    // Blacklist goes here
+
+                    info!("Connected outbound [{}]", addr);
+
+                    let stop_sub = channel.subscribe_stop().await;
+
+                    self.clone()
+                        .register_channel(channel.clone(), executor.clone())
+                        .await?;
+
+                    self.clone()
+                        .attach_protocols(channel, executor.clone())
+                        .await?;
+
+                    // Wait for channel to close
+                    stop_sub.receive().await;
+                }
+                Err(err) => {
+                    info!("Unable to connect to outbound [{}]: {}", addr, err);
+                }
+            }
+        }
+    }
+
+    async fn load_address(&self, slot_number: u32) -> NetResult<SocketAddr> {
+        let hosts = self.p2p().hosts();
+
+        match hosts.load_single().await {
+            Some(addr) => Ok(addr),
+            None => {
+                error!(
+                    "Hosts address pool is empty. Closing connect slot #{}",
+                    slot_number
+                );
+                Err(NetError::ServiceStopped)
+            }
+        }
+    }
+
+    async fn attach_protocols(
+        self: Arc<Self>,
+        channel: ChannelPtr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        let settings = self.p2p().settings().clone();
+        let hosts = self.p2p().hosts().clone();
+
+        let protocol_ping = ProtocolPing::new(channel.clone(), settings.clone());
+        let protocol_addr = ProtocolAddress::new(channel, hosts, settings).await;
+
+        protocol_ping.start(executor.clone()).await;
+        protocol_addr.start(executor).await;
+
+        Ok(())
+    }
+}
+
+impl Session for OutboundSession {
+    fn p2p(&self) -> Arc<P2p> {
+        self.p2p.upgrade().unwrap()
+    }
+}

+ 124 - 0
src/net/sessions/seed_session.rs

@@ -0,0 +1,124 @@
+use async_executor::Executor;
+use log::*;
+use std::net::SocketAddr;
+use std::sync::{Arc, Weak};
+
+use crate::net::error::{NetError, NetResult};
+use crate::net::protocols::{ProtocolPing, ProtocolSeed};
+use crate::net::sessions::Session;
+use crate::net::{ChannelPtr, Connector, HostsPtr, P2p, SettingsPtr};
+
+pub struct SeedSession {
+    p2p: Weak<P2p>,
+}
+
+impl SeedSession {
+    pub fn new(p2p: Weak<P2p>) -> Arc<Self> {
+        Arc::new(Self { p2p })
+    }
+
+    pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
+        debug!(target: "net", "SeedSession::start() [START]");
+        let settings = {
+            let p2p = self.p2p.upgrade().unwrap();
+            p2p.settings()
+        };
+
+        if settings.skip_seed_sync {
+            info!("Configured to skip seed synchronization process.");
+            return Ok(());
+        }
+
+        // if cached addresses then quit
+
+        // if seeds empty then seeding required but empty
+        if settings.seeds.is_empty() {
+            error!("Seeding is required but no seeds are configured.");
+            return Err(NetError::OperationFailed);
+        }
+
+        let mut tasks = Vec::new();
+
+        for (i, seed) in settings.seeds.iter().enumerate() {
+            tasks.push(executor.spawn(self.clone().start_seed(i, seed.clone(), executor.clone())));
+        }
+
+        for (i, task) in tasks.into_iter().enumerate() {
+            // Ignore errors
+            match task.await {
+                Ok(()) => info!("Successfully queried seed #{}", i),
+                Err(err) => warn!("Seed query #{} failed for reason: {}", i, err),
+            }
+        }
+
+        // Seed process complete
+        // TODO: check increase count of address
+
+        debug!(target: "net", "SeedSession::start() [END]");
+        Ok(())
+    }
+
+    async fn start_seed(
+        self: Arc<Self>,
+        seed_index: usize,
+        seed: SocketAddr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        debug!(target: "net", "SeedSession::start_seed(i={}) [START]", seed_index);
+        let (hosts, settings) = {
+            let p2p = self.p2p.upgrade().unwrap();
+            (p2p.hosts(), p2p.settings())
+        };
+
+        let connector = Connector::new(settings.clone());
+        match connector.connect(seed).await {
+            Ok(channel) => {
+                // Blacklist goes here
+
+                info!("Connected seed #{} [{}]", seed_index, seed);
+
+                self.clone()
+                    .register_channel(channel.clone(), executor.clone())
+                    .await?;
+
+                self.attach_protocols(channel, hosts, settings, executor)
+                    .await?;
+
+                debug!(target: "net", "SeedSession::start_seed(i={}) [END]", seed_index);
+                Ok(())
+            }
+            Err(err) => {
+                info!(
+                    "Failure contacting seed #{} [{}]: {}",
+                    seed_index, seed, err
+                );
+                Err(err)
+            }
+        }
+    }
+
+    async fn attach_protocols(
+        self: Arc<Self>,
+        channel: ChannelPtr,
+        hosts: HostsPtr,
+        settings: SettingsPtr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        let protocol_ping = ProtocolPing::new(channel.clone(), settings.clone());
+        protocol_ping.start(executor.clone()).await;
+
+        let protocol_seed = ProtocolSeed::new(channel.clone(), hosts, settings.clone());
+        // This will block until seed process is complete
+        protocol_seed.start(executor.clone()).await?;
+
+        channel.stop().await;
+
+        Ok(())
+    }
+}
+
+impl Session for SeedSession {
+    fn p2p(&self) -> Arc<P2p> {
+        self.p2p.upgrade().unwrap()
+    }
+}

+ 72 - 0
src/net/sessions/session.rs

@@ -0,0 +1,72 @@
+use async_trait::async_trait;
+use log::*;
+use smol::Executor;
+use std::sync::Arc;
+
+use crate::net::error::NetResult;
+use crate::net::p2p::P2pPtr;
+use crate::net::protocols::ProtocolVersion;
+use crate::net::ChannelPtr;
+
+async fn remove_sub_on_stop(p2p: P2pPtr, channel: ChannelPtr) {
+    debug!(target: "net", "remove_sub_on_stop() [START]");
+    // Subscribe to stop events
+    let stop_sub = channel.clone().subscribe_stop().await;
+    // Wait for a stop event
+    let _ = stop_sub.receive().await;
+    debug!(target: "net",
+        "remove_sub_on_stop(): received stop event. Removing channel {}",
+        channel.address()
+    );
+    // Remove channel from p2p
+    p2p.remove(channel).await;
+    debug!(target: "net", "remove_sub_on_stop() [END]");
+}
+
+#[async_trait]
+pub trait Session: Sync {
+    async fn register_channel(
+        self: Arc<Self>,
+        channel: ChannelPtr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        debug!(target: "net", "Session::register_channel() [START]");
+
+        let protocol_version = ProtocolVersion::new(channel.clone(), self.p2p().settings()).await;
+        let handshake_task =
+            self.perform_handshake_protocols(protocol_version, channel.clone(), executor.clone());
+
+        // start channel
+        channel.start(executor);
+
+        handshake_task.await?;
+
+        debug!(target: "net", "Session::register_channel() [END]");
+        Ok(())
+    }
+
+    async fn perform_handshake_protocols(
+        &self,
+        protocol_version: Arc<ProtocolVersion>,
+        channel: ChannelPtr,
+        executor: Arc<Executor<'_>>,
+    ) -> NetResult<()> {
+        // Perform handshake
+        protocol_version.run(executor.clone()).await?;
+
+        // Channel is now initialized
+
+        // Add channel to p2p
+        self.p2p().clone().store(channel.clone()).await;
+
+        // Subscribe to stop, so can remove from p2p
+        executor
+            .spawn(remove_sub_on_stop(self.p2p(), channel))
+            .detach();
+
+        // Channel is ready for use
+        Ok(())
+    }
+
+    fn p2p(&self) -> P2pPtr;
+}

+ 19 - 0
src/net/settings.rs

@@ -0,0 +1,19 @@
+use std::net::SocketAddr;
+use std::sync::Arc;
+
+pub type SettingsPtr = Arc<Settings>;
+
+#[derive(Clone)]
+pub struct Settings {
+    pub inbound: Option<SocketAddr>,
+    pub outbound_connections: u32,
+
+    pub connect_timeout_seconds: u32,
+    pub channel_handshake_seconds: u32,
+    pub channel_heartbeat_seconds: u32,
+
+    pub external_addr: Option<SocketAddr>,
+    pub peers: Vec<SocketAddr>,
+    pub seeds: Vec<SocketAddr>,
+    pub skip_seed_sync: bool,
+}

+ 6 - 0
src/net/utility.rs

@@ -0,0 +1,6 @@
+use smol::Timer;
+use std::time::Duration;
+
+pub async fn sleep(seconds: u32) {
+    Timer::after(Duration::from_secs(seconds.into())).await;
+}

+ 677 - 622
src/serial.rs

@@ -1,7 +1,7 @@
 use bls12_381 as bls;
 use std::borrow::Cow;
 use std::io::{Cursor, Read, Write};
-
+use std::net::{IpAddr, SocketAddr};
 use std::{io, mem};
 
 use crate::endian;
@@ -9,185 +9,185 @@ use crate::error::{Error, Result};
 
 /// Encode an object into a vector
 pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> {
-    let mut encoder = Vec::new();
-    let len = data.encode(&mut encoder).unwrap();
-    assert_eq!(len, encoder.len());
-    encoder
+let mut encoder = Vec::new();
+let len = data.encode(&mut encoder).unwrap();
+assert_eq!(len, encoder.len());
+encoder
 }
 
 /// Encode an object into a hex-encoded string
 pub fn serialize_hex<T: Encodable + ?Sized>(data: &T) -> String {
-    hex::encode(serialize(data))
+hex::encode(serialize(data))
 }
 
 /// Deserialize an object from a vector, will error if said deserialization
 /// doesn't consume the entire vector.
 pub fn deserialize<T: Decodable>(data: &[u8]) -> Result<T> {
-    let (rv, consumed) = deserialize_partial(data)?;
-
-    // Fail if data are not consumed entirely.
-    if consumed == data.len() {
-        Ok(rv)
-    } else {
-        Err(Error::ParseFailed(
-            "data not consumed entirely when explicitly deserializing",
-        ))
-    }
+let (rv, consumed) = deserialize_partial(data)?;
+
+// Fail if data are not consumed entirely.
+if consumed == data.len() {
+Ok(rv)
+} else {
+Err(Error::ParseFailed(
+"data not consumed entirely when explicitly deserializing",
+))
+}
 }
 
 /// Deserialize an object from a vector, but will not report an error if said deserialization
 /// doesn't consume the entire vector.
 pub fn deserialize_partial<T: Decodable>(data: &[u8]) -> Result<(T, usize)> {
-    let mut decoder = Cursor::new(data);
-    let rv = Decodable::decode(&mut decoder)?;
-    let consumed = decoder.position() as usize;
+let mut decoder = Cursor::new(data);
+let rv = Decodable::decode(&mut decoder)?;
+let consumed = decoder.position() as usize;
 
-    Ok((rv, consumed))
+Ok((rv, consumed))
 }
 
 /// Extensions of `Write` to encode data as per Bitcoin consensus
 pub trait WriteExt {
-    /// Output a 64-bit uint
-    fn write_u64(&mut self, v: u64) -> Result<()>;
-    /// Output a 32-bit uint
-    fn write_u32(&mut self, v: u32) -> Result<()>;
-    /// Output a 16-bit uint
-    fn write_u16(&mut self, v: u16) -> Result<()>;
-    /// Output a 8-bit uint
-    fn write_u8(&mut self, v: u8) -> Result<()>;
-
-    /// Output a 64-bit int
-    fn write_i64(&mut self, v: i64) -> Result<()>;
-    /// Output a 32-bit int
-    fn write_i32(&mut self, v: i32) -> Result<()>;
-    /// Output a 16-bit int
-    fn write_i16(&mut self, v: i16) -> Result<()>;
-    /// Output a 8-bit int
-    fn write_i8(&mut self, v: i8) -> Result<()>;
-
-    /// Output a boolean
-    fn write_bool(&mut self, v: bool) -> Result<()>;
-
-    /// Output a byte slice
-    fn write_slice(&mut self, v: &[u8]) -> Result<()>;
+/// Output a 64-bit uint
+fn write_u64(&mut self, v: u64) -> Result<()>;
+/// Output a 32-bit uint
+fn write_u32(&mut self, v: u32) -> Result<()>;
+/// Output a 16-bit uint
+fn write_u16(&mut self, v: u16) -> Result<()>;
+/// Output a 8-bit uint
+fn write_u8(&mut self, v: u8) -> Result<()>;
+
+/// Output a 64-bit int
+fn write_i64(&mut self, v: i64) -> Result<()>;
+/// Output a 32-bit int
+fn write_i32(&mut self, v: i32) -> Result<()>;
+/// Output a 16-bit int
+fn write_i16(&mut self, v: i16) -> Result<()>;
+/// Output a 8-bit int
+fn write_i8(&mut self, v: i8) -> Result<()>;
+
+/// Output a boolean
+fn write_bool(&mut self, v: bool) -> Result<()>;
+
+/// Output a byte slice
+fn write_slice(&mut self, v: &[u8]) -> Result<()>;
 }
 
 /// Extensions of `Read` to decode data as per Bitcoin consensus
 pub trait ReadExt {
-    /// Read a 64-bit uint
-    fn read_u64(&mut self) -> Result<u64>;
-    /// Read a 32-bit uint
-    fn read_u32(&mut self) -> Result<u32>;
-    /// Read a 16-bit uint
-    fn read_u16(&mut self) -> Result<u16>;
-    /// Read a 8-bit uint
-    fn read_u8(&mut self) -> Result<u8>;
-
-    /// Read a 64-bit int
-    fn read_i64(&mut self) -> Result<i64>;
-    /// Read a 32-bit int
-    fn read_i32(&mut self) -> Result<i32>;
-    /// Read a 16-bit int
-    fn read_i16(&mut self) -> Result<i16>;
-    /// Read a 8-bit int
-    fn read_i8(&mut self) -> Result<i8>;
-
-    /// Read a boolean
-    fn read_bool(&mut self) -> Result<bool>;
-
-    /// Read a byte slice
-    fn read_slice(&mut self, slice: &mut [u8]) -> Result<()>;
+/// Read a 64-bit uint
+fn read_u64(&mut self) -> Result<u64>;
+/// Read a 32-bit uint
+fn read_u32(&mut self) -> Result<u32>;
+/// Read a 16-bit uint
+fn read_u16(&mut self) -> Result<u16>;
+/// Read a 8-bit uint
+fn read_u8(&mut self) -> Result<u8>;
+
+/// Read a 64-bit int
+fn read_i64(&mut self) -> Result<i64>;
+/// Read a 32-bit int
+fn read_i32(&mut self) -> Result<i32>;
+/// Read a 16-bit int
+fn read_i16(&mut self) -> Result<i16>;
+/// Read a 8-bit int
+fn read_i8(&mut self) -> Result<i8>;
+
+/// Read a boolean
+fn read_bool(&mut self) -> Result<bool>;
+
+/// Read a byte slice
+fn read_slice(&mut self, slice: &mut [u8]) -> Result<()>;
 }
 
 macro_rules! encoder_fn {
-    ($name:ident, $val_type:ty, $writefn:ident) => {
-        #[inline]
-        fn $name(&mut self, v: $val_type) -> Result<()> {
-            self.write_all(&endian::$writefn(v)).map_err(Error::Io)
-        }
-    };
+($name:ident, $val_type:ty, $writefn:ident) => {
+#[inline]
+fn $name(&mut self, v: $val_type) -> Result<()> {
+self.write_all(&endian::$writefn(v)).map_err(Error::Io)
+}
+};
 }
 
 macro_rules! decoder_fn {
-    ($name:ident, $val_type:ty, $readfn:ident, $byte_len: expr) => {
-        #[inline]
-        fn $name(&mut self) -> Result<$val_type> {
-            assert_eq!(::std::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22
-            let mut val = [0; $byte_len];
-            self.read_exact(&mut val[..]).map_err(Error::Io)?;
-            Ok(endian::$readfn(&val))
-        }
-    };
+($name:ident, $val_type:ty, $readfn:ident, $byte_len: expr) => {
+#[inline]
+fn $name(&mut self) -> Result<$val_type> {
+assert_eq!(::std::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22
+let mut val = [0; $byte_len];
+self.read_exact(&mut val[..]).map_err(Error::Io)?;
+Ok(endian::$readfn(&val))
+}
+};
 }
 
 impl<W: Write> WriteExt for W {
-    encoder_fn!(write_u64, u64, u64_to_array_le);
-    encoder_fn!(write_u32, u32, u32_to_array_le);
-    encoder_fn!(write_u16, u16, u16_to_array_le);
-    encoder_fn!(write_i64, i64, i64_to_array_le);
-    encoder_fn!(write_i32, i32, i32_to_array_le);
-    encoder_fn!(write_i16, i16, i16_to_array_le);
-
-    #[inline]
-    fn write_i8(&mut self, v: i8) -> Result<()> {
-        self.write_all(&[v as u8]).map_err(Error::Io)
-    }
-    #[inline]
-    fn write_u8(&mut self, v: u8) -> Result<()> {
-        self.write_all(&[v]).map_err(Error::Io)
-    }
-    #[inline]
-    fn write_bool(&mut self, v: bool) -> Result<()> {
-        self.write_all(&[v as u8]).map_err(Error::Io)
-    }
-    #[inline]
-    fn write_slice(&mut self, v: &[u8]) -> Result<()> {
-        self.write_all(v).map_err(Error::Io)
-    }
+encoder_fn!(write_u64, u64, u64_to_array_le);
+encoder_fn!(write_u32, u32, u32_to_array_le);
+encoder_fn!(write_u16, u16, u16_to_array_le);
+encoder_fn!(write_i64, i64, i64_to_array_le);
+encoder_fn!(write_i32, i32, i32_to_array_le);
+encoder_fn!(write_i16, i16, i16_to_array_le);
+
+#[inline]
+fn write_i8(&mut self, v: i8) -> Result<()> {
+self.write_all(&[v as u8]).map_err(Error::Io)
+}
+#[inline]
+fn write_u8(&mut self, v: u8) -> Result<()> {
+self.write_all(&[v]).map_err(Error::Io)
+}
+#[inline]
+fn write_bool(&mut self, v: bool) -> Result<()> {
+self.write_all(&[v as u8]).map_err(Error::Io)
+}
+#[inline]
+fn write_slice(&mut self, v: &[u8]) -> Result<()> {
+self.write_all(v).map_err(Error::Io)
+}
 }
 
 impl<R: Read> ReadExt for R {
-    decoder_fn!(read_u64, u64, slice_to_u64_le, 8);
-    decoder_fn!(read_u32, u32, slice_to_u32_le, 4);
-    decoder_fn!(read_u16, u16, slice_to_u16_le, 2);
-    decoder_fn!(read_i64, i64, slice_to_i64_le, 8);
-    decoder_fn!(read_i32, i32, slice_to_i32_le, 4);
-    decoder_fn!(read_i16, i16, slice_to_i16_le, 2);
-
-    #[inline]
-    fn read_u8(&mut self) -> Result<u8> {
-        let mut slice = [0u8; 1];
-        self.read_exact(&mut slice)?;
-        Ok(slice[0])
-    }
-    #[inline]
-    fn read_i8(&mut self) -> Result<i8> {
-        let mut slice = [0u8; 1];
-        self.read_exact(&mut slice)?;
-        Ok(slice[0] as i8)
-    }
-    #[inline]
-    fn read_bool(&mut self) -> Result<bool> {
-        ReadExt::read_i8(self).map(|bit| bit != 0)
-    }
-    #[inline]
-    fn read_slice(&mut self, slice: &mut [u8]) -> Result<()> {
-        self.read_exact(slice).map_err(Error::Io)
-    }
+decoder_fn!(read_u64, u64, slice_to_u64_le, 8);
+decoder_fn!(read_u32, u32, slice_to_u32_le, 4);
+decoder_fn!(read_u16, u16, slice_to_u16_le, 2);
+decoder_fn!(read_i64, i64, slice_to_i64_le, 8);
+decoder_fn!(read_i32, i32, slice_to_i32_le, 4);
+decoder_fn!(read_i16, i16, slice_to_i16_le, 2);
+
+#[inline]
+fn read_u8(&mut self) -> Result<u8> {
+let mut slice = [0u8; 1];
+self.read_exact(&mut slice)?;
+Ok(slice[0])
+}
+#[inline]
+fn read_i8(&mut self) -> Result<i8> {
+let mut slice = [0u8; 1];
+self.read_exact(&mut slice)?;
+Ok(slice[0] as i8)
+}
+#[inline]
+fn read_bool(&mut self) -> Result<bool> {
+ReadExt::read_i8(self).map(|bit| bit != 0)
+}
+#[inline]
+fn read_slice(&mut self, slice: &mut [u8]) -> Result<()> {
+self.read_exact(slice).map_err(Error::Io)
+}
 }
 
 /// Data which can be encoded in a consensus-consistent way
 pub trait Encodable {
-    /// Encode an object with a well-defined format, should only ever error if
-    /// the underlying `Write` errors. Returns the number of bytes written on
-    /// success
-    fn encode<W: io::Write>(&self, e: W) -> Result<usize>;
+/// Encode an object with a well-defined format, should only ever error if
+/// the underlying `Write` errors. Returns the number of bytes written on
+/// success
+fn encode<W: io::Write>(&self, e: W) -> Result<usize>;
 }
 
 /// Data which can be encoded in a consensus-consistent way
 pub trait Decodable: Sized {
-    /// Decode an object with a well-defined format
-    fn decode<D: io::Read>(d: D) -> Result<Self>;
+/// Decode an object with a well-defined format
+fn decode<D: io::Read>(d: D) -> Result<Self>;
 }
 
 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
@@ -195,21 +195,21 @@ pub struct VarInt(pub u64);
 
 // Primitive types
 macro_rules! impl_int_encodable {
-    ($ty:ident, $meth_dec:ident, $meth_enc:ident) => {
-        impl Decodable for $ty {
-            #[inline]
-            fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-                ReadExt::$meth_dec(&mut d).map($ty::from_le)
-            }
-        }
-        impl Encodable for $ty {
-            #[inline]
-            fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
-                s.$meth_enc(self.to_le())?;
-                Ok(mem::size_of::<$ty>())
-            }
-        }
-    };
+($ty:ident, $meth_dec:ident, $meth_enc:ident) => {
+impl Decodable for $ty {
+#[inline]
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+ReadExt::$meth_dec(&mut d).map($ty::from_le)
+}
+}
+impl Encodable for $ty {
+#[inline]
+fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
+s.$meth_enc(self.to_le())?;
+Ok(mem::size_of::<$ty>())
+}
+}
+};
 }
 
 impl_int_encodable!(u8, read_u8, write_u8);
@@ -222,156 +222,156 @@ impl_int_encodable!(i32, read_i32, write_i32);
 impl_int_encodable!(i64, read_i64, write_i64);
 
 impl VarInt {
-    /// Gets the length of this VarInt when encoded.
-    /// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1),
-    /// and 9 otherwise.
-    #[inline]
-    pub fn len(&self) -> usize {
-        match self.0 {
-            0..=0xFC => 1,
-            0xFD..=0xFFFF => 3,
-            0x10000..=0xFFFFFFFF => 5,
-            _ => 9,
-        }
-    }
+/// Gets the length of this VarInt when encoded.
+/// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1),
+/// and 9 otherwise.
+#[inline]
+pub fn len(&self) -> usize {
+match self.0 {
+0..=0xFC => 1,
+0xFD..=0xFFFF => 3,
+0x10000..=0xFFFFFFFF => 5,
+_ => 9,
+}
+}
 }
 
 impl Encodable for VarInt {
-    #[inline]
-    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        match self.0 {
-            0..=0xFC => {
-                (self.0 as u8).encode(s)?;
-                Ok(1)
-            }
-            0xFD..=0xFFFF => {
-                s.write_u8(0xFD)?;
-                (self.0 as u16).encode(s)?;
-                Ok(3)
-            }
-            0x10000..=0xFFFFFFFF => {
-                s.write_u8(0xFE)?;
-                (self.0 as u32).encode(s)?;
-                Ok(5)
-            }
-            _ => {
-                s.write_u8(0xFF)?;
-                (self.0 as u64).encode(s)?;
-                Ok(9)
-            }
-        }
-    }
+#[inline]
+fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+match self.0 {
+0..=0xFC => {
+(self.0 as u8).encode(s)?;
+Ok(1)
+}
+0xFD..=0xFFFF => {
+s.write_u8(0xFD)?;
+(self.0 as u16).encode(s)?;
+Ok(3)
+}
+0x10000..=0xFFFFFFFF => {
+s.write_u8(0xFE)?;
+(self.0 as u32).encode(s)?;
+Ok(5)
+}
+_ => {
+s.write_u8(0xFF)?;
+(self.0 as u64).encode(s)?;
+Ok(9)
+}
+}
+}
 }
 
 impl Decodable for VarInt {
-    #[inline]
-    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-        let n = ReadExt::read_u8(&mut d)?;
-        match n {
-            0xFF => {
-                let x = ReadExt::read_u64(&mut d)?;
-                if x < 0x100000000 {
-                    Err(self::Error::NonMinimalVarInt)
-                } else {
-                    Ok(VarInt(x))
-                }
-            }
-            0xFE => {
-                let x = ReadExt::read_u32(&mut d)?;
-                if x < 0x10000 {
-                    Err(self::Error::NonMinimalVarInt)
-                } else {
-                    Ok(VarInt(x as u64))
-                }
-            }
-            0xFD => {
-                let x = ReadExt::read_u16(&mut d)?;
-                if x < 0xFD {
-                    Err(self::Error::NonMinimalVarInt)
-                } else {
-                    Ok(VarInt(x as u64))
-                }
-            }
-            n => Ok(VarInt(n as u64)),
-        }
-    }
+#[inline]
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+let n = ReadExt::read_u8(&mut d)?;
+match n {
+0xFF => {
+let x = ReadExt::read_u64(&mut d)?;
+if x < 0x100000000 {
+Err(self::Error::NonMinimalVarInt)
+} else {
+Ok(VarInt(x))
+}
+}
+0xFE => {
+let x = ReadExt::read_u32(&mut d)?;
+if x < 0x10000 {
+Err(self::Error::NonMinimalVarInt)
+} else {
+Ok(VarInt(x as u64))
+}
+}
+0xFD => {
+let x = ReadExt::read_u16(&mut d)?;
+if x < 0xFD {
+Err(self::Error::NonMinimalVarInt)
+} else {
+Ok(VarInt(x as u64))
+}
+}
+n => Ok(VarInt(n as u64)),
+}
+}
 }
 
 // Booleans
 impl Encodable for bool {
-    #[inline]
-    fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
-        s.write_bool(*self)?;
-        Ok(1)
-    }
+#[inline]
+fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
+s.write_bool(*self)?;
+Ok(1)
+}
 }
 
 impl Decodable for bool {
-    #[inline]
-    fn decode<D: io::Read>(mut d: D) -> Result<bool> {
-        ReadExt::read_bool(&mut d)
-    }
+#[inline]
+fn decode<D: io::Read>(mut d: D) -> Result<bool> {
+ReadExt::read_bool(&mut d)
+}
 }
 
 // Strings
 impl Encodable for String {
-    #[inline]
-    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let b = self.as_bytes();
-        let vi_len = VarInt(b.len() as u64).encode(&mut s)?;
-        s.write_slice(&b)?;
-        Ok(vi_len + b.len())
-    }
+#[inline]
+fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+let b = self.as_bytes();
+let vi_len = VarInt(b.len() as u64).encode(&mut s)?;
+s.write_slice(&b)?;
+Ok(vi_len + b.len())
+}
 }
 
 impl Decodable for String {
-    #[inline]
-    fn decode<D: io::Read>(d: D) -> Result<String> {
-        String::from_utf8(Decodable::decode(d)?)
-            .map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
-    }
+#[inline]
+fn decode<D: io::Read>(d: D) -> Result<String> {
+String::from_utf8(Decodable::decode(d)?)
+.map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
+}
 }
 
 // Cow<'static, str>
 impl Encodable for Cow<'static, str> {
-    #[inline]
-    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let b = self.as_bytes();
-        let vi_len = VarInt(b.len() as u64).encode(&mut s)?;
-        s.write_slice(&b)?;
-        Ok(vi_len + b.len())
-    }
+#[inline]
+fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+let b = self.as_bytes();
+let vi_len = VarInt(b.len() as u64).encode(&mut s)?;
+s.write_slice(&b)?;
+Ok(vi_len + b.len())
+}
 }
 
 impl Decodable for Cow<'static, str> {
-    #[inline]
-    fn decode<D: io::Read>(d: D) -> Result<Cow<'static, str>> {
-        String::from_utf8(Decodable::decode(d)?)
-            .map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
-            .map(Cow::Owned)
-    }
+#[inline]
+fn decode<D: io::Read>(d: D) -> Result<Cow<'static, str>> {
+String::from_utf8(Decodable::decode(d)?)
+.map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
+.map(Cow::Owned)
+}
 }
 
 // Arrays
 macro_rules! impl_array {
-    ( $size:expr ) => {
-        impl Encodable for [u8; $size] {
-            #[inline]
-            fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
-                s.write_slice(&self[..])?;
-                Ok(self.len())
-            }
-        }
-
-        impl Decodable for [u8; $size] {
-            #[inline]
-            fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-                let mut ret = [0; $size];
-                d.read_slice(&mut ret)?;
-                Ok(ret)
-            }
-        }
-    };
+( $size:expr ) => {
+impl Encodable for [u8; $size] {
+#[inline]
+fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
+s.write_slice(&self[..])?;
+Ok(self.len())
+}
+}
+
+impl Decodable for [u8; $size] {
+#[inline]
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+let mut ret = [0; $size];
+d.read_slice(&mut ret)?;
+Ok(ret)
+}
+}
+};
 }
 
 impl_array!(2);
@@ -385,95 +385,150 @@ impl_array!(33);
 // Vectors
 #[macro_export]
 macro_rules! impl_vec {
-    ($type: ty) => {
-        impl Encodable for Vec<$type> {
-            #[inline]
-            fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-                let mut len = 0;
-                len += VarInt(self.len() as u64).encode(&mut s)?;
-                for c in self.iter() {
-                    len += c.encode(&mut s)?;
-                }
-                Ok(len)
-            }
-        }
-        impl Decodable for Vec<$type> {
-            #[inline]
-            fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-                let len = VarInt::decode(&mut d)?.0;
-                let mut ret = Vec::with_capacity(len as usize);
-                for _ in 0..len {
-                    ret.push(Decodable::decode(&mut d)?);
-                }
-                Ok(ret)
-            }
-        }
-    };
+($type: ty) => {
+impl Encodable for Vec<$type> {
+#[inline]
+fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+let mut len = 0;
+len += VarInt(self.len() as u64).encode(&mut s)?;
+for c in self.iter() {
+len += c.encode(&mut s)?;
+}
+Ok(len)
+}
+}
+impl Decodable for Vec<$type> {
+#[inline]
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+let len = VarInt::decode(&mut d)?.0;
+let mut ret = Vec::with_capacity(len as usize);
+for _ in 0..len {
+ret.push(Decodable::decode(&mut d)?);
+}
+Ok(ret)
+}
+}
+};
 }
 impl_vec!(bls::Scalar);
+impl_vec!(SocketAddr);
+impl_vec!([u8; 32]);
+
+impl Encodable for IpAddr {
+fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+let mut len = 0;
+match self {
+IpAddr::V4(ip) => {
+let version: u8 = 4;
+len += version.encode(&mut s)?;
+len += ip.octets().encode(s)?;
+}
+IpAddr::V6(ip) => {
+let version: u8 = 6;
+len += version.encode(&mut s)?;
+len += ip.octets().encode(s)?;
+}
+}
+Ok(len)
+}
+}
+
+impl Decodable for IpAddr {
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+let version: u8 = Decodable::decode(&mut d)?;
+match version {
+4 => {
+let addr: [u8; 4] = Decodable::decode(&mut d)?;
+Ok(IpAddr::from(addr))
+}
+6 => {
+let addr: [u8; 16] = Decodable::decode(&mut d)?;
+Ok(IpAddr::from(addr))
+}
+_ => Err(Error::ParseFailed("couldn't decode IpAddr")),
+}
+}
+}
+
+impl Encodable for SocketAddr {
+fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+let mut len = 0;
+len += self.ip().encode(&mut s)?;
+len += self.port().encode(s)?;
+Ok(len)
+}
+}
+
+impl Decodable for SocketAddr {
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+let ip = Decodable::decode(&mut d)?;
+let port: u16 = Decodable::decode(d)?;
+Ok(SocketAddr::new(ip, port))
+}
+}
 
 pub fn encode_with_size<S: io::Write>(data: &[u8], mut s: S) -> Result<usize> {
-    let vi_len = VarInt(data.len() as u64).encode(&mut s)?;
-    s.write_slice(&data)?;
-    Ok(vi_len + data.len())
+let vi_len = VarInt(data.len() as u64).encode(&mut s)?;
+s.write_slice(&data)?;
+Ok(vi_len + data.len())
 }
 
 impl Encodable for Vec<u8> {
-    #[inline]
-    fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
-        encode_with_size(self, s)
-    }
+#[inline]
+fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
+encode_with_size(self, s)
+}
 }
 
 impl Decodable for Vec<u8> {
-    #[inline]
-    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-        let len = VarInt::decode(&mut d)?.0 as usize;
-        let mut ret = vec![0u8; len];
-        d.read_slice(&mut ret)?;
-        Ok(ret)
-    }
+#[inline]
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+let len = VarInt::decode(&mut d)?.0 as usize;
+let mut ret = vec![0u8; len];
+d.read_slice(&mut ret)?;
+Ok(ret)
+}
 }
 
 impl Encodable for Box<[u8]> {
-    #[inline]
-    fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
-        encode_with_size(self, s)
-    }
+#[inline]
+fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
+encode_with_size(self, s)
+}
 }
 
 impl Decodable for Box<[u8]> {
-    #[inline]
-    fn decode<D: io::Read>(d: D) -> Result<Self> {
-        <Vec<u8>>::decode(d).map(From::from)
-    }
+#[inline]
+fn decode<D: io::Read>(d: D) -> Result<Self> {
+<Vec<u8>>::decode(d).map(From::from)
+}
 }
 
 // Tuples
 macro_rules! tuple_encode {
-    ($($x:ident),*) => (
-        impl <$($x: Encodable),*> Encodable for ($($x),*) {
-            #[inline]
-            #[allow(non_snake_case)]
-            fn encode<S: io::Write>(
-                &self,
-                mut s: S,
-            ) -> Result<usize> {
-                let &($(ref $x),*) = self;
-                let mut len = 0;
-                $(len += $x.encode(&mut s)?;)*
-                Ok(len)
-            }
-        }
-
-        impl<$($x: Decodable),*> Decodable for ($($x),*) {
-            #[inline]
-            #[allow(non_snake_case)]
-            fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-                Ok(($({let $x = Decodable::decode(&mut d)?; $x }),*))
-            }
-        }
-    );
+($($x:ident),*) => (
+impl <$($x: Encodable),*> Encodable for ($($x),*) {
+#[inline]
+#[allow(non_snake_case)]
+fn encode<S: io::Write>(
+&self,
+mut s: S,
+) -> Result<usize> {
+let &($(ref $x),*) = self;
+let mut len = 0;
+$(len += $x.encode(&mut s)?;)*
+Ok(len)
+}
+}
+
+impl<$($x: Decodable),*> Decodable for ($($x),*) {
+#[inline]
+#[allow(non_snake_case)]
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+Ok(($({let $x = Decodable::decode(&mut d)?; $x }),*))
+}
+}
+);
 }
 
 tuple_encode!(T0, T1);
@@ -483,286 +538,286 @@ tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
 
 #[cfg(test)]
 mod tests {
-    use super::{deserialize, serialize, Error, Result, VarInt};
-    use super::{deserialize_partial, Encodable};
-    use crate::endian::{u16_to_array_le, u32_to_array_le, u64_to_array_le};
-    use std::io;
-    use std::mem::discriminant;
-
-    #[test]
-    fn serialize_int_test() {
-        // bool
-        assert_eq!(serialize(&false), vec![0u8]);
-        assert_eq!(serialize(&true), vec![1u8]);
-        // u8
-        assert_eq!(serialize(&1u8), vec![1u8]);
-        assert_eq!(serialize(&0u8), vec![0u8]);
-        assert_eq!(serialize(&255u8), vec![255u8]);
-        // u16
-        assert_eq!(serialize(&1u16), vec![1u8, 0]);
-        assert_eq!(serialize(&256u16), vec![0u8, 1]);
-        assert_eq!(serialize(&5000u16), vec![136u8, 19]);
-        // u32
-        assert_eq!(serialize(&1u32), vec![1u8, 0, 0, 0]);
-        assert_eq!(serialize(&256u32), vec![0u8, 1, 0, 0]);
-        assert_eq!(serialize(&5000u32), vec![136u8, 19, 0, 0]);
-        assert_eq!(serialize(&500000u32), vec![32u8, 161, 7, 0]);
-        assert_eq!(serialize(&168430090u32), vec![10u8, 10, 10, 10]);
-        // i32
-        assert_eq!(serialize(&-1i32), vec![255u8, 255, 255, 255]);
-        assert_eq!(serialize(&-256i32), vec![0u8, 255, 255, 255]);
-        assert_eq!(serialize(&-5000i32), vec![120u8, 236, 255, 255]);
-        assert_eq!(serialize(&-500000i32), vec![224u8, 94, 248, 255]);
-        assert_eq!(serialize(&-168430090i32), vec![246u8, 245, 245, 245]);
-        assert_eq!(serialize(&1i32), vec![1u8, 0, 0, 0]);
-        assert_eq!(serialize(&256i32), vec![0u8, 1, 0, 0]);
-        assert_eq!(serialize(&5000i32), vec![136u8, 19, 0, 0]);
-        assert_eq!(serialize(&500000i32), vec![32u8, 161, 7, 0]);
-        assert_eq!(serialize(&168430090i32), vec![10u8, 10, 10, 10]);
-        // u64
-        assert_eq!(serialize(&1u64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
-        assert_eq!(serialize(&256u64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]);
-        assert_eq!(serialize(&5000u64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]);
-        assert_eq!(serialize(&500000u64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]);
-        assert_eq!(
-            serialize(&723401728380766730u64),
-            vec![10u8, 10, 10, 10, 10, 10, 10, 10]
-        );
-        // i64
-        assert_eq!(
-            serialize(&-1i64),
-            vec![255u8, 255, 255, 255, 255, 255, 255, 255]
-        );
-        assert_eq!(
-            serialize(&-256i64),
-            vec![0u8, 255, 255, 255, 255, 255, 255, 255]
-        );
-        assert_eq!(
-            serialize(&-5000i64),
-            vec![120u8, 236, 255, 255, 255, 255, 255, 255]
-        );
-        assert_eq!(
-            serialize(&-500000i64),
-            vec![224u8, 94, 248, 255, 255, 255, 255, 255]
-        );
-        assert_eq!(
-            serialize(&-723401728380766730i64),
-            vec![246u8, 245, 245, 245, 245, 245, 245, 245]
-        );
-        assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
-        assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]);
-        assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]);
-        assert_eq!(serialize(&500000i64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]);
-        assert_eq!(
-            serialize(&723401728380766730i64),
-            vec![10u8, 10, 10, 10, 10, 10, 10, 10]
-        );
-    }
-
-    #[test]
-    fn serialize_varint_test() {
-        assert_eq!(serialize(&VarInt(10)), vec![10u8]);
-        assert_eq!(serialize(&VarInt(0xFC)), vec![0xFCu8]);
-        assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]);
-        assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]);
-        assert_eq!(
-            serialize(&VarInt(0xF0F0F0F)),
-            vec![0xFEu8, 0xF, 0xF, 0xF, 0xF]
-        );
-        assert_eq!(
-            serialize(&VarInt(0xF0F0F0F0F0E0)),
-            vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]
-        );
-        assert_eq!(
-            test_varint_encode(0xFF, &u64_to_array_le(0x100000000)).unwrap(),
-            VarInt(0x100000000)
-        );
-        assert_eq!(
-            test_varint_encode(0xFE, &u64_to_array_le(0x10000)).unwrap(),
-            VarInt(0x10000)
-        );
-        assert_eq!(
-            test_varint_encode(0xFD, &u64_to_array_le(0xFD)).unwrap(),
-            VarInt(0xFD)
-        );
-
-        // Test that length calc is working correctly
-        test_varint_len(VarInt(0), 1);
-        test_varint_len(VarInt(0xFC), 1);
-        test_varint_len(VarInt(0xFD), 3);
-        test_varint_len(VarInt(0xFFFF), 3);
-        test_varint_len(VarInt(0x10000), 5);
-        test_varint_len(VarInt(0xFFFFFFFF), 5);
-        test_varint_len(VarInt(0xFFFFFFFF + 1), 9);
-        test_varint_len(VarInt(u64::max_value()), 9);
-    }
-
-    fn test_varint_len(varint: VarInt, expected: usize) {
-        let mut encoder = io::Cursor::new(vec![]);
-        assert_eq!(varint.encode(&mut encoder).unwrap(), expected);
-        assert_eq!(varint.len(), expected);
-    }
-
-    fn test_varint_encode(n: u8, x: &[u8]) -> Result<VarInt> {
-        let mut input = [0u8; 9];
-        input[0] = n;
-        input[1..x.len() + 1].copy_from_slice(x);
-        deserialize_partial::<VarInt>(&input).map(|t| t.0)
-    }
-
-    #[test]
-    fn deserialize_nonminimal_vec() {
-        // Check the edges for variant int
-        assert_eq!(
-            discriminant(&test_varint_encode(0xFF, &u64_to_array_le(0x100000000 - 1)).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&test_varint_encode(0xFE, &u32_to_array_le(0x10000 - 1)).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&test_varint_encode(0xFD, &u16_to_array_le(0xFD - 1)).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0x00, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(
-                &deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
-                    .unwrap_err()
-            ),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(
-                &deserialize::<Vec<u8>>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00])
-                    .unwrap_err()
-            ),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-
-        let mut vec_256 = vec![0; 259];
-        vec_256[0] = 0xfd;
-        vec_256[1] = 0x00;
-        vec_256[2] = 0x01;
-        assert!(deserialize::<Vec<u8>>(&vec_256).is_ok());
-
-        let mut vec_253 = vec![0; 256];
-        vec_253[0] = 0xfd;
-        vec_253[1] = 0xfd;
-        vec_253[2] = 0x00;
-        assert!(deserialize::<Vec<u8>>(&vec_253).is_ok());
-    }
-
-    #[test]
-    fn serialize_vector_test() {
-        assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]);
-        // TODO: test vectors of more interesting objects
-    }
-
-    #[test]
-    fn serialize_strbuf_test() {
-        assert_eq!(
-            serialize(&"Andrew".to_string()),
-            vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]
-        );
-    }
-
-    #[test]
-    fn deserialize_int_test() {
-        // bool
-        assert!((deserialize(&[58u8, 0]) as Result<bool>).is_err());
-        assert_eq!(deserialize(&[58u8]).ok(), Some(true));
-        assert_eq!(deserialize(&[1u8]).ok(), Some(true));
-        assert_eq!(deserialize(&[0u8]).ok(), Some(false));
-        assert!((deserialize(&[0u8, 1]) as Result<bool>).is_err());
-
-        // u8
-        assert_eq!(deserialize(&[58u8]).ok(), Some(58u8));
-
-        // u16
-        assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16));
-        assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16));
-        assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16));
-        let failure16: Result<u16> = deserialize(&[1u8]);
-        assert!(failure16.is_err());
-
-        // u32
-        assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32));
-        assert_eq!(
-            deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(),
-            Some(0xCDAB0DA0u32)
-        );
-        let failure32: Result<u32> = deserialize(&[1u8, 2, 3]);
-        assert!(failure32.is_err());
-        // TODO: test negative numbers
-        assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32));
-        assert_eq!(
-            deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(),
-            Some(0x2DAB0DA0i32)
-        );
-        let failurei32: Result<i32> = deserialize(&[1u8, 2, 3]);
-        assert!(failurei32.is_err());
-
-        // u64
-        assert_eq!(
-            deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(),
-            Some(0xCDABu64)
-        );
-        assert_eq!(
-            deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(),
-            Some(0x99000099CDAB0DA0u64)
-        );
-        let failure64: Result<u64> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
-        assert!(failure64.is_err());
-        // TODO: test negative numbers
-        assert_eq!(
-            deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(),
-            Some(0xCDABi64)
-        );
-        assert_eq!(
-            deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(),
-            Some(-0x66ffff663254f260i64)
-        );
-        let failurei64: Result<i64> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
-        assert!(failurei64.is_err());
-    }
-
-    #[test]
-    fn deserialize_vec_test() {
-        assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4]));
-        assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result<Vec<u8>>).is_err());
-    }
-
-    #[test]
-    fn deserialize_strbuf_test() {
-        assert_eq!(
-            deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
-            Some("Andrew".to_string())
-        );
-        assert_eq!(
-            deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
-            Some(::std::borrow::Cow::Borrowed("Andrew"))
-        );
-    }
+use super::{deserialize, serialize, Error, Result, VarInt};
+use super::{deserialize_partial, Encodable};
+use crate::endian::{u16_to_array_le, u32_to_array_le, u64_to_array_le};
+use std::io;
+use std::mem::discriminant;
+
+#[test]
+fn serialize_int_test() {
+// bool
+assert_eq!(serialize(&false), vec![0u8]);
+assert_eq!(serialize(&true), vec![1u8]);
+// u8
+assert_eq!(serialize(&1u8), vec![1u8]);
+assert_eq!(serialize(&0u8), vec![0u8]);
+assert_eq!(serialize(&255u8), vec![255u8]);
+// u16
+assert_eq!(serialize(&1u16), vec![1u8, 0]);
+assert_eq!(serialize(&256u16), vec![0u8, 1]);
+assert_eq!(serialize(&5000u16), vec![136u8, 19]);
+// u32
+assert_eq!(serialize(&1u32), vec![1u8, 0, 0, 0]);
+assert_eq!(serialize(&256u32), vec![0u8, 1, 0, 0]);
+assert_eq!(serialize(&5000u32), vec![136u8, 19, 0, 0]);
+assert_eq!(serialize(&500000u32), vec![32u8, 161, 7, 0]);
+assert_eq!(serialize(&168430090u32), vec![10u8, 10, 10, 10]);
+// i32
+assert_eq!(serialize(&-1i32), vec![255u8, 255, 255, 255]);
+assert_eq!(serialize(&-256i32), vec![0u8, 255, 255, 255]);
+assert_eq!(serialize(&-5000i32), vec![120u8, 236, 255, 255]);
+assert_eq!(serialize(&-500000i32), vec![224u8, 94, 248, 255]);
+assert_eq!(serialize(&-168430090i32), vec![246u8, 245, 245, 245]);
+assert_eq!(serialize(&1i32), vec![1u8, 0, 0, 0]);
+assert_eq!(serialize(&256i32), vec![0u8, 1, 0, 0]);
+assert_eq!(serialize(&5000i32), vec![136u8, 19, 0, 0]);
+assert_eq!(serialize(&500000i32), vec![32u8, 161, 7, 0]);
+assert_eq!(serialize(&168430090i32), vec![10u8, 10, 10, 10]);
+// u64
+assert_eq!(serialize(&1u64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
+assert_eq!(serialize(&256u64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]);
+assert_eq!(serialize(&5000u64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]);
+assert_eq!(serialize(&500000u64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]);
+assert_eq!(
+serialize(&723401728380766730u64),
+vec![10u8, 10, 10, 10, 10, 10, 10, 10]
+);
+// i64
+assert_eq!(
+serialize(&-1i64),
+vec![255u8, 255, 255, 255, 255, 255, 255, 255]
+);
+assert_eq!(
+serialize(&-256i64),
+vec![0u8, 255, 255, 255, 255, 255, 255, 255]
+);
+assert_eq!(
+serialize(&-5000i64),
+vec![120u8, 236, 255, 255, 255, 255, 255, 255]
+);
+assert_eq!(
+serialize(&-500000i64),
+vec![224u8, 94, 248, 255, 255, 255, 255, 255]
+);
+assert_eq!(
+serialize(&-723401728380766730i64),
+vec![246u8, 245, 245, 245, 245, 245, 245, 245]
+);
+assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
+assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]);
+assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]);
+assert_eq!(serialize(&500000i64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]);
+assert_eq!(
+serialize(&723401728380766730i64),
+vec![10u8, 10, 10, 10, 10, 10, 10, 10]
+);
+}
+
+#[test]
+fn serialize_varint_test() {
+assert_eq!(serialize(&VarInt(10)), vec![10u8]);
+assert_eq!(serialize(&VarInt(0xFC)), vec![0xFCu8]);
+assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]);
+assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]);
+assert_eq!(
+serialize(&VarInt(0xF0F0F0F)),
+vec![0xFEu8, 0xF, 0xF, 0xF, 0xF]
+);
+assert_eq!(
+serialize(&VarInt(0xF0F0F0F0F0E0)),
+vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]
+);
+assert_eq!(
+test_varint_encode(0xFF, &u64_to_array_le(0x100000000)).unwrap(),
+VarInt(0x100000000)
+);
+assert_eq!(
+test_varint_encode(0xFE, &u64_to_array_le(0x10000)).unwrap(),
+VarInt(0x10000)
+);
+assert_eq!(
+test_varint_encode(0xFD, &u64_to_array_le(0xFD)).unwrap(),
+VarInt(0xFD)
+);
+
+// Test that length calc is working correctly
+test_varint_len(VarInt(0), 1);
+test_varint_len(VarInt(0xFC), 1);
+test_varint_len(VarInt(0xFD), 3);
+test_varint_len(VarInt(0xFFFF), 3);
+test_varint_len(VarInt(0x10000), 5);
+test_varint_len(VarInt(0xFFFFFFFF), 5);
+test_varint_len(VarInt(0xFFFFFFFF + 1), 9);
+test_varint_len(VarInt(u64::max_value()), 9);
+}
+
+fn test_varint_len(varint: VarInt, expected: usize) {
+let mut encoder = io::Cursor::new(vec![]);
+assert_eq!(varint.encode(&mut encoder).unwrap(), expected);
+assert_eq!(varint.len(), expected);
+}
+
+fn test_varint_encode(n: u8, x: &[u8]) -> Result<VarInt> {
+let mut input = [0u8; 9];
+input[0] = n;
+input[1..x.len() + 1].copy_from_slice(x);
+deserialize_partial::<VarInt>(&input).map(|t| t.0)
+}
+
+#[test]
+fn deserialize_nonminimal_vec() {
+// Check the edges for variant int
+assert_eq!(
+discriminant(&test_varint_encode(0xFF, &u64_to_array_le(0x100000000 - 1)).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&test_varint_encode(0xFE, &u32_to_array_le(0x10000 - 1)).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&test_varint_encode(0xFD, &u16_to_array_le(0xFD - 1)).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0x00, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(
+&deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+.unwrap_err()
+),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(
+&deserialize::<Vec<u8>>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00])
+.unwrap_err()
+),
+discriminant(&Error::NonMinimalVarInt)
+);
+
+let mut vec_256 = vec![0; 259];
+vec_256[0] = 0xfd;
+vec_256[1] = 0x00;
+vec_256[2] = 0x01;
+assert!(deserialize::<Vec<u8>>(&vec_256).is_ok());
+
+let mut vec_253 = vec![0; 256];
+vec_253[0] = 0xfd;
+vec_253[1] = 0xfd;
+vec_253[2] = 0x00;
+assert!(deserialize::<Vec<u8>>(&vec_253).is_ok());
+}
+
+#[test]
+fn serialize_vector_test() {
+assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]);
+// TODO: test vectors of more interesting objects
+}
+
+#[test]
+fn serialize_strbuf_test() {
+assert_eq!(
+serialize(&"Andrew".to_string()),
+vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]
+);
+}
+
+#[test]
+fn deserialize_int_test() {
+// bool
+assert!((deserialize(&[58u8, 0]) as Result<bool>).is_err());
+assert_eq!(deserialize(&[58u8]).ok(), Some(true));
+assert_eq!(deserialize(&[1u8]).ok(), Some(true));
+assert_eq!(deserialize(&[0u8]).ok(), Some(false));
+assert!((deserialize(&[0u8, 1]) as Result<bool>).is_err());
+
+// u8
+assert_eq!(deserialize(&[58u8]).ok(), Some(58u8));
+
+// u16
+assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16));
+assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16));
+assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16));
+let failure16: Result<u16> = deserialize(&[1u8]);
+assert!(failure16.is_err());
+
+// u32
+assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32));
+assert_eq!(
+deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(),
+Some(0xCDAB0DA0u32)
+);
+let failure32: Result<u32> = deserialize(&[1u8, 2, 3]);
+assert!(failure32.is_err());
+// TODO: test negative numbers
+assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32));
+assert_eq!(
+deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(),
+Some(0x2DAB0DA0i32)
+);
+let failurei32: Result<i32> = deserialize(&[1u8, 2, 3]);
+assert!(failurei32.is_err());
+
+// u64
+assert_eq!(
+deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(),
+Some(0xCDABu64)
+);
+assert_eq!(
+deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(),
+Some(0x99000099CDAB0DA0u64)
+);
+let failure64: Result<u64> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
+assert!(failure64.is_err());
+// TODO: test negative numbers
+assert_eq!(
+deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(),
+Some(0xCDABi64)
+);
+assert_eq!(
+deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(),
+Some(-0x66ffff663254f260i64)
+);
+let failurei64: Result<i64> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
+assert!(failurei64.is_err());
+}
+
+#[test]
+fn deserialize_vec_test() {
+assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4]));
+assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result<Vec<u8>>).is_err());
+}
+
+#[test]
+fn deserialize_strbuf_test() {
+assert_eq!(
+deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
+Some("Andrew".to_string())
+);
+assert_eq!(
+deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
+Some(::std::borrow::Cow::Borrowed("Andrew"))
+);
+}
 }

+ 7 - 0
src/system/mod.rs

@@ -0,0 +1,7 @@
+pub mod stoppable_task;
+pub mod subscriber;
+pub mod types;
+
+pub use stoppable_task::{StoppableTask, StoppableTaskPtr};
+pub use subscriber::{Subscriber, SubscriberPtr, Subscription};
+pub use types::ExecutorPtr;

+ 50 - 0
src/system/stoppable_task.rs

@@ -0,0 +1,50 @@
+use async_executor::Executor;
+use futures::Future;
+use futures::FutureExt;
+use std::sync::Arc;
+
+pub type StoppableTaskPtr = Arc<StoppableTask>;
+
+pub struct StoppableTask {
+    stop_send: async_channel::Sender<()>,
+    stop_recv: async_channel::Receiver<()>,
+}
+
+impl StoppableTask {
+    pub fn new() -> Arc<Self> {
+        let (stop_send, stop_recv) = async_channel::unbounded();
+        Arc::new(Self {
+            stop_send,
+            stop_recv,
+        })
+    }
+
+    pub async fn stop(&self) {
+        // Ignore any errors from this send
+        let _ = self.stop_send.send(()).await;
+    }
+
+    pub fn start<'a, MainFut, StopFut, StopFn, Error>(
+        self: Arc<Self>,
+        main: MainFut,
+        stop_handler: StopFn,
+        stop_value: Error,
+        executor: Arc<Executor<'a>>,
+    ) where
+        MainFut: Future<Output = std::result::Result<(), Error>> + Send + 'a,
+        StopFut: Future<Output = ()> + Send,
+        StopFn: FnOnce(std::result::Result<(), Error>) -> StopFut + Send + 'a,
+        Error: std::error::Error + Send + 'a,
+    {
+        executor
+            .spawn(async move {
+                let result = futures::select! {
+                    _ = self.stop_recv.recv().fuse() => Err(stop_value),
+                    result = main.fuse() => result
+                };
+
+                stop_handler(result).await;
+            })
+            .detach();
+    }
+}

+ 79 - 0
src/system/subscriber.rs

@@ -0,0 +1,79 @@
+use async_std::sync::Mutex;
+use rand::Rng;
+use std::collections::HashMap;
+use std::sync::Arc;
+
+pub type SubscriberPtr<T> = Arc<Subscriber<T>>;
+
+pub type SubscriptionID = u64;
+
+pub struct Subscription<T> {
+    id: SubscriptionID,
+    recv_queue: async_channel::Receiver<Arc<T>>,
+    parent: Arc<Subscriber<T>>,
+}
+
+impl<T> Subscription<T> {
+    pub async fn receive(&self) -> Arc<T> {
+        let message_result = self.recv_queue.recv().await;
+
+        match message_result {
+            Ok(message_result) => message_result,
+            Err(err) => {
+                panic!("MessageSubscription::receive() recv_queue failed! {}", err);
+            }
+        }
+    }
+
+    // Must be called manually since async Drop is not possible in Rust
+    pub async fn unsubscribe(&self) {
+        self.parent.clone().unsubscribe(self.id).await
+    }
+}
+
+// Simple broadcast (publish-subscribe) class
+pub struct Subscriber<T> {
+    subs: Mutex<HashMap<u64, async_channel::Sender<Arc<T>>>>,
+}
+
+impl<T> Subscriber<T> {
+    pub fn new() -> Arc<Self> {
+        Arc::new(Self {
+            subs: Mutex::new(HashMap::new()),
+        })
+    }
+
+    pub fn random_id() -> SubscriptionID {
+        let mut rng = rand::thread_rng();
+        rng.gen()
+    }
+
+    pub async fn subscribe(self: Arc<Self>) -> Subscription<T> {
+        let (sender, recvr) = async_channel::unbounded();
+
+        let sub_id = Self::random_id();
+
+        self.subs.lock().await.insert(sub_id, sender);
+
+        Subscription {
+            id: sub_id,
+            recv_queue: recvr,
+            parent: self.clone(),
+        }
+    }
+
+    async fn unsubscribe(self: Arc<Self>, sub_id: SubscriptionID) {
+        self.subs.lock().await.remove(&sub_id);
+    }
+
+    pub async fn notify(&self, message_result: Arc<T>) {
+        for sub in (*self.subs.lock().await).values() {
+            match sub.send(message_result.clone()).await {
+                Ok(()) => {}
+                Err(err) => {
+                    panic!("Error returned sending message in notify() call! {}", err);
+                }
+            }
+        }
+    }
+}

+ 4 - 0
src/system/types.rs

@@ -0,0 +1,4 @@
+use smol::Executor;
+use std::sync::Arc;
+
+pub type ExecutorPtr<'a> = Arc<Executor<'a>>;

+ 89 - 0
src/utility.rs

@@ -0,0 +1,89 @@
+use std::collections::HashMap;
+use std::fs::OpenOptions;
+use std::io::prelude::*;
+use std::net::SocketAddr;
+use std::sync::atomic::AtomicU64;
+use std::sync::Arc;
+use std::time::{SystemTime, UNIX_EPOCH};
+
+use rand::seq::SliceRandom;
+use smol::{Executor, Task};
+
+//use crate::{net, serial, Channel, ClientProtocol, Result, SlabsManagerSafe};
+use crate::{net::messages as net, serial, Result};
+
+pub type ConnectionsMap = std::sync::Arc<
+    async_std::sync::Mutex<HashMap<SocketAddr, async_channel::Sender<net::Message>>>,
+>;
+
+pub type AddrsStorage = std::sync::Arc<async_std::sync::Mutex<Vec<SocketAddr>>>;
+
+pub type Clock = std::sync::Arc<AtomicU64>;
+
+pub fn get_current_time() -> u64 {
+    let start = SystemTime::now();
+    let since_the_epoch = start
+        .duration_since(UNIX_EPOCH)
+        .expect("Incorrect system clock: time went backwards");
+    let in_ms =
+        since_the_epoch.as_secs() * 1000 + since_the_epoch.subsec_nanos() as u64 / 1_000_000;
+    return in_ms;
+}
+
+pub fn save_to_addrs_store(stored_addrs: &Vec<SocketAddr>) -> Result<()> {
+    let mut writer = OpenOptions::new()
+        .write(true)
+        .create(true)
+        .open("addrs.dps")?;
+    let buffer = serial::serialize(stored_addrs);
+    writer.write_all(&buffer)?;
+    Ok(())
+}
+
+pub fn load_stored_addrs() -> Result<Vec<SocketAddr>> {
+    let mut reader = OpenOptions::new()
+        .read(true)
+        .write(true)
+        .create(true)
+        .open("addrs.dps")?;
+    let mut buffer = Vec::new();
+    reader.read_to_end(&mut buffer)?;
+    if !buffer.is_empty() {
+        let addrs: Vec<SocketAddr> = serial::deserialize(&buffer)?;
+        Ok(addrs)
+    } else {
+        Ok(vec![])
+    }
+}
+
+pub async fn start_connections_process(
+    //slabman: SlabsManagerSafe,
+    stored_addrs: Vec<SocketAddr>,
+    connections: ConnectionsMap,
+    _accept_addr: SocketAddr,
+    _channel_secret: [u8; 32],
+    executor: Arc<Executor<'_>>,
+) -> Vec<Task<()>> {
+    let mut tasks: Vec<Task<()>> = vec![];
+    for _ in 0..10 {
+        let connections_cloned = connections.clone();
+        let stored_addrs_cloned = stored_addrs.clone();
+        //let slabman_cloned = slabman.clone();
+        //let channel_secret = channel_secret.clone();
+        let task = executor.spawn(async move {
+            loop {
+                let addr = stored_addrs_cloned.choose(&mut rand::thread_rng()).unwrap();
+                if !connections_cloned.lock().await.contains_key(addr) {
+                    /*let mut protocol =
+                        ClientProtocol::new(connections_cloned.clone(), slabman_cloned.clone());
+                    protocol
+                        .start(addr.clone(), accept_addr.clone(), &channel_secret)
+                        .await;
+                        */
+                }
+            }
+        });
+        tasks.push(task);
+    }
+    tasks
+}

+ 1 - 6
src/vm.rs

@@ -1,9 +1,4 @@
-use bellman::{
-    gadgets::{
-        Assignment,
-    },
-    groth16, Circuit, ConstraintSystem, SynthesisError,
-};
+use bellman::{gadgets::Assignment, groth16, Circuit, ConstraintSystem, SynthesisError};
 use bls12_381::Bls12;
 use bls12_381::Scalar;
 use ff::{Field, PrimeField};

+ 1 - 2
src/vm_serial.rs

@@ -1,8 +1,7 @@
 use crate::error::{Error, Result};
 use crate::serial::{Decodable, Encodable, ReadExt, VarInt};
 use crate::vm::{
-    AllocType, ConstraintInstruction, CryptoOperation, VariableIndex, VariableRef, 
-    ZKVirtualMachine,
+    AllocType, ConstraintInstruction, CryptoOperation, VariableIndex, VariableRef, ZKVirtualMachine,
 };
 use crate::{impl_vec, ZKContract, ZKProof};
 use bellman::groth16;