From bc53ce094cce174695c55350cb4f52f7ddbaa6c3 Mon Sep 17 00:00:00 2001 From: Marc Nijdam Date: Fri, 21 Jul 2023 08:24:30 -0600 Subject: [PATCH] Short next beacon time on beacon error (#434) * Short next beacon time on beacon error This constructs a short next beacon time when there is a failure to construct, transmit or (finally) deliver a beacon report. * remove bitfield duplicate with a version bump * review feedback * Switch to using bytes in lorawan subcrate, add unit tests --- Cargo.lock | 19 +-- Cargo.toml | 1 - lorawan/Cargo.toml | 4 +- lorawan/src/lib.rs | 304 ++++++++++++++++++++++++++++++++------------- src/beaconer.rs | 109 +++++----------- src/packet.rs | 2 +- 6 files changed, 254 insertions(+), 185 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e71a619c..aae159dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,12 +201,6 @@ dependencies = [ "which", ] -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - [[package]] name = "bitfield" version = "0.14.0" @@ -517,7 +511,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0e4b7ce1bb7badaf11912039331509503ad798854dc1351a36ce20ac33bf027" dependencies = [ - "bitfield 0.14.0", + "bitfield", "bytes", "i2c-linux", "serde", @@ -792,7 +786,6 @@ dependencies = [ "tracing-appender", "tracing-subscriber", "triggered", - "xxhash-rust", ] [[package]] @@ -1143,8 +1136,8 @@ name = "lorawan" version = "0.1.0" dependencies = [ "base64", - "bitfield 0.13.2", - "byteorder", + "bitfield", + "bytes", ] [[package]] @@ -2426,12 +2419,6 @@ dependencies = [ "tap", ] -[[package]] -name = "xxhash-rust" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70" - [[package]] name = "zeroize" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 5fae72a8..8e626f99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,6 @@ rand = {workspace = true} prost = {workspace = true} tonic = "0" http = "*" -xxhash-rust = { version = "0.8", features = ["xxh64"]} sha2 = {workspace = true} base64 = {workspace = true} helium-proto = {workspace = true} diff --git a/lorawan/Cargo.toml b/lorawan/Cargo.toml index 8237d107..7294bd2a 100644 --- a/lorawan/Cargo.toml +++ b/lorawan/Cargo.toml @@ -6,8 +6,8 @@ edition = "2021" license = "Apache-2.0" [dependencies] -byteorder = {workspace = true} -bitfield = "0.13" +bitfield = "0.14" +bytes = "1" [dev-dependencies] base64 = ">=0.21" diff --git a/lorawan/src/lib.rs b/lorawan/src/lib.rs index 4384e259..222302a7 100644 --- a/lorawan/src/lib.rs +++ b/lorawan/src/lib.rs @@ -1,6 +1,6 @@ use bitfield::bitfield; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::{convert::From, fmt, io, mem::size_of, result}; +use bytes::{Buf, BufMut, Bytes}; +use std::{convert::From, fmt, mem::size_of, result}; pub mod error; pub use error::LoraWanError; @@ -63,12 +63,12 @@ bitfield! { } impl MHDR { - pub fn read(reader: &mut dyn io::Read) -> Result { - Ok(Self(reader.read_u8()?)) + pub fn read(reader: &mut dyn Buf) -> Result { + Ok(Self(reader.get_u8())) } - pub fn write(self, output: &mut dyn io::Write) -> Result { - output.write_u8(self.0)?; + pub fn write(self, output: &mut dyn BufMut) -> Result { + output.put_u8(self.0); Ok(1) } } @@ -93,16 +93,15 @@ impl PHYPayload { mhdr.set_mtype(MType::Proprietary); mhdr }, - payload: PHYPayloadFrame::Proprietary(payload.into()), + payload: PHYPayloadFrame::Proprietary(Bytes::copy_from_slice(payload)), mic: None, } } - pub fn read(direction: Direction, reader: &mut dyn io::Read) -> Result { + pub fn read(direction: Direction, reader: &mut dyn Buf) -> Result { let mhdr = MHDR::read(reader)?; let packet_type = mhdr.mtype(); - let mut data = vec![]; - reader.read_to_end(&mut data)?; + let mut data = reader.copy_to_bytes(reader.remaining()); let phy_len = data.len() + 1; let invalid = match packet_type { @@ -135,21 +134,21 @@ impl PHYPayload { None }; - let mut payload = &data[..]; let res = Self { mhdr, - payload: PHYPayloadFrame::read(direction, packet_type, &mut payload)?, + payload: PHYPayloadFrame::read(direction, packet_type, &mut data)?, mic, }; Ok(res) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { + pub fn write(&self, output: &mut dyn BufMut) -> Result { let mut written = 0_usize; written += self.mhdr.write(output)?; written += self.payload.write(output)?; if let Some(mic) = self.mic { - written += output.write(&mic)?; + output.put_slice(&mic); + written += mic.len(); } Ok(written) } @@ -173,21 +172,20 @@ pub enum PHYPayloadFrame { MACPayload(MACPayload), JoinRequest(JoinRequest), JoinAccept(JoinAccept), - Proprietary(Vec), + Proprietary(Bytes), } impl PHYPayloadFrame { pub fn read( direction: Direction, packet_type: MType, - reader: &mut dyn io::Read, + reader: &mut dyn Buf, ) -> Result { let res = match packet_type { MType::JoinRequest => Self::JoinRequest(JoinRequest::read(reader)?), MType::JoinAccept => Self::JoinAccept(JoinAccept::read(reader)?), MType::Proprietary => { - let mut proprietary_payload = vec![]; - reader.read_to_end(&mut proprietary_payload)?; + let proprietary_payload = reader.copy_to_bytes(reader.remaining()); Self::Proprietary(proprietary_payload) } _ => Self::MACPayload(MACPayload::read(packet_type, direction, reader)?), @@ -195,12 +193,15 @@ impl PHYPayloadFrame { Ok(res) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { + pub fn write(&self, output: &mut dyn BufMut) -> Result { match self { Self::MACPayload(mp) => mp.write(output), Self::JoinRequest(jr) => jr.write(output), Self::JoinAccept(ja) => ja.write(output), - Self::Proprietary(v) => Ok(output.write(v)?), + Self::Proprietary(v) => { + output.put_slice(v); + Ok(v.len()) + } } } @@ -217,7 +218,7 @@ pub struct Fhdr { pub dev_addr: u32, pub fctrl: FCtrl, pub fcnt: u16, - pub fopts: Vec, + pub fopts: Bytes, } impl fmt::Debug for Fhdr { @@ -232,12 +233,11 @@ impl fmt::Debug for Fhdr { } impl Fhdr { - pub fn read(direction: Direction, reader: &mut dyn io::Read) -> Result { - let dev_addr = reader.read_u32::()?; + pub fn read(direction: Direction, reader: &mut dyn Buf) -> Result { + let dev_addr = reader.get_u32_le(); let fctrl = FCtrl::read(direction, reader)?; - let fcnt = reader.read_u16::()?; - let mut fopts = vec![0u8; fctrl.fopts_len().into()]; - reader.read_exact(&mut fopts)?; + let fcnt = reader.get_u16_le(); + let fopts = reader.copy_to_bytes(fctrl.fopts_len()); let res = Self { dev_addr, fctrl, @@ -247,15 +247,16 @@ impl Fhdr { Ok(res) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { + pub fn write(&self, output: &mut dyn BufMut) -> Result { let mut written = 0; - output.write_u32::(self.dev_addr)?; + output.put_u32_le(self.dev_addr); written += size_of::(); - output.write_u32::(self.dev_addr)?; + output.put_u32_le(self.dev_addr); written += self.fctrl.write(output)?; - output.write_u16::(self.fcnt)?; + output.put_u16_le(self.fcnt); written += size_of::(); - written += output.write(&self.fopts)?; + output.put_slice(&self.fopts); + written += self.fopts.len(); Ok(written) } } @@ -272,12 +273,12 @@ bitfield! { } impl FCtrlUplink { - pub fn read(reader: &mut dyn io::Read) -> Result { - Ok(Self(reader.read_u8()?)) + pub fn read(reader: &mut dyn Buf) -> Result { + Ok(Self(reader.get_u8())) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { - output.write_u8(self.0)?; + pub fn write(&self, output: &mut dyn BufMut) -> Result { + output.put_u8(self.0); Ok(size_of::()) } } @@ -294,12 +295,12 @@ bitfield! { } impl FCtrlDownlink { - pub fn read(reader: &mut dyn io::Read) -> Result { - Ok(Self(reader.read_u8()?)) + pub fn read(reader: &mut dyn Buf) -> Result { + Ok(Self(reader.get_u8())) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { - output.write_u8(self.0)?; + pub fn write(&self, output: &mut dyn BufMut) -> Result { + output.put_u8(self.0); Ok(size_of::()) } } @@ -311,14 +312,14 @@ pub enum FCtrl { } impl FCtrl { - pub fn fopts_len(&self) -> u8 { + pub fn fopts_len(&self) -> usize { match self { - FCtrl::Uplink(fctrl) => fctrl.fopts_len(), - FCtrl::Downlink(fctrl) => fctrl.fopts_len(), + FCtrl::Uplink(fctrl) => fctrl.fopts_len().into(), + FCtrl::Downlink(fctrl) => fctrl.fopts_len().into(), } } - pub fn read(direction: Direction, reader: &mut dyn io::Read) -> Result { + pub fn read(direction: Direction, reader: &mut dyn Buf) -> Result { let res = match direction { Direction::Uplink => Self::Uplink(FCtrlUplink::read(reader)?), Direction::Downlink => Self::Downlink(FCtrlDownlink::read(reader)?), @@ -326,7 +327,7 @@ impl FCtrl { Ok(res) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { + pub fn write(&self, output: &mut dyn BufMut) -> Result { match self { Self::Uplink(ul) => ul.write(output), Self::Downlink(dl) => dl.write(output), @@ -345,11 +346,10 @@ impl MACPayload { pub fn read( payload_type: MType, direction: Direction, - reader: &mut dyn io::Read, + reader: &mut dyn Buf, ) -> Result { let fhdr = Fhdr::read(direction, reader)?; - let mut data = vec![]; - reader.read_to_end(&mut data)?; + let data = reader.copy_to_bytes(reader.remaining()); let (fport, payload) = match data.split_first() { Some((port, mut payload)) => ( Some(*port), @@ -368,12 +368,12 @@ impl MACPayload { Ok(res) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { + pub fn write(&self, output: &mut dyn BufMut) -> Result { let mut written = 0; written += self.fhdr.write(output)?; written += match self.fport { Some(fp) => { - output.write_u8(fp)?; + output.put_u8(fp); size_of::() } None => 0, @@ -399,7 +399,7 @@ pub enum FRMPayload { } impl FRMPayload { - pub fn read(payload_type: MType, reader: &mut dyn io::Read) -> Result { + pub fn read(payload_type: MType, reader: &mut dyn Buf) -> Result { let res = match payload_type { MType::UnconfirmedUp => Self::UnconfirmedUp(Payload::read(reader)?), MType::UnconfirmedDown => Self::UnconfirmedDown(Payload::read(reader)?), @@ -411,7 +411,7 @@ impl FRMPayload { Ok(res) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { + pub fn write(&self, output: &mut dyn BufMut) -> Result { match self { Self::UnconfirmedUp(p) => p.write(output), Self::UnconfirmedDown(p) => p.write(output), @@ -422,18 +422,17 @@ impl FRMPayload { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Payload(Vec); +pub struct Payload(Bytes); impl Payload { - pub fn read(reader: &mut dyn io::Read) -> Result { - let mut data = vec![]; - reader.read_to_end(&mut data)?; - let res = Self(data); - Ok(res) + pub fn read(reader: &mut dyn Buf) -> Result { + let data = reader.copy_to_bytes(reader.remaining()); + Ok(Self(data)) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { - Ok(output.write(&self.0)?) + pub fn write(&self, output: &mut dyn BufMut) -> Result { + output.put_slice(&self.0); + Ok(self.0.len()) } } @@ -455,24 +454,22 @@ impl fmt::Debug for JoinRequest { } impl JoinRequest { - pub fn read(reader: &mut dyn io::Read) -> Result { + pub fn read(reader: &mut dyn Buf) -> Result { + // TODO: Reader length check let mut res = Self { - app_eui: reader.read_u64::()?, - dev_eui: reader.read_u64::()?, + app_eui: reader.get_u64_le(), + dev_eui: reader.get_u64_le(), dev_nonce: [0; 2], }; - reader.read_exact(&mut res.dev_nonce)?; + reader.copy_to_slice(&mut res.dev_nonce); Ok(res) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { - let mut written = 0; - output.write_u64::(self.app_eui)?; - written += size_of::(); - output.write_u64::(self.dev_eui)?; - written += size_of::(); - written += output.write(&self.dev_nonce)?; - Ok(written) + pub fn write(&self, output: &mut dyn BufMut) -> Result { + output.put_u64_le(self.app_eui); + output.put_u64_le(self.dev_eui); + output.put_slice(&self.dev_nonce); + Ok(size_of::()) } } @@ -487,32 +484,29 @@ pub struct JoinAccept { } impl JoinAccept { - pub fn read(reader: &mut dyn io::Read) -> Result { + pub fn read(reader: &mut dyn Buf) -> Result { + // TODO: Reader length check let mut app_nonce = [0u8; 3]; let mut net_id = [0u8; 3]; - reader.read_exact(&mut app_nonce)?; - reader.read_exact(&mut net_id)?; + reader.copy_to_slice(&mut app_nonce); + reader.copy_to_slice(&mut net_id); let res = Self { app_nonce, net_id, - dev_addr: reader.read_u32::()?, - dl_settings: reader.read_u8()?, - rx_delay: reader.read_u8()?, + dev_addr: reader.get_u32_le(), + dl_settings: reader.get_u8(), + rx_delay: reader.get_u8(), }; Ok(res) } - pub fn write(&self, output: &mut dyn io::Write) -> Result { - let mut written = 0; - written += output.write(&self.app_nonce)?; - written += output.write(&self.net_id)?; - output.write_u32::(self.dev_addr)?; - written += size_of::(); - output.write_u8(self.dl_settings)?; - written += size_of::(); - output.write_u8(self.rx_delay)?; - written += size_of::(); - Ok(written) + pub fn write(&self, output: &mut dyn BufMut) -> Result { + output.put_slice(&self.app_nonce); + output.put_slice(&self.net_id); + output.put_u32_le(self.dev_addr); + output.put_u8(self.dl_settings); + output.put_u8(self.rx_delay); + Ok(size_of::()) } } @@ -532,4 +526,138 @@ mod test { payload_a.write(&mut data_b).unwrap(); assert_eq!(data_a, data_b); } + + #[test] + fn test_packets() { + for (routing, data) in mk_test_packets() { + let expected_routing = Routing::try_from(data).expect("routing"); + assert_eq!(routing, expected_routing); + } + } + + impl TryFrom<&[u8]> for Routing { + type Error = LoraWanError; + fn try_from(value: &[u8]) -> Result { + match PHYPayload::read(Direction::Uplink, &mut &value[..]) { + Err(_err) => Ok(Self::Invalid), + Ok(payload) => payload.try_into(), + } + } + } + + impl TryFrom for Routing { + type Error = LoraWanError; + fn try_from(value: PHYPayload) -> Result { + fn get_dev_addr(mtype: MType, payload: &PHYPayload) -> Result { + match payload.payload { + PHYPayloadFrame::MACPayload(MACPayload { + fhdr: Fhdr { dev_addr, .. }, + .. + }) => Ok(dev_addr), + _ => return Err(LoraWanError::InvalidPacketType(mtype.into())), + } + } + + match value.mtype() { + MType::UnconfirmedUp => { + let dev_addr = get_dev_addr(value.mtype(), &value)?; + Ok(Self::Unconfirmed { + devaddr: format!("{:06X}", dev_addr), + }) + } + MType::ConfirmedUp => { + let dev_addr = get_dev_addr(value.mtype(), &value)?; + Ok(Self::Confirmed { + devaddr: format!("{:06X}", dev_addr), + }) + } + MType::JoinRequest => { + let (dev_eui, app_eui) = match value.payload { + PHYPayloadFrame::JoinRequest(JoinRequest { + dev_eui, app_eui, .. + }) => (dev_eui, app_eui), + _ => return Err(LoraWanError::InvalidPacketType(value.mtype().into())), + }; + Ok(Self::Join { + eui: format!("{:06X}", app_eui), + dev: format!("{:06X}", dev_eui), + }) + } + _ => Ok(Self::Invalid), + } + } + } + + #[derive(Debug, PartialEq, Eq)] + enum Routing { + Unconfirmed { devaddr: String }, + Confirmed { devaddr: String }, + Join { eui: String, dev: String }, + Invalid, + } + + fn mk_test_packets() -> Vec<(Routing, &'static [u8])> { + vec![ + ( + Routing::Unconfirmed { + devaddr: "65A547".to_string(), + }, + &[ + 64, 71, 165, 101, 0, 128, 130, 41, 2, 214, 3, 27, 61, 140, 165, 211, 143, 196, + 1, 134, 56, 31, 122, 222, + ], + ), + (Routing::Invalid, &[4, 217, 181, 6, 11, 130, 2, 254, 1]), + ( + Routing::Join { + eui: "70B3D5B02000088D".to_string(), + dev: "70B3D5B020038C7F".to_string(), + }, + &[ + 0, 141, 8, 0, 32, 176, 213, 179, 112, 127, 140, 3, 32, 176, 213, 179, 112, 135, + 15, 125, 90, 77, 199, + ], + ), + ( + Routing::Confirmed { + devaddr: "127B3F4".to_string(), + }, + &[ + 128, 244, 179, 39, 1, 128, 27, 0, 61, 112, 100, 42, 151, 154, 203, 136, 193, + 200, 210, 165, + ], + ), + ( + Routing::Join { + eui: "1122334455667799".to_string(), + dev: "956906000056AD".to_string(), + }, + &[ + 0, 153, 119, 102, 85, 68, 51, 34, 17, 173, 86, 0, 0, 6, 105, 149, 0, 151, 197, + 232, 148, 220, 26, + ], + ), + (Routing::Invalid, &[4, 73, 201, 4, 152, 149, 2, 254, 1]), + (Routing::Invalid, &[4, 214, 159, 4, 116, 253, 2, 254, 1]), + ( + Routing::Unconfirmed { + devaddr: "90CC175".to_string(), + }, + &[ + 64, 117, 193, 12, 9, 128, 255, 254, 5, 4, 240, 62, 237, 70, 223, 10, 6, 103, + 172, 117, 113, 137, 253, 157, 62, 152, 146, 62, + ], + ), + ( + Routing::Unconfirmed { + devaddr: "203D5C8".to_string(), + }, + &[ + 64, 200, 213, 3, 2, 128, 11, 124, 1, 38, 51, 2, 5, 95, 101, 161, 40, 44, 86, + 116, 134, 134, 205, 127, 80, 215, 216, 107, 195, 105, 179, 202, 251, 251, 103, + 113, 108, 15, 139, 26, 35, 190, 230, 163, 135, 83, 179, + ], + ), + ] + } } diff --git a/src/beaconer.rs b/src/beaconer.rs index 7941a6ac..96deb896 100644 --- a/src/beaconer.rs +++ b/src/beaconer.rs @@ -14,7 +14,6 @@ use rand::{rngs::OsRng, Rng}; use std::sync::Arc; use tokio::time::{self, Duration, Instant}; use tracing::{info, warn}; -use xxhash_rust::xxh64::xxh64; /// To prevent a thundering herd of hotspots all beaconing at the same time, we /// add a randomized jitter value of up to `BEACON_INTERVAL_JITTER_PERCENTAGE` @@ -143,7 +142,7 @@ impl Beaconer { } } - pub async fn mk_beacon(&mut self) -> Result { + pub async fn mk_beacon(&self) -> Result { self.region_params.check_valid()?; let mut entropy_service = EntropyService::new(self.entropy_uri.clone()); @@ -157,32 +156,29 @@ impl Beaconer { /// Sends a gateway-to-gateway packet. /// /// See [`gateway::MessageSender::transmit_beacon`] - pub async fn send_beacon(&mut self, beacon: beacon::Beacon) { + pub async fn send_beacon(&self, beacon: beacon::Beacon) -> Result { let beacon_id = beacon.beacon_id(); info!(beacon_id, "transmitting beacon"); - let (powe, tmst) = match self.transmit.transmit_beacon(beacon.clone()).await { - Ok(BeaconResp { powe, tmst }) => (powe, tmst), - Err(err) => { - warn!(%err, "transmit beacon"); - return; - } - }; + let (powe, tmst) = self + .transmit + .transmit_beacon(beacon.clone()) + .inspect_err(|err| warn!(%err, "transmit beacon")) + .map_ok(|BeaconResp { powe, tmst }| (powe, tmst)) + .await?; - self.last_beacon = Some(beacon.clone()); + let report = self + .mk_beacon_report(beacon.clone(), powe, tmst) + .inspect_err(|err| warn!(beacon_id, %err, "poc beacon report")) + .await?; - let report = match self.mk_beacon_report(beacon, powe, tmst).await { - Ok(report) => report, - Err(err) => { - warn!(beacon_id, %err, "poc beacon report"); - return; - } - }; - let _ = PocIotService::new(self.poc_ingest_uri.clone()) + PocIotService::new(self.poc_ingest_uri.clone()) .submit_beacon(report) - .inspect_err(|err| info!(beacon_id, %err, "submit poc beacon report",)) + .inspect_err(|err| warn!(beacon_id, %err, "submit poc beacon report",)) .inspect_ok(|_| info!(beacon_id, "poc beacon report submitted",)) - .await; + .await?; + + Ok(beacon) } async fn mk_beacon_report( @@ -213,21 +209,21 @@ impl Beaconer { if self.disabled { return; } - match self.mk_beacon().await { - Ok(beacon) => { - self.send_beacon(beacon).await; - // On success just use the normal behavior for selecting a next - // beacon time. Can't be the first time since we have region - // parameters to construct a beacon - self.next_beacon_time = Self::mk_next_beacon_time(self.interval); - } - Err(err) => { - warn!(%err, "construct beacon"); - // On failure to construct a beacon at all, select a shortened - // "first time" next beacon time - self.next_beacon_time = Self::mk_next_short_beacon_time(self.interval); - } - }; + let interval = self.interval; + let (last_beacon, next_beacon_time) = self + .mk_beacon() + .inspect_err(|err| warn!(%err, "construct beacon")) + .and_then(|beacon| self.send_beacon(beacon)) + // On success to construct and transmit a beacon and its report + // select a normal full next beacon time + .map_ok(|beacon| (Some(beacon), Self::mk_next_beacon_time(interval))) + // On failure to construct, transmit or send a beacon or its + // report, select a shortened next beacon time + .unwrap_or_else(|_| (None, Self::mk_next_short_beacon_time(interval))) + .await; + + self.next_beacon_time = next_beacon_time; + self.last_beacon = last_beacon; } async fn handle_received_beacon(&mut self, packet: PacketUp) { @@ -265,47 +261,6 @@ impl Beaconer { ) }) .await; - - // Disable secondary beacons until TTL is implemented - if false { - self.handle_secondary_beacon(report).await - } - } - - async fn handle_secondary_beacon(&mut self, report: poc_lora::LoraWitnessReportReqV1) { - if self.region_params.check_valid().is_err() { - warn!("no region params for secondary beacon"); - return; - }; - - // check if hash of witness is below the "difficulty threshold" for a secondary beacon - // TODO provide a way to get this difficulty threshold from eg. the entropy server - let buf = report.encode_to_vec(); - let threshold = 1855177858159416090; - // compare the hash of the witness report as a u64 to the difficulty threshold - // this is sort of a bitcoin-esque proof of work check insofar as as we're looking - // for hashes under a certain value. Because of the time constraints involved this - // should not be a 'mineable' check, but it provides a useful probabalistic way to - // allow for verifiable secondary beacons without any coordination. - let factor = xxh64(&buf, 0); - if factor < threshold { - let beacon = match beacon::Entropy::from_data(report.data.clone()) - .and_then(|remote_entropy| { - beacon::Entropy::from_data(buf) - .map(|local_entropy| (remote_entropy, local_entropy)) - }) - .and_then(|(remote_entropy, local_entropy)| { - beacon::Beacon::new(remote_entropy, local_entropy, &self.region_params) - }) { - Ok(beacon) => beacon, - Err(err) => { - warn!(%err, "secondary beacon construction"); - return; - } - }; - - self.send_beacon(beacon).await - } } /// Construct a next beacon time based on a fraction of the given interval. diff --git a/src/packet.rs b/src/packet.rs index f9a10778..e9e23d89 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -70,7 +70,7 @@ impl TryFrom for poc_lora::LoraWitnessReportReqV1 { _ => return Err(DecodeError::not_beacon()), }; let report = poc_lora::LoraWitnessReportReqV1 { - data: payload, + data: payload.to_vec(), tmst: value.0.timestamp as u32, timestamp: SystemTime::now() .duration_since(UNIX_EPOCH)