gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-depolymerization] branch master updated (42ba478 -> 52e7d8b)


From: gnunet
Subject: [taler-depolymerization] branch master updated (42ba478 -> 52e7d8b)
Date: Thu, 23 Nov 2023 05:23:36 +0100

This is an automated email from the git hooks/post-receive script.

antoine pushed a change to branch master
in repository depolymerization.

    from 42ba478  Support ethereum 1.13.5
     new 50be772  Test support for bitcoind 25.1
     new 52e7d8b  Fix dirty fix

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 Cargo.lock                  |  32 ++---
 README.md                   |   3 +-
 btc-wire/src/segwit.rs      | 343 ++++++++++++++++++++++----------------------
 eth-wire/src/rpc.rs         |  17 +--
 instrumentation/src/eth.rs  |   8 +-
 instrumentation/src/main.rs |   3 +-
 script/prepare.sh           |  10 +-
 7 files changed, 204 insertions(+), 212 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 0f18a97..0677e34 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -604,9 +604,9 @@ dependencies = [
 
 [[package]]
 name = "data-encoding"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
+checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
 
 [[package]]
 name = "deadpool"
@@ -818,9 +818,9 @@ checksum = 
"3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 dependencies = [
  "percent-encoding",
 ]
@@ -1070,9 +1070,9 @@ checksum = 
"b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 
 [[package]]
 name = "idna"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
 dependencies = [
  "unicode-bidi",
  "unicode-normalization",
@@ -1393,9 +1393,9 @@ dependencies = [
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "phf"
@@ -1830,18 +1830,18 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.192"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.192"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2339,9 +2339,9 @@ dependencies = [
 
 [[package]]
 name = "url"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -2458,9 +2458,9 @@ dependencies = [
 
 [[package]]
 name = "webpki-roots"
-version = "0.25.2"
+version = "0.25.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
+checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10"
 
 [[package]]
 name = "whoami"
diff --git a/README.md b/README.md
index d9aa59d..8235867 100644
--- a/README.md
+++ b/README.md
@@ -33,11 +33,12 @@ make install
 Depolymerizer require:
 
 - taler-config from [Taler exchange](https://git.taler.net/exchange.git/)
+ ap
 - PostgreSQL
 
 #### Bitcoin
 
-[Bitcoind](https://bitcoincore.org/) version 24.1 is expected
+[Bitcoind](https://bitcoincore.org/) version 25.1 is expected
 
 #### Ethereum
 
diff --git a/btc-wire/src/segwit.rs b/btc-wire/src/segwit.rs
index 5b7414d..e754d71 100644
--- a/btc-wire/src/segwit.rs
+++ b/btc-wire/src/segwit.rs
@@ -1,171 +1,172 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2022 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU Affero General Public License as published by the Free 
Software
-  Foundation; either version 3, or (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
-
-  You should have received a copy of the GNU Affero General Public License 
along with
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-*/
-use bech32::{u5, FromBase32, ToBase32, Variant};
-use common::{rand::rngs::OsRng, rand_slice};
-
-/// Encode metadata into a segwit address
-pub fn encode_segwit_addr(hrp: &str, metada: &[u8; 20]) -> String {
-    // We use the version 0 with bech32 encoding
-    let mut buf = vec![u5::try_from_u8(0).unwrap()];
-    buf.extend_from_slice(&metada.to_base32());
-    bech32::encode(hrp, buf, Variant::Bech32).unwrap()
-}
-
-/// Encode half of a 32B key into a segwit address
-fn encode_segwit_key_half(
-    hrp: &str,
-    is_first: bool,
-    prefix: &[u8; 4],
-    key_half: &[u8; 16],
-) -> String {
-    // Combine prefix and the key half
-    let mut buf = [0u8; 20];
-    buf[..4].copy_from_slice(prefix);
-    buf[4..].copy_from_slice(key_half);
-    // Toggle first bit for ordering
-    if is_first {
-        buf[0] &= 0b0111_1111 // Unset first bit
-    } else {
-        buf[0] |= 0b1000_0000 // Set first bit
-    }
-    // Encode into an fake segwit address
-    encode_segwit_addr(hrp, &buf)
-}
-
-/// Encode a 32B key into two segwit adresses
-pub fn encode_segwit_key(hrp: &str, msg: &[u8; 32]) -> [String; 2] {
-    // Generate a random prefix
-    let prefix = rand_slice();
-    // Split key in half;
-    let split: (&[u8; 16], &[u8; 16]) =
-        (msg[..16].try_into().unwrap(), msg[16..].try_into().unwrap());
-    [
-        encode_segwit_key_half(hrp, true, &prefix, split.0),
-        encode_segwit_key_half(hrp, false, &prefix, split.1),
-    ]
-}
-
-#[derive(Debug, Clone, thiserror::Error)]
-pub enum DecodeSegWitErr {
-    #[error("There is less than 2 segwit addresses")]
-    MissingSegWitAddress,
-    #[error("No adresses are sharing a common prefix")]
-    NoPrefixMatch,
-    #[error("More than two addresses are sharing a common prefix")]
-    PrefixCollision,
-}
-
-/// Decode a 32B key into from adresses
-pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) -> Result<[u8; 32], 
DecodeSegWitErr> {
-    // Extract parts from every addresses
-    let decoded: Vec<(bool, [u8; 4], [u8; 16])> = segwit_addrs
-        .iter()
-        .filter_map(|addr| {
-            bech32::decode(addr.as_ref()).ok().and_then(|(_, wp, _)| {
-                // Skip version
-                let pg: Vec<u8> = Vec::from_base32(&wp[1..]).unwrap();
-                if pg.len() == 20 {
-                    let mut prefix: [u8; 4] = pg[..4].try_into().unwrap();
-                    let key_half: [u8; 16] = pg[4..].try_into().unwrap();
-                    let is_first = !pg[0] & 0b1000_0000 == 0;
-                    // Clear first bit
-                    prefix[0] &= 0b0111_1111;
-                    Some((is_first, prefix, key_half))
-                } else {
-                    None
-                }
-            })
-        })
-        .collect();
-
-    if decoded.len() < 2 {
-        return Err(DecodeSegWitErr::MissingSegWitAddress);
-    }
-    // Keep only the addresses with duplicated prefix
-    // TODO use sort_unstable_by and partition_dedup_by_key when stable
-    let matches: Vec<&(bool, [u8; 4], [u8; 16])> = decoded
-        .iter()
-        .filter(|(_, prefix, _)| {
-            decoded
-                .iter()
-                .filter(|(_, other, _)| other == prefix)
-                .count()
-                > 1
-        })
-        .collect();
-
-    if matches.len() > 2 {
-        return Err(DecodeSegWitErr::PrefixCollision);
-    } else if matches.len() < 2 {
-        return Err(DecodeSegWitErr::MissingSegWitAddress);
-    }
-
-    let mut key = [0; 32];
-    for (is_first, _, half) in matches {
-        key[*is_first as usize * 16..][..16].copy_from_slice(half);
-    }
-    Ok(key)
-}
-
-// TODO find a way to hide that function while using it in test and benchmark
-pub fn rand_addresses(hrp: &str, key: &[u8; 32]) -> Vec<String> {
-    use common::rand::prelude::SliceRandom;
-
-    let mut rng_address: Vec<String> =
-        std::iter::repeat_with(|| encode_segwit_addr(hrp, &rand_slice()))
-            .take(2)
-            .collect();
-
-    let mut addresses = encode_segwit_key(hrp, key).to_vec();
-    addresses.append(&mut rng_address);
-    addresses.shuffle(&mut OsRng);
-    addresses
-}
-
-#[cfg(test)]
-mod test {
-    use common::{
-        rand::{prelude::SliceRandom, rngs::OsRng},
-        rand_slice,
-    };
-
-    use crate::segwit::{decode_segwit_msg, encode_segwit_key, rand_addresses};
-
-    #[test]
-    fn test_shuffle() {
-        for _ in 0..1000 {
-            let key = rand_slice();
-            let mut addresses = encode_segwit_key("test", &key);
-            addresses.shuffle(&mut OsRng);
-            let decoded =
-                decode_segwit_msg(&addresses.iter().map(|s| 
s.as_str()).collect::<Vec<&str>>())
-                    .unwrap();
-            assert_eq!(key, decoded);
-        }
-    }
-
-    #[test]
-    fn test_shuffle_many() {
-        for _ in 0..1000 {
-            let key = rand_slice();
-            let addresses = rand_addresses("test", &key);
-            let decoded =
-                decode_segwit_msg(&addresses.iter().map(|s| 
s.as_str()).collect::<Vec<&str>>())
-                    .unwrap();
-            assert_eq!(key, decoded);
-        }
-    }
-}
+/*
+  This file is part of TALER
+  Copyright (C) 2022 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+use bech32::{u5, FromBase32, ToBase32, Variant};
+use common::{rand::rngs::OsRng, rand_slice};
+use std::cmp::Ordering;
+
+/// Encode metadata into a segwit address
+pub fn encode_segwit_addr(hrp: &str, metada: &[u8; 20]) -> String {
+    // We use the version 0 with bech32 encoding
+    let mut buf = vec![u5::try_from_u8(0).unwrap()];
+    buf.extend_from_slice(&metada.to_base32());
+    bech32::encode(hrp, buf, Variant::Bech32).unwrap()
+}
+
+/// Encode half of a 32B key into a segwit address
+fn encode_segwit_key_half(
+    hrp: &str,
+    is_first: bool,
+    prefix: &[u8; 4],
+    key_half: &[u8; 16],
+) -> String {
+    // Combine prefix and the key half
+    let mut buf = [0u8; 20];
+    buf[..4].copy_from_slice(prefix);
+    buf[4..].copy_from_slice(key_half);
+    // Toggle first bit for ordering
+    if is_first {
+        buf[0] &= 0b0111_1111 // Unset first bit
+    } else {
+        buf[0] |= 0b1000_0000 // Set first bit
+    }
+    // Encode into an fake segwit address
+    encode_segwit_addr(hrp, &buf)
+}
+
+/// Encode a 32B key into two segwit adresses
+pub fn encode_segwit_key(hrp: &str, msg: &[u8; 32]) -> [String; 2] {
+    // Generate a random prefix
+    let prefix = rand_slice();
+    // Split key in half;
+    let split: (&[u8; 16], &[u8; 16]) =
+        (msg[..16].try_into().unwrap(), msg[16..].try_into().unwrap());
+    [
+        encode_segwit_key_half(hrp, true, &prefix, split.0),
+        encode_segwit_key_half(hrp, false, &prefix, split.1),
+    ]
+}
+
+#[derive(Debug, Clone, thiserror::Error)]
+pub enum DecodeSegWitErr {
+    #[error("There is less than 2 segwit addresses")]
+    MissingSegWitAddress,
+    #[error("No adresses are sharing a common prefix")]
+    NoPrefixMatch,
+    #[error("More than two addresses are sharing a common prefix")]
+    PrefixCollision,
+}
+
+/// Decode a 32B key into from adresses
+pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) -> Result<[u8; 32], 
DecodeSegWitErr> {
+    // Extract parts from every addresses
+    let decoded: Vec<(bool, [u8; 4], [u8; 16])> = segwit_addrs
+        .iter()
+        .filter_map(|addr| {
+            bech32::decode(addr.as_ref()).ok().and_then(|(_, wp, _)| {
+                // Skip version
+                let pg: Vec<u8> = Vec::from_base32(&wp[1..]).unwrap();
+                if pg.len() == 20 {
+                    let mut prefix: [u8; 4] = pg[..4].try_into().unwrap();
+                    let key_half: [u8; 16] = pg[4..].try_into().unwrap();
+                    let is_first = !pg[0] & 0b1000_0000 == 0;
+                    // Clear first bit
+                    prefix[0] &= 0b0111_1111;
+                    Some((is_first, prefix, key_half))
+                } else {
+                    None
+                }
+            })
+        })
+        .collect();
+
+    if decoded.len() < 2 {
+        return Err(DecodeSegWitErr::MissingSegWitAddress);
+    }
+    // Keep only the addresses with duplicated prefix
+    // TODO use sort_unstable_by and partition_dedup_by_key when stable
+    let matches: Vec<&(bool, [u8; 4], [u8; 16])> = decoded
+        .iter()
+        .filter(|(_, prefix, _)| {
+            decoded
+                .iter()
+                .filter(|(_, other, _)| other == prefix)
+                .count()
+                > 1
+        })
+        .collect();
+
+    match matches.len().cmp(&2) {
+        Ordering::Equal => {
+            let mut key = [0; 32];
+            for (is_first, _, half) in matches {
+                key[*is_first as usize * 16..][..16].copy_from_slice(half);
+            }
+            Ok(key)
+        }
+        Ordering::Greater => Err(DecodeSegWitErr::PrefixCollision),
+        Ordering::Less => Err(DecodeSegWitErr::MissingSegWitAddress),
+    }
+}
+
+// TODO find a way to hide that function while using it in test and benchmark
+pub fn rand_addresses(hrp: &str, key: &[u8; 32]) -> Vec<String> {
+    use common::rand::prelude::SliceRandom;
+
+    let mut rng_address: Vec<String> =
+        std::iter::repeat_with(|| encode_segwit_addr(hrp, &rand_slice()))
+            .take(2)
+            .collect();
+
+    let mut addresses = encode_segwit_key(hrp, key).to_vec();
+    addresses.append(&mut rng_address);
+    addresses.shuffle(&mut OsRng);
+    addresses
+}
+
+#[cfg(test)]
+mod test {
+    use common::{
+        rand::{prelude::SliceRandom, rngs::OsRng},
+        rand_slice,
+    };
+
+    use crate::segwit::{decode_segwit_msg, encode_segwit_key, rand_addresses};
+
+    #[test]
+    fn test_shuffle() {
+        for _ in 0..1000 {
+            let key = rand_slice();
+            let mut addresses = encode_segwit_key("test", &key);
+            addresses.shuffle(&mut OsRng);
+            let decoded =
+                decode_segwit_msg(&addresses.iter().map(|s| 
s.as_str()).collect::<Vec<&str>>())
+                    .unwrap();
+            assert_eq!(key, decoded);
+        }
+    }
+
+    #[test]
+    fn test_shuffle_many() {
+        for _ in 0..1000 {
+            let key = rand_slice();
+            let addresses = rand_addresses("test", &key);
+            let decoded =
+                decode_segwit_msg(&addresses.iter().map(|s| 
s.as_str()).collect::<Vec<&str>>())
+                    .unwrap();
+            assert_eq!(key, decoded);
+        }
+    }
+}
diff --git a/eth-wire/src/rpc.rs b/eth-wire/src/rpc.rs
index 95d3428..66b16b0 100644
--- a/eth-wire/src/rpc.rs
+++ b/eth-wire/src/rpc.rs
@@ -180,14 +180,7 @@ impl Rpc {
     }
 
     pub fn subscribe_new_head(&mut self) -> Result<RpcStream<Nothing>> {
-        self.send("eth_subscribe", &["newHeads"])?;
-        let id = loop {
-            match self.receive::<SubscribeDirtyFix>()? {
-                SubscribeDirtyFix::Fix(_) => { /* TODO debug */ }
-                SubscribeDirtyFix::Id(id) => break id,
-            }
-        };
-        let id = self.handle_response(id)?;
+        let id: String = self.call("eth_subscribe", &["newHeads"])?;
         Ok(RpcStream::new(self, id))
     }
 
@@ -288,7 +281,6 @@ impl<N: Debug + DeserializeOwned> Drop for RpcStream<'_, N> 
{
                 NotificationOrResponse::Response(_) => return,
             }
         }
-        println!("has unusubsriced")
     }
 }
 
@@ -407,11 +399,8 @@ pub trait RpcClient {
 
     /* ----- Miner ----- */
 
-    fn miner_set_etherbase(&mut self, addr: &H160) -> Result<()> {
-        match self.call("miner_setEtherbase", &[addr]) {
-            Err(Error::Null) => Ok(()),
-            i => i,
-        }
+    fn miner_set_etherbase(&mut self, addr: &H160) -> Result<bool> {
+        self.call("miner_setEtherbase", &[addr])
     }
 
     /// Start mining
diff --git a/instrumentation/src/eth.rs b/instrumentation/src/eth.rs
index f215fd3..7d5c534 100644
--- a/instrumentation/src/eth.rs
+++ b/instrumentation/src/eth.rs
@@ -321,7 +321,7 @@ impl EthCtx {
                 &unused_port().to_string(),
                 "--port",
                 &unused_port().to_string(),
-                "--rpc.enabledeprecatedpersonal"
+                "--rpc.enabledeprecatedpersonal",
             ],
             &ctx.log("geth"),
         );
@@ -330,7 +330,7 @@ impl EthCtx {
 
         // Generate wallet
         let out = cmd_out(
-           &ctx.wire_bin_path,
+            &ctx.wire_bin_path,
             &["-c", ctx.conf.to_str().unwrap(), "initwallet"],
         );
 
@@ -442,7 +442,7 @@ impl EthCtx {
                 &unused_port().to_string(),
                 "--port",
                 &unused_port().to_string(),
-                "--rpc.enabledeprecatedpersonal"
+                "--rpc.enabledeprecatedpersonal",
             ],
             &self.ctx.log("geth2"),
         );
@@ -485,7 +485,7 @@ impl EthCtx {
                 &unused_port().to_string(),
                 "--port",
                 &unused_port().to_string(),
-                "--rpc.enabledeprecatedpersonal"
+                "--rpc.enabledeprecatedpersonal",
             ],
             &self.ctx.log("geth"),
         );
diff --git a/instrumentation/src/main.rs b/instrumentation/src/main.rs
index 12971ad..c31fb71 100644
--- a/instrumentation/src/main.rs
+++ b/instrumentation/src/main.rs
@@ -17,7 +17,8 @@
 use std::{
     panic::catch_unwind,
     path::PathBuf,
-    time::{Duration, Instant}, sync::{Arc, Mutex},
+    sync::{Arc, Mutex},
+    time::{Duration, Instant},
 };
 
 use clap::Parser;
diff --git a/script/prepare.sh b/script/prepare.sh
index 8c6a63b..834c676 100755
--- a/script/prepare.sh
+++ b/script/prepare.sh
@@ -20,21 +20,21 @@ echo "Ⅰ - Find installed postgres version"
 PG_VER=`pg_config --version | egrep -o '[0-9]{1,}' | head -1`
 echo "Found version $PG_VER"
 
-echo "Ⅱ - Install bitcoind version 24.1"
+echo "Ⅱ - Install bitcoind version 25.1"
 cd $DIR
-curl -L 
https://bitcoincore.org/bin/bitcoin-core-24.1/bitcoin-24.1-x86_64-linux-gnu.tar.gz
 -o btc.tar.gz
+curl -L 
https://bitcoincore.org/bin/bitcoin-core-25.1/bitcoin-25.1-x86_64-linux-gnu.tar.gz
 -o btc.tar.gz
 tar xvzf btc.tar.gz
 rm -rfv ~/bitcoin
 mkdir -pv ~/bitcoin
-mv -v bitcoin-24.1/* ~/bitcoin
+mv -v bitcoin-25.1/* ~/bitcoin
 
 echo "Ⅲ - Install Go Ethereum (Geth) v1.13.5"
 cd $DIR
-curl -L 
https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.13.5-916d6a44.tar.gz
 -o geth.tar.gz
+curl -L 
https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.13.5-916d6a44.tar.gz
 -o geth.tar.gz
 tar xvzf geth.tar.gz
 rm -rfv ~/geth
 mkdir -pv ~/geth
-mv -v geth-alltools-linux-amd64-1.13.5-916d6a44/* ~/geth
+mv -v geth-linux-amd64-1.13.5-916d6a44/* ~/geth
 
 echo "Ⅳ - Install Lightning Network Daemon v0.15.5-beta"
 cd $DIR

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]