diff --git a/crates/core/src/client_events.rs b/crates/core/src/client_events.rs index 8bba626ac..9b302189f 100644 --- a/crates/core/src/client_events.rs +++ b/crates/core/src/client_events.rs @@ -493,6 +493,8 @@ pub(crate) mod test { related_contracts: RelatedContracts::new(), }; + tracing::debug!("sending put to an existing contract"); + return Some(request.into()); } } diff --git a/crates/core/src/generated/mod.rs b/crates/core/src/generated/mod.rs index ae2fa5753..cd9c8eb2a 100644 --- a/crates/core/src/generated/mod.rs +++ b/crates/core/src/generated/mod.rs @@ -21,6 +21,8 @@ pub enum ContractChange<'a> { PutRequest(topology::PutRequest<'a>), PutSuccess(topology::PutSuccess<'a>), PutFailure(topology::PutFailure<'a>), + BroadcastEmitted(topology::BroadcastEmitted<'a>), + BroadcastReceived(topology::BroadcastReceived<'a>), } // TODO: Change this to EventWrapper @@ -35,6 +37,8 @@ impl ContractChange<'_> { contract: String, requester: String, target: String, + timestamp: u64, + contract_location: f64, ) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); let transaction = buf.create_string(transaction.as_str()); @@ -48,6 +52,8 @@ impl ContractChange<'_> { key: Some(contract), requester: Some(requester), target: Some(target), + timestamp, + contract_location, }, ); let msg = topology::ContractChange::create( @@ -67,12 +73,14 @@ impl ContractChange<'_> { contract: String, requester: String, target: String, + timestamp: u64, + contract_location: f64, ) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); let transaction = buf.create_string(transaction.as_str()); let contract = buf.create_string(contract.as_str()); let requester = buf.create_string(requester.as_str()); - let target = buf.create_string(target.to_string().as_str()); + let target = buf.create_string(target.as_str()); let put_success = topology::PutSuccess::create( &mut buf, &topology::PutSuccessArgs { @@ -80,6 +88,8 @@ impl ContractChange<'_> { key: Some(contract), requester: Some(requester), target: Some(target), + timestamp, + contract_location, }, ); let msg = topology::ContractChange::create( @@ -99,6 +109,7 @@ impl ContractChange<'_> { contract: impl AsRef, requester: impl AsRef, target: impl AsRef, + _timestamp: u64, ) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); let transaction = buf.create_string(transaction.as_ref()); @@ -125,19 +136,104 @@ impl ContractChange<'_> { buf.finish_minimal(msg); buf.finished_data().to_vec() } + + pub fn broadcast_emitted_msg( + transaction: impl AsRef, + upstream: impl AsRef, + broadcast_to: Vec, + broadcasted_to: usize, + contract_key: impl AsRef, + sender: impl AsRef, + + timestamp: u64, + contract_location: f64, + ) -> Vec { + let mut buf = flatbuffers::FlatBufferBuilder::new(); + let transaction = buf.create_string(transaction.as_ref()); + let upstream = buf.create_string(upstream.as_ref()); + let broadcast_to = broadcast_to + .iter() + .map(|s| buf.create_string(s.as_str())) + .collect::>(); + let broadcast_to = buf.create_vector(&broadcast_to); + let contract_key = buf.create_string(contract_key.as_ref()); + let sender = buf.create_string(sender.as_ref()); + let broadcast_emitted = topology::BroadcastEmitted::create( + &mut buf, + &topology::BroadcastEmittedArgs { + transaction: Some(transaction), + upstream: Some(upstream), + broadcast_to: Some(broadcast_to), + broadcasted_to: broadcasted_to as u32, + key: Some(contract_key), + sender: Some(sender), + timestamp, + contract_location, + }, + ); + + let msg = topology::ContractChange::create( + &mut buf, + &topology::ContractChangeArgs { + contract_id: Some(contract_key), + change_type: topology::ContractChangeType::BroadcastEmitted, + change: Some(broadcast_emitted.as_union_value()), + }, + ); + buf.finish_minimal(msg); + buf.finished_data().to_vec() + } + + pub fn broadcast_received_msg( + transaction: impl AsRef, + target: impl AsRef, + requester: impl AsRef, + contract_key: impl AsRef, + + timestamp: u64, + contract_location: f64, + ) -> Vec { + let mut buf = flatbuffers::FlatBufferBuilder::new(); + let transaction = buf.create_string(transaction.as_ref()); + let target = buf.create_string(target.as_ref()); + let requester = buf.create_string(requester.as_ref()); + let contract_key = buf.create_string(contract_key.as_ref()); + let broadcast_received = topology::BroadcastReceived::create( + &mut buf, + &topology::BroadcastReceivedArgs { + transaction: Some(transaction), + target: Some(target), + requester: Some(requester), + key: Some(contract_key), + timestamp, + contract_location, + }, + ); + + let msg = topology::ContractChange::create( + &mut buf, + &topology::ContractChangeArgs { + contract_id: Some(contract_key), + change_type: topology::ContractChangeType::BroadcastReceived, + change: Some(broadcast_received.as_union_value()), + }, + ); + buf.finish_minimal(msg); + buf.finished_data().to_vec() + } } impl PeerChange<'_> { pub fn current_state_msg<'a>( - to: PeerId, + to: String, to_location: f64, - connections: impl Iterator, + connections: impl Iterator, ) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); - let to = buf.create_vector(&bincode::serialize(&to).unwrap()); + let to = buf.create_vector(to.as_bytes()); let connections = connections .map(|(from, from_location)| { - let from = Some(buf.create_vector(&bincode::serialize(from).unwrap())); + let from = Some(buf.create_vector(from.as_bytes())); topology::AddedConnection::create( &mut buf, &topology::AddedConnectionArgs { @@ -165,12 +261,12 @@ impl PeerChange<'_> { pub fn added_connection_msg( transaction: Option>, - (from, from_location): (PeerId, f64), - (to, to_location): (PeerId, f64), + (from, from_location): (String, f64), + (to, to_location): (String, f64), ) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); - let from = buf.create_vector(&bincode::serialize(&from).unwrap()); - let to = buf.create_vector(&bincode::serialize(&to).unwrap()); + let from = buf.create_vector(from.as_bytes()); + let to = buf.create_vector(to.as_bytes()); let transaction = transaction.map(|t| buf.create_string(t.as_ref())); let add_conn = topology::AddedConnection::create( &mut buf, @@ -194,10 +290,10 @@ impl PeerChange<'_> { buf.finished_data().to_vec() } - pub fn removed_connection_msg(at: PeerId, from: PeerId) -> Vec { + pub fn removed_connection_msg(at: String, from: String) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); - let at = buf.create_vector(&bincode::serialize(&at).unwrap()); - let from = buf.create_vector(&bincode::serialize(&from).unwrap()); + let at = buf.create_vector(&at.as_bytes()); + let from = buf.create_vector(&from.as_bytes()); let remove_conn = topology::RemovedConnection::create( &mut buf, &topology::RemovedConnectionArgs { @@ -319,7 +415,27 @@ impl<'a> TryFromFbs<'a> for ContractChange<'a> { })?; Ok(Self::PutFailure(req)) } - _ => unreachable!(), + topology::ContractChangeType::BroadcastEmitted => { + let req = req.change_as_broadcast_emitted().ok_or_else(|| { + flatbuffers::InvalidFlatbuffer::InconsistentUnion { + field: "change_type", + field_type: "ContractChangeType", + error_trace: Default::default(), + } + })?; + Ok(Self::BroadcastEmitted(req)) + } + topology::ContractChangeType::BroadcastReceived => { + let req = req.change_as_broadcast_received().ok_or_else(|| { + flatbuffers::InvalidFlatbuffer::InconsistentUnion { + field: "change_type", + field_type: "ContractChangeType", + error_trace: Default::default(), + } + })?; + Ok(Self::BroadcastReceived(req)) + } + _ => unreachable!("Invalid contract change type"), } } } diff --git a/crates/core/src/generated/topology_generated.rs b/crates/core/src/generated/topology_generated.rs index a0ad83526..b24f893af 100644 --- a/crates/core/src/generated/topology_generated.rs +++ b/crates/core/src/generated/topology_generated.rs @@ -224,17 +224,19 @@ pub mod topology { since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021." )] - pub const ENUM_MAX_CONTRACT_CHANGE_TYPE: u8 = 6; + pub const ENUM_MAX_CONTRACT_CHANGE_TYPE: u8 = 8; #[deprecated( since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021." )] #[allow(non_camel_case_types)] - pub const ENUM_VALUES_CONTRACT_CHANGE_TYPE: [ContractChangeType; 7] = [ + pub const ENUM_VALUES_CONTRACT_CHANGE_TYPE: [ContractChangeType; 9] = [ ContractChangeType::NONE, ContractChangeType::PutRequest, ContractChangeType::PutSuccess, ContractChangeType::PutFailure, + ContractChangeType::BroadcastEmitted, + ContractChangeType::BroadcastReceived, ContractChangeType::UpdateRequest, ContractChangeType::UpdateSuccess, ContractChangeType::UpdateFailure, @@ -249,17 +251,21 @@ pub mod topology { pub const PutRequest: Self = Self(1); pub const PutSuccess: Self = Self(2); pub const PutFailure: Self = Self(3); - pub const UpdateRequest: Self = Self(4); - pub const UpdateSuccess: Self = Self(5); - pub const UpdateFailure: Self = Self(6); + pub const BroadcastEmitted: Self = Self(4); + pub const BroadcastReceived: Self = Self(5); + pub const UpdateRequest: Self = Self(6); + pub const UpdateSuccess: Self = Self(7); + pub const UpdateFailure: Self = Self(8); pub const ENUM_MIN: u8 = 0; - pub const ENUM_MAX: u8 = 6; + pub const ENUM_MAX: u8 = 8; pub const ENUM_VALUES: &'static [Self] = &[ Self::NONE, Self::PutRequest, Self::PutSuccess, Self::PutFailure, + Self::BroadcastEmitted, + Self::BroadcastReceived, Self::UpdateRequest, Self::UpdateSuccess, Self::UpdateFailure, @@ -271,6 +277,8 @@ pub mod topology { Self::PutRequest => Some("PutRequest"), Self::PutSuccess => Some("PutSuccess"), Self::PutFailure => Some("PutFailure"), + Self::BroadcastEmitted => Some("BroadcastEmitted"), + Self::BroadcastReceived => Some("BroadcastReceived"), Self::UpdateRequest => Some("UpdateRequest"), Self::UpdateSuccess => Some("UpdateSuccess"), Self::UpdateFailure => Some("UpdateFailure"), @@ -1411,6 +1419,8 @@ pub mod topology { pub const VT_KEY: flatbuffers::VOffsetT = 6; pub const VT_REQUESTER: flatbuffers::VOffsetT = 8; pub const VT_TARGET: flatbuffers::VOffsetT = 10; + pub const VT_TIMESTAMP: flatbuffers::VOffsetT = 12; + pub const VT_CONTRACT_LOCATION: flatbuffers::VOffsetT = 14; #[inline] pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { @@ -1422,6 +1432,8 @@ pub mod topology { args: &'args PutRequestArgs<'args>, ) -> flatbuffers::WIPOffset> { let mut builder = PutRequestBuilder::new(_fbb); + builder.add_contract_location(args.contract_location); + builder.add_timestamp(args.timestamp); if let Some(x) = args.target { builder.add_target(x); } @@ -1481,6 +1493,28 @@ pub mod topology { .unwrap() } } + #[inline] + pub fn timestamp(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(PutRequest::VT_TIMESTAMP, Some(0)) + .unwrap() + } + } + #[inline] + pub fn contract_location(&self) -> f64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(PutRequest::VT_CONTRACT_LOCATION, Some(0.0)) + .unwrap() + } + } } impl flatbuffers::Verifiable for PutRequest<'_> { @@ -1503,6 +1537,8 @@ pub mod topology { true, )? .visit_field::>("target", Self::VT_TARGET, true)? + .visit_field::("timestamp", Self::VT_TIMESTAMP, false)? + .visit_field::("contract_location", Self::VT_CONTRACT_LOCATION, false)? .finish(); Ok(()) } @@ -1512,6 +1548,8 @@ pub mod topology { pub key: Option>, pub requester: Option>, pub target: Option>, + pub timestamp: u64, + pub contract_location: f64, } impl<'a> Default for PutRequestArgs<'a> { #[inline] @@ -1521,6 +1559,8 @@ pub mod topology { key: None, // required field requester: None, // required field target: None, // required field + timestamp: 0, + contract_location: 0.0, } } } @@ -1553,6 +1593,16 @@ pub mod topology { .push_slot_always::>(PutRequest::VT_TARGET, target); } #[inline] + pub fn add_timestamp(&mut self, timestamp: u64) { + self.fbb_ + .push_slot::(PutRequest::VT_TIMESTAMP, timestamp, 0); + } + #[inline] + pub fn add_contract_location(&mut self, contract_location: f64) { + self.fbb_ + .push_slot::(PutRequest::VT_CONTRACT_LOCATION, contract_location, 0.0); + } + #[inline] pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> PutRequestBuilder<'a, 'b> { let start = _fbb.start_table(); PutRequestBuilder { @@ -1579,6 +1629,8 @@ pub mod topology { ds.field("key", &self.key()); ds.field("requester", &self.requester()); ds.field("target", &self.target()); + ds.field("timestamp", &self.timestamp()); + ds.field("contract_location", &self.contract_location()); ds.finish() } } @@ -1802,6 +1854,8 @@ pub mod topology { pub const VT_REQUESTER: flatbuffers::VOffsetT = 6; pub const VT_TARGET: flatbuffers::VOffsetT = 8; pub const VT_KEY: flatbuffers::VOffsetT = 10; + pub const VT_TIMESTAMP: flatbuffers::VOffsetT = 12; + pub const VT_CONTRACT_LOCATION: flatbuffers::VOffsetT = 14; #[inline] pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { @@ -1813,6 +1867,8 @@ pub mod topology { args: &'args PutSuccessArgs<'args>, ) -> flatbuffers::WIPOffset> { let mut builder = PutSuccessBuilder::new(_fbb); + builder.add_contract_location(args.contract_location); + builder.add_timestamp(args.timestamp); if let Some(x) = args.key { builder.add_key(x); } @@ -1872,6 +1928,28 @@ pub mod topology { .unwrap() } } + #[inline] + pub fn timestamp(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(PutSuccess::VT_TIMESTAMP, Some(0)) + .unwrap() + } + } + #[inline] + pub fn contract_location(&self) -> f64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(PutSuccess::VT_CONTRACT_LOCATION, Some(0.0)) + .unwrap() + } + } } impl flatbuffers::Verifiable for PutSuccess<'_> { @@ -1894,6 +1972,8 @@ pub mod topology { )? .visit_field::>("target", Self::VT_TARGET, true)? .visit_field::>("key", Self::VT_KEY, true)? + .visit_field::("timestamp", Self::VT_TIMESTAMP, false)? + .visit_field::("contract_location", Self::VT_CONTRACT_LOCATION, false)? .finish(); Ok(()) } @@ -1903,6 +1983,8 @@ pub mod topology { pub requester: Option>, pub target: Option>, pub key: Option>, + pub timestamp: u64, + pub contract_location: f64, } impl<'a> Default for PutSuccessArgs<'a> { #[inline] @@ -1912,6 +1994,8 @@ pub mod topology { requester: None, // required field target: None, // required field key: None, // required field + timestamp: 0, + contract_location: 0.0, } } } @@ -1944,6 +2028,16 @@ pub mod topology { .push_slot_always::>(PutSuccess::VT_KEY, key); } #[inline] + pub fn add_timestamp(&mut self, timestamp: u64) { + self.fbb_ + .push_slot::(PutSuccess::VT_TIMESTAMP, timestamp, 0); + } + #[inline] + pub fn add_contract_location(&mut self, contract_location: f64) { + self.fbb_ + .push_slot::(PutSuccess::VT_CONTRACT_LOCATION, contract_location, 0.0); + } + #[inline] pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> PutSuccessBuilder<'a, 'b> { let start = _fbb.start_table(); PutSuccessBuilder { @@ -1970,6 +2064,8 @@ pub mod topology { ds.field("requester", &self.requester()); ds.field("target", &self.target()); ds.field("key", &self.key()); + ds.field("timestamp", &self.timestamp()); + ds.field("contract_location", &self.contract_location()); ds.finish() } } @@ -2562,6 +2658,567 @@ pub mod topology { ds.finish() } } + pub enum BroadcastEmittedOffset {} + #[derive(Copy, Clone, PartialEq)] + + pub struct BroadcastEmitted<'a> { + pub _tab: flatbuffers::Table<'a>, + } + + impl<'a> flatbuffers::Follow<'a> for BroadcastEmitted<'a> { + type Inner = BroadcastEmitted<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table::new(buf, loc), + } + } + } + + impl<'a> BroadcastEmitted<'a> { + pub const VT_TRANSACTION: flatbuffers::VOffsetT = 4; + pub const VT_UPSTREAM: flatbuffers::VOffsetT = 6; + pub const VT_BROADCAST_TO: flatbuffers::VOffsetT = 8; + pub const VT_BROADCASTED_TO: flatbuffers::VOffsetT = 10; + pub const VT_KEY: flatbuffers::VOffsetT = 12; + pub const VT_SENDER: flatbuffers::VOffsetT = 14; + pub const VT_TIMESTAMP: flatbuffers::VOffsetT = 16; + pub const VT_CONTRACT_LOCATION: flatbuffers::VOffsetT = 18; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + BroadcastEmitted { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args BroadcastEmittedArgs<'args>, + ) -> flatbuffers::WIPOffset> { + let mut builder = BroadcastEmittedBuilder::new(_fbb); + builder.add_contract_location(args.contract_location); + builder.add_timestamp(args.timestamp); + if let Some(x) = args.sender { + builder.add_sender(x); + } + if let Some(x) = args.key { + builder.add_key(x); + } + builder.add_broadcasted_to(args.broadcasted_to); + if let Some(x) = args.broadcast_to { + builder.add_broadcast_to(x); + } + if let Some(x) = args.upstream { + builder.add_upstream(x); + } + if let Some(x) = args.transaction { + builder.add_transaction(x); + } + builder.finish() + } + + #[inline] + pub fn transaction(&self) -> &'a str { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>( + BroadcastEmitted::VT_TRANSACTION, + None, + ) + .unwrap() + } + } + #[inline] + pub fn upstream(&self) -> &'a str { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>(BroadcastEmitted::VT_UPSTREAM, None) + .unwrap() + } + } + #[inline] + pub fn broadcast_to( + &self, + ) -> Option>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>, + >>(BroadcastEmitted::VT_BROADCAST_TO, None) + } + } + #[inline] + pub fn broadcasted_to(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(BroadcastEmitted::VT_BROADCASTED_TO, Some(0)) + .unwrap() + } + } + #[inline] + pub fn key(&self) -> &'a str { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>(BroadcastEmitted::VT_KEY, None) + .unwrap() + } + } + #[inline] + pub fn sender(&self) -> &'a str { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>(BroadcastEmitted::VT_SENDER, None) + .unwrap() + } + } + #[inline] + pub fn timestamp(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(BroadcastEmitted::VT_TIMESTAMP, Some(0)) + .unwrap() + } + } + #[inline] + pub fn contract_location(&self) -> f64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(BroadcastEmitted::VT_CONTRACT_LOCATION, Some(0.0)) + .unwrap() + } + } + } + + impl flatbuffers::Verifiable for BroadcastEmitted<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>( + "transaction", + Self::VT_TRANSACTION, + true, + )? + .visit_field::>( + "upstream", + Self::VT_UPSTREAM, + true, + )? + .visit_field::>, + >>("broadcast_to", Self::VT_BROADCAST_TO, false)? + .visit_field::("broadcasted_to", Self::VT_BROADCASTED_TO, false)? + .visit_field::>("key", Self::VT_KEY, true)? + .visit_field::>("sender", Self::VT_SENDER, true)? + .visit_field::("timestamp", Self::VT_TIMESTAMP, false)? + .visit_field::("contract_location", Self::VT_CONTRACT_LOCATION, false)? + .finish(); + Ok(()) + } + } + pub struct BroadcastEmittedArgs<'a> { + pub transaction: Option>, + pub upstream: Option>, + pub broadcast_to: Option< + flatbuffers::WIPOffset>>, + >, + pub broadcasted_to: u32, + pub key: Option>, + pub sender: Option>, + pub timestamp: u64, + pub contract_location: f64, + } + impl<'a> Default for BroadcastEmittedArgs<'a> { + #[inline] + fn default() -> Self { + BroadcastEmittedArgs { + transaction: None, // required field + upstream: None, // required field + broadcast_to: None, + broadcasted_to: 0, + key: None, // required field + sender: None, // required field + timestamp: 0, + contract_location: 0.0, + } + } + } + + pub struct BroadcastEmittedBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, + } + impl<'a: 'b, 'b> BroadcastEmittedBuilder<'a, 'b> { + #[inline] + pub fn add_transaction(&mut self, transaction: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + BroadcastEmitted::VT_TRANSACTION, + transaction, + ); + } + #[inline] + pub fn add_upstream(&mut self, upstream: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + BroadcastEmitted::VT_UPSTREAM, + upstream, + ); + } + #[inline] + pub fn add_broadcast_to( + &mut self, + broadcast_to: flatbuffers::WIPOffset< + flatbuffers::Vector<'b, flatbuffers::ForwardsUOffset<&'b str>>, + >, + ) { + self.fbb_.push_slot_always::>( + BroadcastEmitted::VT_BROADCAST_TO, + broadcast_to, + ); + } + #[inline] + pub fn add_broadcasted_to(&mut self, broadcasted_to: u32) { + self.fbb_ + .push_slot::(BroadcastEmitted::VT_BROADCASTED_TO, broadcasted_to, 0); + } + #[inline] + pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { + self.fbb_ + .push_slot_always::>(BroadcastEmitted::VT_KEY, key); + } + #[inline] + pub fn add_sender(&mut self, sender: flatbuffers::WIPOffset<&'b str>) { + self.fbb_ + .push_slot_always::>(BroadcastEmitted::VT_SENDER, sender); + } + #[inline] + pub fn add_timestamp(&mut self, timestamp: u64) { + self.fbb_ + .push_slot::(BroadcastEmitted::VT_TIMESTAMP, timestamp, 0); + } + #[inline] + pub fn add_contract_location(&mut self, contract_location: f64) { + self.fbb_.push_slot::( + BroadcastEmitted::VT_CONTRACT_LOCATION, + contract_location, + 0.0, + ); + } + #[inline] + pub fn new( + _fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, + ) -> BroadcastEmittedBuilder<'a, 'b> { + let start = _fbb.start_table(); + BroadcastEmittedBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + self.fbb_ + .required(o, BroadcastEmitted::VT_TRANSACTION, "transaction"); + self.fbb_ + .required(o, BroadcastEmitted::VT_UPSTREAM, "upstream"); + self.fbb_.required(o, BroadcastEmitted::VT_KEY, "key"); + self.fbb_.required(o, BroadcastEmitted::VT_SENDER, "sender"); + flatbuffers::WIPOffset::new(o.value()) + } + } + + impl core::fmt::Debug for BroadcastEmitted<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("BroadcastEmitted"); + ds.field("transaction", &self.transaction()); + ds.field("upstream", &self.upstream()); + ds.field("broadcast_to", &self.broadcast_to()); + ds.field("broadcasted_to", &self.broadcasted_to()); + ds.field("key", &self.key()); + ds.field("sender", &self.sender()); + ds.field("timestamp", &self.timestamp()); + ds.field("contract_location", &self.contract_location()); + ds.finish() + } + } + pub enum BroadcastReceivedOffset {} + #[derive(Copy, Clone, PartialEq)] + + pub struct BroadcastReceived<'a> { + pub _tab: flatbuffers::Table<'a>, + } + + impl<'a> flatbuffers::Follow<'a> for BroadcastReceived<'a> { + type Inner = BroadcastReceived<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table::new(buf, loc), + } + } + } + + impl<'a> BroadcastReceived<'a> { + pub const VT_TRANSACTION: flatbuffers::VOffsetT = 4; + pub const VT_TARGET: flatbuffers::VOffsetT = 6; + pub const VT_REQUESTER: flatbuffers::VOffsetT = 8; + pub const VT_KEY: flatbuffers::VOffsetT = 10; + pub const VT_TIMESTAMP: flatbuffers::VOffsetT = 12; + pub const VT_CONTRACT_LOCATION: flatbuffers::VOffsetT = 14; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + BroadcastReceived { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args BroadcastReceivedArgs<'args>, + ) -> flatbuffers::WIPOffset> { + let mut builder = BroadcastReceivedBuilder::new(_fbb); + builder.add_contract_location(args.contract_location); + builder.add_timestamp(args.timestamp); + if let Some(x) = args.key { + builder.add_key(x); + } + if let Some(x) = args.requester { + builder.add_requester(x); + } + if let Some(x) = args.target { + builder.add_target(x); + } + if let Some(x) = args.transaction { + builder.add_transaction(x); + } + builder.finish() + } + + #[inline] + pub fn transaction(&self) -> &'a str { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>( + BroadcastReceived::VT_TRANSACTION, + None, + ) + .unwrap() + } + } + #[inline] + pub fn target(&self) -> &'a str { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>(BroadcastReceived::VT_TARGET, None) + .unwrap() + } + } + #[inline] + pub fn requester(&self) -> &'a str { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>( + BroadcastReceived::VT_REQUESTER, + None, + ) + .unwrap() + } + } + #[inline] + pub fn key(&self) -> &'a str { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>(BroadcastReceived::VT_KEY, None) + .unwrap() + } + } + #[inline] + pub fn timestamp(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(BroadcastReceived::VT_TIMESTAMP, Some(0)) + .unwrap() + } + } + #[inline] + pub fn contract_location(&self) -> f64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(BroadcastReceived::VT_CONTRACT_LOCATION, Some(0.0)) + .unwrap() + } + } + } + + impl flatbuffers::Verifiable for BroadcastReceived<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>( + "transaction", + Self::VT_TRANSACTION, + true, + )? + .visit_field::>("target", Self::VT_TARGET, true)? + .visit_field::>( + "requester", + Self::VT_REQUESTER, + true, + )? + .visit_field::>("key", Self::VT_KEY, true)? + .visit_field::("timestamp", Self::VT_TIMESTAMP, false)? + .visit_field::("contract_location", Self::VT_CONTRACT_LOCATION, false)? + .finish(); + Ok(()) + } + } + pub struct BroadcastReceivedArgs<'a> { + pub transaction: Option>, + pub target: Option>, + pub requester: Option>, + pub key: Option>, + pub timestamp: u64, + pub contract_location: f64, + } + impl<'a> Default for BroadcastReceivedArgs<'a> { + #[inline] + fn default() -> Self { + BroadcastReceivedArgs { + transaction: None, // required field + target: None, // required field + requester: None, // required field + key: None, // required field + timestamp: 0, + contract_location: 0.0, + } + } + } + + pub struct BroadcastReceivedBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, + } + impl<'a: 'b, 'b> BroadcastReceivedBuilder<'a, 'b> { + #[inline] + pub fn add_transaction(&mut self, transaction: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + BroadcastReceived::VT_TRANSACTION, + transaction, + ); + } + #[inline] + pub fn add_target(&mut self, target: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + BroadcastReceived::VT_TARGET, + target, + ); + } + #[inline] + pub fn add_requester(&mut self, requester: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + BroadcastReceived::VT_REQUESTER, + requester, + ); + } + #[inline] + pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { + self.fbb_ + .push_slot_always::>(BroadcastReceived::VT_KEY, key); + } + #[inline] + pub fn add_timestamp(&mut self, timestamp: u64) { + self.fbb_ + .push_slot::(BroadcastReceived::VT_TIMESTAMP, timestamp, 0); + } + #[inline] + pub fn add_contract_location(&mut self, contract_location: f64) { + self.fbb_.push_slot::( + BroadcastReceived::VT_CONTRACT_LOCATION, + contract_location, + 0.0, + ); + } + #[inline] + pub fn new( + _fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, + ) -> BroadcastReceivedBuilder<'a, 'b> { + let start = _fbb.start_table(); + BroadcastReceivedBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + self.fbb_ + .required(o, BroadcastReceived::VT_TRANSACTION, "transaction"); + self.fbb_ + .required(o, BroadcastReceived::VT_TARGET, "target"); + self.fbb_ + .required(o, BroadcastReceived::VT_REQUESTER, "requester"); + self.fbb_.required(o, BroadcastReceived::VT_KEY, "key"); + flatbuffers::WIPOffset::new(o.value()) + } + } + + impl core::fmt::Debug for BroadcastReceived<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("BroadcastReceived"); + ds.field("transaction", &self.transaction()); + ds.field("target", &self.target()); + ds.field("requester", &self.requester()); + ds.field("key", &self.key()); + ds.field("timestamp", &self.timestamp()); + ds.field("contract_location", &self.contract_location()); + ds.finish() + } + } pub enum ContractChangeOffset {} #[derive(Copy, Clone, PartialEq)] @@ -2687,6 +3344,36 @@ pub mod topology { } } + #[inline] + #[allow(non_snake_case)] + pub fn change_as_broadcast_emitted(&self) -> Option> { + if self.change_type() == ContractChangeType::BroadcastEmitted { + self.change().map(|t| { + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + unsafe { BroadcastEmitted::init_from_table(t) } + }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn change_as_broadcast_received(&self) -> Option> { + if self.change_type() == ContractChangeType::BroadcastReceived { + self.change().map(|t| { + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + unsafe { BroadcastReceived::init_from_table(t) } + }) + } else { + None + } + } + #[inline] #[allow(non_snake_case)] pub fn change_as_update_request(&self) -> Option> { @@ -2741,52 +3428,21 @@ pub mod topology { ) -> Result<(), flatbuffers::InvalidFlatbuffer> { use self::flatbuffers::Verifiable; v.visit_table(pos)? - .visit_field::>( - "contract_id", - Self::VT_CONTRACT_ID, - true, - )? - .visit_union::( - "change_type", - Self::VT_CHANGE_TYPE, - "change", - Self::VT_CHANGE, - false, - |key, v, pos| match key { - ContractChangeType::PutRequest => v - .verify_union_variant::>( - "ContractChangeType::PutRequest", - pos, - ), - ContractChangeType::PutSuccess => v - .verify_union_variant::>( - "ContractChangeType::PutSuccess", - pos, - ), - ContractChangeType::PutFailure => v - .verify_union_variant::>( - "ContractChangeType::PutFailure", - pos, - ), - ContractChangeType::UpdateRequest => v - .verify_union_variant::>( - "ContractChangeType::UpdateRequest", - pos, - ), - ContractChangeType::UpdateSuccess => v - .verify_union_variant::>( - "ContractChangeType::UpdateSuccess", - pos, - ), - ContractChangeType::UpdateFailure => v - .verify_union_variant::>( - "ContractChangeType::UpdateFailure", - pos, - ), - _ => Ok(()), - }, - )? - .finish(); + .visit_field::>("contract_id", Self::VT_CONTRACT_ID, true)? + .visit_union::("change_type", Self::VT_CHANGE_TYPE, "change", Self::VT_CHANGE, false, |key, v, pos| { + match key { + ContractChangeType::PutRequest => v.verify_union_variant::>("ContractChangeType::PutRequest", pos), + ContractChangeType::PutSuccess => v.verify_union_variant::>("ContractChangeType::PutSuccess", pos), + ContractChangeType::PutFailure => v.verify_union_variant::>("ContractChangeType::PutFailure", pos), + ContractChangeType::BroadcastEmitted => v.verify_union_variant::>("ContractChangeType::BroadcastEmitted", pos), + ContractChangeType::BroadcastReceived => v.verify_union_variant::>("ContractChangeType::BroadcastReceived", pos), + ContractChangeType::UpdateRequest => v.verify_union_variant::>("ContractChangeType::UpdateRequest", pos), + ContractChangeType::UpdateSuccess => v.verify_union_variant::>("ContractChangeType::UpdateSuccess", pos), + ContractChangeType::UpdateFailure => v.verify_union_variant::>("ContractChangeType::UpdateFailure", pos), + _ => Ok(()), + } + })? + .finish(); Ok(()) } } @@ -2886,6 +3542,26 @@ pub mod topology { ) } } + ContractChangeType::BroadcastEmitted => { + if let Some(x) = self.change_as_broadcast_emitted() { + ds.field("change", &x) + } else { + ds.field( + "change", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ContractChangeType::BroadcastReceived => { + if let Some(x) = self.change_as_broadcast_received() { + ds.field("change", &x) + } else { + ds.field( + "change", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } ContractChangeType::UpdateRequest => { if let Some(x) = self.change_as_update_request() { ds.field("change", &x) diff --git a/crates/core/src/operations/put.rs b/crates/core/src/operations/put.rs index 96122ba9b..8b78eb2c1 100644 --- a/crates/core/src/operations/put.rs +++ b/crates/core/src/operations/put.rs @@ -182,6 +182,7 @@ impl Operation for PutOp { tx = %id, %key, target = %target.peer, + sender = %sender.peer, "Puttting contract at target peer", ); @@ -266,6 +267,7 @@ impl Operation for PutOp { new_value, contract, sender, + .. } => { let target = op_manager.ring.connection_manager.own_location(); @@ -313,6 +315,7 @@ impl Operation for PutOp { new_value, contract, upstream, + .. } => { let sender = op_manager.ring.connection_manager.own_location(); let mut broadcasted_to = *broadcasted_to; @@ -325,6 +328,7 @@ impl Operation for PutOp { new_value: new_value.clone(), sender: sender.clone(), contract: contract.clone(), + target: peer.clone(), }; let f = conn_manager.send(&peer.peer, msg.into()); broadcasting.push(f); @@ -365,6 +369,7 @@ impl Operation for PutOp { id: *id, target: upstream.clone(), key: *key, + sender, }); new_state = None; } @@ -383,11 +388,13 @@ impl Operation for PutOp { "Peer completed contract value put", ); new_state = Some(PutState::Finished { key }); + if let Some(upstream) = upstream { return_msg = Some(PutMsg::SuccessfulPut { id: *id, target: upstream, key, + sender: op_manager.ring.connection_manager.own_location(), }); } else { return_msg = None; @@ -581,6 +588,7 @@ async fn try_to_broadcast( key, contract, upstream, + sender: op_manager.ring.connection_manager.own_location(), }); let op = PutOp { @@ -598,6 +606,7 @@ async fn try_to_broadcast( id, target: upstream, key, + sender: op_manager.ring.connection_manager.own_location(), }); } } @@ -832,6 +841,7 @@ mod messages { id: Transaction, target: PeerKeyLocation, key: ContractKey, + sender: PeerKeyLocation, }, /// Target the node which is closest to the key SeekNode { @@ -854,6 +864,7 @@ mod messages { new_value: WrappedState, contract: ContractContainer, upstream: PeerKeyLocation, + sender: PeerKeyLocation, }, /// Broadcasting a change to a peer, which then will relay the changes to other peers. BroadcastTo { @@ -862,6 +873,7 @@ mod messages { key: ContractKey, new_value: WrappedState, contract: ContractContainer, + target: PeerKeyLocation, }, } diff --git a/crates/core/src/operations/update.rs b/crates/core/src/operations/update.rs index 5ab272a02..e7aa16acf 100644 --- a/crates/core/src/operations/update.rs +++ b/crates/core/src/operations/update.rs @@ -192,6 +192,7 @@ impl Operation for UpdateOp { tx = %id, %key, target = %target.peer, + sender = %sender.peer, "Updating contract at target peer", ); diff --git a/crates/core/src/ring.rs b/crates/core/src/ring.rs index 1c8370e25..ddfcb26c3 100644 --- a/crates/core/src/ring.rs +++ b/crates/core/src/ring.rs @@ -844,7 +844,7 @@ impl Location { self.0 } - fn from_contract_key(bytes: &[u8]) -> Self { + pub(crate) fn from_contract_key(bytes: &[u8]) -> Self { let mut value = 0.0; let mut divisor = 256.0; for byte in bytes { diff --git a/crates/core/src/tracing.rs b/crates/core/src/tracing.rs index 49fb489ec..27b434c4c 100644 --- a/crates/core/src/tracing.rs +++ b/crates/core/src/tracing.rs @@ -217,42 +217,61 @@ impl<'a> NetEventLog<'a> { id, .. }) => { - let this_peer = &op_manager.ring.connection_manager.get_peer_key().unwrap(); + let this_peer = &op_manager.ring.connection_manager.own_location(); let key = contract.key(); EventKind::Put(PutEvent::Request { requester: this_peer.clone(), target: target.clone(), key, id: *id, + timestamp: chrono::Utc::now().timestamp() as u64, }) } - NetMessageV1::Put(PutMsg::SuccessfulPut { id, target, key }) => { - EventKind::Put(PutEvent::PutSuccess { - id: *id, - requester: op_manager.ring.connection_manager.get_peer_key().unwrap(), - target: target.clone(), - key: *key, - }) - } + NetMessageV1::Put(PutMsg::SuccessfulPut { + id, + target, + key, + sender, + }) => EventKind::Put(PutEvent::PutSuccess { + id: *id, + requester: sender.clone(), + target: target.clone(), + key: *key, + timestamp: chrono::Utc::now().timestamp() as u64, + }), NetMessageV1::Put(PutMsg::Broadcasting { new_value, broadcast_to, + broadcasted_to, // broadcasted_to n peers key, + id, + upstream, + sender, .. }) => EventKind::Put(PutEvent::BroadcastEmitted { + id: *id, + upstream: upstream.clone(), broadcast_to: broadcast_to.clone(), + broadcasted_to: *broadcasted_to, key: *key, value: new_value.clone(), + sender: sender.clone(), + timestamp: chrono::Utc::now().timestamp() as u64, }), NetMessageV1::Put(PutMsg::BroadcastTo { sender, new_value, key, + target, + id, .. }) => EventKind::Put(PutEvent::BroadcastReceived { - requester: sender.peer.clone(), + id: *id, + requester: sender.clone(), key: *key, value: new_value.clone(), + target: target.clone(), + timestamp: chrono::Utc::now().timestamp() as u64, }), NetMessageV1::Get(GetMsg::ReturnGet { key, @@ -475,7 +494,7 @@ async fn connect_to_metrics_server() -> Option { let msg = PeerChange::added_connection_msg( (&send_msg.tx != Transaction::NULL).then(|| send_msg.tx.to_string()), - (from_peer.clone(), from_loc.as_f64()), - (to_peer.clone(), to_loc.as_f64()), + (from_peer.clone().to_string(), from_loc.as_f64()), + (to_peer.clone().to_string(), to_loc.as_f64()), ); ws_stream.send(Message::Binary(msg)).await } EventKind::Disconnected { from } => { - let msg = PeerChange::removed_connection_msg(from.clone(), send_msg.peer_id.clone()); + let msg = PeerChange::removed_connection_msg( + from.clone().to_string(), + send_msg.peer_id.clone().to_string(), + ); ws_stream.send(Message::Binary(msg)).await } EventKind::Put(PutEvent::Request { requester, key, target, + timestamp, .. }) => { + let contract_location = Location::from_contract_key(key.as_bytes()); let msg = ContractChange::put_request_msg( send_msg.tx.to_string(), key.to_string(), requester.to_string(), target.peer.to_string(), + *timestamp, + contract_location.as_f64(), ); ws_stream.send(Message::Binary(msg)).await } @@ -534,13 +560,60 @@ async fn send_to_metrics_server( requester, target, key, + timestamp, .. }) => { + let contract_location = Location::from_contract_key(key.as_bytes()); + let msg = ContractChange::put_success_msg( send_msg.tx.to_string(), key.to_string(), requester.to_string(), target.peer.to_string(), + *timestamp, + contract_location.as_f64(), + ); + ws_stream.send(Message::Binary(msg)).await + } + EventKind::Put(PutEvent::BroadcastEmitted { + id, + upstream, + broadcast_to, // broadcast_to n peers + broadcasted_to, + key, + sender, + timestamp, + .. + }) => { + let contract_location = Location::from_contract_key(key.as_bytes()); + let msg = ContractChange::broadcast_emitted_msg( + id.to_string(), + upstream.to_string(), + broadcast_to.iter().map(|p| p.to_string()).collect(), + *broadcasted_to, + key.to_string(), + sender.to_string(), + *timestamp, + contract_location.as_f64(), + ); + ws_stream.send(Message::Binary(msg)).await + } + EventKind::Put(PutEvent::BroadcastReceived { + id, + target, + requester, + key, + timestamp, + .. + }) => { + let contract_location = Location::from_contract_key(key.as_bytes()); + let msg = ContractChange::broadcast_received_msg( + id.to_string(), + target.to_string(), + requester.to_string(), + key.to_string(), + *timestamp, + contract_location.as_f64(), ); ws_stream.send(Message::Binary(msg)).await } @@ -905,31 +978,42 @@ enum ConnectEvent { enum PutEvent { Request { id: Transaction, - requester: PeerId, + requester: PeerKeyLocation, key: ContractKey, target: PeerKeyLocation, + timestamp: u64, }, PutSuccess { id: Transaction, - requester: PeerId, + requester: PeerKeyLocation, target: PeerKeyLocation, key: ContractKey, + timestamp: u64, }, BroadcastEmitted { + id: Transaction, + upstream: PeerKeyLocation, /// subscribed peers broadcast_to: Vec, + broadcasted_to: usize, /// key of the contract which value was being updated key: ContractKey, /// value that was put value: WrappedState, + sender: PeerKeyLocation, + timestamp: u64, }, BroadcastReceived { + id: Transaction, /// peer who started the broadcast op - requester: PeerId, + requester: PeerKeyLocation, /// key of the contract which value was being updated key: ContractKey, /// value that was put value: WrappedState, + /// target peer + target: PeerKeyLocation, + timestamp: u64, }, } diff --git a/crates/fdev/src/network_metrics_server.rs b/crates/fdev/src/network_metrics_server.rs index c2846d78b..b1c916b7f 100644 --- a/crates/fdev/src/network_metrics_server.rs +++ b/crates/fdev/src/network_metrics_server.rs @@ -1,4 +1,4 @@ -use std::{net::Ipv4Addr, path::PathBuf, sync::Arc, time::Duration}; +use std::{fmt::Display, net::Ipv4Addr, path::PathBuf, sync::Arc, time::Duration}; use axum::{ body::Body, @@ -12,11 +12,8 @@ use axum::{ Router, }; use dashmap::DashMap; -use freenet::{ - dev_tool::PeerId, - generated::{ - topology::ControllerResponse, ChangesWrapper, ContractChange, PeerChange, TryFromFbs, - }, +use freenet::generated::{ + topology::ControllerResponse, ChangesWrapper, ContractChange, PeerChange, TryFromFbs, }; use futures::{SinkExt, StreamExt}; use serde::{Deserialize, Serialize}; @@ -84,6 +81,7 @@ async fn push_stats( async fn push_interface(ws: WebSocket, state: Arc) -> anyhow::Result<()> { let (mut tx, mut rx) = ws.split(); while let Some(msg) = rx.next().await { + let received_random_id = rand::random::(); match msg { Ok(msg) => { let msg = match msg { @@ -96,51 +94,54 @@ async fn push_interface(ws: WebSocket, state: Arc) -> anyhow::Resul } _ => continue, }; - match PeerChange::try_decode_fbs(&msg) { - Ok(PeerChange::Error(err)) => { - tracing::error!(error = %err.message(), "Received error from peer"); - break; - } + + let mut decoding_errors = vec![]; + + match ContractChange::try_decode_fbs(&msg) { + Ok(ContractChange::PutFailure(_err)) => todo!(), Ok(change) => { - if let Err(err) = state.save_record(ChangesWrapper::PeerChange(change)) { + if let Err(err) = state.save_record(ChangesWrapper::ContractChange(change)) + { tracing::error!(error = %err, "Failed saving report"); tx.send(Message::Binary(ControllerResponse::into_fbs_bytes(Err( format!("{err}"), )))) .await?; } + continue; } Err(decoding_error) => { - tracing::error!(error = %decoding_error, "Failed to decode message"); - tx.send(Message::Binary(ControllerResponse::into_fbs_bytes(Err( - format!("{decoding_error}"), - )))) - .await?; + tracing::warn!(%received_random_id, error = %decoding_error, "Failed to decode message from 1st ContractChange"); + decoding_errors.push(decoding_error.to_string()); } } - match ContractChange::try_decode_fbs(&msg) { - Ok(ContractChange::PutFailure(_err)) => { - // FIXME: handle put failure - tracing::error!(error = "Failed to put contract"); + + match PeerChange::try_decode_fbs(&msg) { + Ok(PeerChange::Error(err)) => { + tracing::error!(error = %err.message(), "Received error from peer"); + break; } Ok(change) => { - if let Err(err) = state.save_record(ChangesWrapper::ContractChange(change)) - { + if let Err(err) = state.save_record(ChangesWrapper::PeerChange(change)) { tracing::error!(error = %err, "Failed saving report"); tx.send(Message::Binary(ControllerResponse::into_fbs_bytes(Err( format!("{err}"), )))) .await?; } + continue; } Err(decoding_error) => { - tracing::error!(error = %decoding_error, "Failed to decode message"); - tx.send(Message::Binary(ControllerResponse::into_fbs_bytes(Err( - format!("{decoding_error}"), - )))) - .await?; + tracing::warn!(error = %decoding_error, "Failed to decode message"); + decoding_errors.push(decoding_error.to_string()); } } + + tracing::error!(%received_random_id, "The message was not decoded by any fbs type"); + tx.send(Message::Binary(ControllerResponse::into_fbs_bytes(Err( + decoding_errors.join(", "), + )))) + .await?; } Err(e) => { tracing::debug!("Websocket error: {}", e); @@ -173,6 +174,94 @@ async fn pull_interface(ws: WebSocket, state: Arc) -> anyhow::Resul ); tx.send(Message::Binary(msg)).await?; } + + for transaction in state.transactions_data.iter() { + tracing::info!("sending transaction data"); + for change in transaction.value() { + let msg = match change { + Change::PutRequest { + tx_id, + key, + requester, + target, + timestamp, + contract_location, + } => { + tracing::info!("sending put request"); + ContractChange::put_request_msg( + tx_id.clone(), + key.to_string(), + requester.to_string(), + target.to_string(), + *timestamp, + *contract_location, + ) + } + Change::PutSuccess { + tx_id, + key, + target, + timestamp, + requester, + contract_location, + } => { + tracing::info!("sending put success"); + ContractChange::put_success_msg( + tx_id.clone(), + key.to_string(), + requester.to_string(), + target.to_string(), + *timestamp, + *contract_location, + ) + } + Change::BroadcastEmitted { + tx_id, + upstream, + broadcast_to, + broadcasted_to, + key, + sender, + timestamp, + contract_location, + } => { + tracing::info!("sending broadcast emitted"); + ContractChange::broadcast_emitted_msg( + tx_id.clone(), + upstream, + broadcast_to.iter().map(|s| s.to_string()).collect(), + *broadcasted_to, + key, + sender, + *timestamp, + *contract_location, + ) + } + Change::BroadcastReceived { + tx_id, + key, + requester, + target, + timestamp, + contract_location, + } => { + tracing::info!("sending broadcast received"); + ContractChange::broadcast_received_msg( + tx_id, + target, + requester, + key, + *timestamp, + *contract_location, + ) + } + + _ => continue, + }; + tx.send(Message::Binary(msg)).await?; + } + } + let mut changes = state.changes.subscribe(); while let Ok(msg) = changes.recv().await { match msg { @@ -197,13 +286,77 @@ async fn pull_interface(ws: WebSocket, state: Arc) -> anyhow::Resul key, requester, target, + timestamp, + contract_location, } => { tracing::debug!(%tx_id, %key, %requester, %target, "sending put request"); - let msg = ContractChange::put_request_msg(tx_id, key, requester, target); + let msg = ContractChange::put_request_msg( + tx_id, + key, + requester, + target, + timestamp, + contract_location, + ); tx.send(Message::Binary(msg)).await?; } - Change::PutSuccess { tx_id, key, target } => { - let msg = ContractChange::put_success_msg(tx_id, key, target.clone(), target); + Change::PutSuccess { + tx_id, + key, + target, + requester, + timestamp, + contract_location, + } => { + tracing::debug!(%tx_id, %key, %requester, %target, "sending put success"); + let msg = ContractChange::put_success_msg( + tx_id, + key, + requester, + target, + timestamp, + contract_location, + ); + tx.send(Message::Binary(msg)).await?; + } + Change::BroadcastEmitted { + tx_id, + upstream, + broadcast_to, + broadcasted_to, + key, + sender, + timestamp, + contract_location, + } => { + let msg = ContractChange::broadcast_emitted_msg( + tx_id, + upstream, + broadcast_to, + broadcasted_to, + key, + sender, + timestamp, + contract_location, + ); + tx.send(Message::Binary(msg)).await?; + } + Change::BroadcastReceived { + tx_id, + key, + requester, + target, + timestamp, + contract_location, + } => { + let msg = ContractChange::broadcast_received_msg( + tx_id, + target, + requester, + key, + timestamp, + contract_location, + ); tx.send(Message::Binary(msg)).await?; } } @@ -213,15 +366,23 @@ async fn pull_interface(ws: WebSocket, state: Arc) -> anyhow::Resul struct ServerState { changes: tokio::sync::broadcast::Sender, - peer_data: DashMap, - transactions_data: DashMap>, + peer_data: DashMap, + transactions_data: DashMap>, + contract_data: DashMap, } struct PeerData { - connections: Vec<(PeerId, f64)>, + connections: Vec<(String, f64)>, location: f64, } +#[derive(Debug, Serialize, Deserialize)] +struct ContractData { + location: f64, + connections: Vec, + key: String, +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) enum Change { AddedConnection { @@ -240,39 +401,64 @@ pub(crate) enum Change { key: String, requester: String, target: String, + timestamp: u64, + contract_location: f64, }, PutSuccess { tx_id: String, key: String, + requester: String, target: String, + timestamp: u64, + contract_location: f64, + }, + BroadcastEmitted { + tx_id: String, + upstream: String, + broadcast_to: Vec, + broadcasted_to: usize, + key: String, + sender: String, + timestamp: u64, + contract_location: f64, + }, + BroadcastReceived { + tx_id: String, + key: String, + requester: String, + target: String, + timestamp: u64, + contract_location: f64, }, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub(crate) struct PeerIdHumanReadable(PeerId); +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub(crate) struct PeerIdHumanReadable(String); -impl From for PeerIdHumanReadable { - fn from(peer_id: PeerId) -> Self { - Self(peer_id) +impl Display for PeerIdHumanReadable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) } } -impl std::fmt::Display for PeerIdHumanReadable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0.addr) +impl From for PeerIdHumanReadable { + fn from(peer_id: String) -> Self { + Self(peer_id) } } impl ServerState { - fn save_record(&self, change: ChangesWrapper) -> anyhow::Result<()> { + fn save_record(&self, change: ChangesWrapper) -> Result<(), anyhow::Error> { match change { ChangesWrapper::PeerChange(PeerChange::AddedConnection(added)) => { - let from_peer_id: PeerId = bincode::deserialize(added.from().bytes())?; + let from_peer_id = String::from_utf8(added.from().bytes().to_vec())?; let from_loc = added.from_location(); - let to_peer_id: PeerId = bincode::deserialize(added.to().bytes())?; + let to_peer_id = String::from_utf8(added.to().bytes().to_vec())?; let to_loc = added.to_location(); + tracing::info!(%from_peer_id, %to_peer_id, "--addedconnection adding connection"); + match self.peer_data.entry(from_peer_id.clone()) { dashmap::mapref::entry::Entry::Occupied(mut occ) => { let connections = &mut occ.get_mut().connections; @@ -310,8 +496,8 @@ impl ServerState { }); } ChangesWrapper::PeerChange(PeerChange::RemovedConnection(removed)) => { - let from_peer_id = bincode::deserialize(removed.from().bytes())?; - let at_peer_id = bincode::deserialize(removed.at().bytes())?; + let from_peer_id = String::from_utf8(removed.from().bytes().to_vec())?; + let at_peer_id = String::from_utf8(removed.at().bytes().to_vec())?; if let Some(mut entry) = self.peer_data.get_mut(&from_peer_id) { entry @@ -335,18 +521,36 @@ impl ServerState { let key = change.key().to_string(); let requester = change.requester().to_string(); let target = change.target().to_string(); + let timestamp = change.timestamp(); + let contract_location = change.contract_location(); - if self.transactions_data.get_mut(&tx_id).is_some() { - unreachable!( - "found an already included in logs transaction when it should create it." - ); + if tx_id.is_empty() { + return Err(anyhow::anyhow!("tx_id is empty")); + } + + if key.is_empty() { + return Err(anyhow::anyhow!("key is empty")); + } + + if requester.is_empty() { + return Err(anyhow::anyhow!("requester is empty")); + } + + if let Some(_entry) = self.transactions_data.get_mut(&tx_id) { + tracing::error!("this tx should not be included on transactions_data"); + + unreachable!(); } else { self.transactions_data.insert( tx_id.clone(), - vec![format!( - "tx_id {} key {} req {} target {} state PutRequest", - tx_id, key, requester, target - )], + vec![Change::PutRequest { + tx_id: tx_id.clone(), + key: key.clone(), + requester: requester.clone(), + target: target.clone(), + timestamp, + contract_location, + }], ); } @@ -357,6 +561,8 @@ impl ServerState { key, requester, target, + timestamp, + contract_location, }); } ChangesWrapper::ContractChange(ContractChange::PutSuccess(change)) => { @@ -364,20 +570,200 @@ impl ServerState { let key = change.key().to_string(); let requester = change.requester().to_string(); let target = change.target().to_string(); + let timestamp = change.timestamp(); + let contract_location = change.contract_location(); - if let Some(mut entry) = self.transactions_data.get_mut(&tx_id) { - entry.push(format!( - "tx_id {} key {} req {} target {} state PutSuccess", - tx_id, key, requester, target - )); - } else { - tracing::error!("transaction data not found for this tx when it should."); - unreachable!() + if tx_id.is_empty() { + return Err(anyhow::anyhow!("tx_id is empty")); + } + + if key.is_empty() { + return Err(anyhow::anyhow!("key is empty")); + } + + if requester.is_empty() { + return Err(anyhow::anyhow!("requester is empty")); + } + + match self.transactions_data.entry(tx_id.clone()) { + dashmap::mapref::entry::Entry::Occupied(mut occ) => { + tracing::info!("found transaction data, adding PutSuccess to changes"); + let changes = occ.get_mut(); + changes.push(Change::PutSuccess { + tx_id: tx_id.clone(), + key: key.clone(), + target: target.clone(), + requester: requester.clone(), + timestamp, + contract_location, + }); + //connections.sort_unstable_by(|a, b| a.cmp(&b.0)); + //connections.dedup(); + } + dashmap::mapref::entry::Entry::Vacant(_vac) => { + // this should not happen + tracing::error!("this tx should be included on transactions_data. It should exists a PutRequest before the PutSuccess."); + unreachable!(); + } } tracing::debug!(%tx_id, %key, %requester, %target, "checking values from save_record -- putsuccess"); - let _ = self.changes.send(Change::PutSuccess { tx_id, key, target }); + match self.contract_data.entry(key.clone()) { + dashmap::mapref::entry::Entry::Occupied(mut occ) => { + let connections = &mut occ.get_mut().connections; + + connections.push(target.clone()); + //connections.sort_unstable_by(|a, b| a.cmp(&b.0)); + //connections.dedup(); + } + dashmap::mapref::entry::Entry::Vacant(vac) => { + vac.insert(ContractData { + connections: vec![target.clone()], + location: contract_location, + key: key.clone(), + }); + } + } + + tracing::debug!("after contract_data updates"); + + let _ = self.changes.send(Change::PutSuccess { + tx_id, + key, + target, + requester, + timestamp, + contract_location, + }); + } + + ChangesWrapper::ContractChange(ContractChange::BroadcastEmitted(broadcast_data)) => { + let tx_id = broadcast_data.transaction().to_string(); + let upstream = broadcast_data.upstream().to_string(); + let broadcast_to = broadcast_data + .broadcast_to() + .unwrap() + .into_iter() + .map(|s| s.to_string()) + .collect::>(); + let broadcasted_to = broadcast_data.broadcasted_to(); + let key = broadcast_data.key().to_string(); + let sender = broadcast_data.sender().to_string(); + + let timestamp = broadcast_data.timestamp(); + let contract_location = broadcast_data.contract_location(); + + if broadcast_to.is_empty() { + return Err(anyhow::anyhow!("broadcast_to is empty")); + } + + tracing::info!(?broadcast_to, "save_record broadcast_to"); + + if tx_id.is_empty() { + return Err(anyhow::anyhow!("tx_id is empty")); + } + + if key.is_empty() { + return Err(anyhow::anyhow!("key is empty")); + } + + match self.transactions_data.entry(tx_id.clone()) { + dashmap::mapref::entry::Entry::Occupied(mut occ) => { + tracing::info!( + "found transaction data, adding BroadcastEmitted to history" + ); + let changes = occ.get_mut(); + changes.push(Change::BroadcastEmitted { + tx_id: tx_id.clone(), + upstream: upstream.clone(), + broadcast_to: broadcast_to.clone(), + broadcasted_to: broadcasted_to as usize, + key: key.clone(), + sender: sender.clone(), + timestamp, + contract_location, + }); + + //connections.sort_unstable_by(|a, b| a.cmp(&b.0)); + //connections.dedup(); + } + dashmap::mapref::entry::Entry::Vacant(_vac) => { + // this should not happen + tracing::error!("this tx should be included on transactions_data. It should exists a PutRequest before BroadcastEmitted."); + unreachable!(); + } + } + + tracing::debug!(%tx_id, %key, %upstream, %sender, "checking values from save_record -- broadcastemitted"); + + let _ = self.changes.send(Change::BroadcastEmitted { + tx_id, + upstream, + broadcast_to, + broadcasted_to: broadcasted_to as usize, + key, + sender, + timestamp, + contract_location, + }); + } + + ChangesWrapper::ContractChange(ContractChange::BroadcastReceived(broadcast_data)) => { + let tx_id = broadcast_data.transaction().to_string(); + let key = broadcast_data.key().to_string(); + let requester = broadcast_data.requester().to_string(); + let target = broadcast_data.target().to_string(); + let timestamp = broadcast_data.timestamp(); + let contract_location = broadcast_data.contract_location(); + + if tx_id.is_empty() { + return Err(anyhow::anyhow!("tx_id is empty")); + } + + if key.is_empty() { + return Err(anyhow::anyhow!("key is empty")); + } + + if requester.is_empty() { + return Err(anyhow::anyhow!("requester is empty")); + } + + match self.transactions_data.entry(tx_id.clone()) { + dashmap::mapref::entry::Entry::Occupied(mut occ) => { + tracing::info!( + "found transaction data, adding BroadcastReceived to history" + ); + let changes = occ.get_mut(); + changes.push(Change::BroadcastReceived { + tx_id: tx_id.clone(), + key: key.clone(), + requester: requester.clone(), + target: target.clone(), + timestamp, + contract_location, + }); + + //connections.sort_unstable_by(|a, b| a.cmp(&b.0)); + //connections.dedup(); + } + dashmap::mapref::entry::Entry::Vacant(_vac) => { + // this should not happen + tracing::error!("this tx should be included on transactions_data. It should exists a PutRequest before BroadcastReceived."); + unreachable!(); + } + } + + tracing::debug!(%tx_id, %key, %requester, %target, "checking values from save_record -- broadcastreceived"); + + let _ = self.changes.send(Change::BroadcastReceived { + tx_id, + key, + requester, + target, + timestamp, + contract_location, + }); } _ => unreachable!(), diff --git a/crates/fdev/src/network_metrics_server/v1.rs b/crates/fdev/src/network_metrics_server/v1.rs index a7de9c1ba..a0e2c66a2 100644 --- a/crates/fdev/src/network_metrics_server/v1.rs +++ b/crates/fdev/src/network_metrics_server/v1.rs @@ -19,6 +19,7 @@ pub(super) async fn run_server( changes, peer_data: DashMap::new(), transactions_data: DashMap::new(), + contract_data: DashMap::new(), })); tracing::info!("Starting metrics server on port {port}"); diff --git a/crates/fdev/src/testing/network.rs b/crates/fdev/src/testing/network.rs index 2ff4becf8..8cf6b985c 100644 --- a/crates/fdev/src/testing/network.rs +++ b/crates/fdev/src/testing/network.rs @@ -627,6 +627,8 @@ impl Runnable for NetworkPeer { } }; + tracing::info!("Starting event generator for peer {}", peer.clone()); + let event_generator = NetworkEventGenerator::new(peer.clone(), memory_event_generator, ws_client); diff --git a/network-monitor/.prettierrc b/network-monitor/.prettierrc index 330f17ff1..3a43b2683 100644 --- a/network-monitor/.prettierrc +++ b/network-monitor/.prettierrc @@ -1,5 +1,5 @@ { "tabWidth": 4, - "bracketSpacing": true, - "useTabs": false + "useTabs": false, + "semi": true } diff --git a/network-monitor/dist/index.html b/network-monitor/dist/index.html index 337113199..333bc1be8 100644 --- a/network-monitor/dist/index.html +++ b/network-monitor/dist/index.html @@ -74,6 +74,11 @@

Connections history

+ diff --git a/network-monitor/src/app.ts b/network-monitor/src/app.ts index 766f7aa37..db1f4ed4e 100644 --- a/network-monitor/src/app.ts +++ b/network-monitor/src/app.ts @@ -1,16 +1,31 @@ import * as flatbuffers from "flatbuffers"; import * as fbTopology from "./generated/topology"; import { handleChange } from "./topology"; -import { handlePutRequest, handlePutSuccess } from "./transactions-data"; -import { parse_put_msg_data } from "./utils"; +import { + handleBroadcastEmitted, + handleBroadcastReceived, + handlePutRequest, + handlePutSuccess, +} from "./transactions-data"; +import { + get_change_type, + parse_broadcast_emitted_msg, + parse_broadcast_received_msg, + parse_put_request_msg_data, + parse_put_success_msg_data, +} from "./utils"; +import { ChangeType } from "./type_definitions"; +import { unionToContractChangeType } from "./generated/topology/contract-change-type"; let connection_established = false; const ws_connection_interval = setInterval(() => { if (!connection_established) { try { + console.log("Attempting to establish WS Connection"); + const socket = new WebSocket( - "ws://127.0.0.1:55010/pull-stats/peer-changes/" + "ws://127.0.0.1:55010/v1/pull-stats/peer-changes/" ); socket.addEventListener("open", () => { @@ -36,91 +51,145 @@ function handleChanges(event: MessageEvent) { .then((uint8Array) => { const buf = new flatbuffers.ByteBuffer(uint8Array); + let errors = []; + try { const contractChange = fbTopology.ContractChange.getRootAsContractChange(buf); - console.log(contractChange.changeType()); + let now_change_type = get_change_type( + contractChange.changeType() + ); - if ( - contractChange.changeType() === - fbTopology.ContractChangeType.PutRequest - ) { + if (now_change_type == ChangeType.BROADCAST_EMITTED) { let { transaction, - contract_id, - target, - requester, - change_type, - } = parse_put_msg_data( + upstream, + broadcast_to, + key, + requester: sender, + timestamp, + contract_location, + } = parse_broadcast_emitted_msg( contractChange, - fbTopology.ContractChangeType.PutRequest + contractChange.changeType() ); - handlePutRequest( + handleBroadcastEmitted( transaction, - contract_id, - target, - requester, - change_type + upstream, + broadcast_to, + key, + sender, + timestamp, + contract_location ); return; } - if ( - contractChange.changeType() === - fbTopology.ContractChangeType.PutSuccess - ) { + if (now_change_type == ChangeType.BROADCAST_RECEIVED) { let { transaction, - contract_id, target, requester, + key, change_type, - } = parse_put_msg_data( + timestamp, + contract_location, + } = parse_broadcast_received_msg( contractChange, - fbTopology.ContractChangeType.PutSuccess + contractChange.changeType() ); - handlePutSuccess( + let fixed_target = target.split(" (@")[0]; + + let broadcast_target_peer_location = target + .split(" (@")[1] + .split(")")[0]; + + handleBroadcastReceived( transaction, - contract_id, - target, + fixed_target, requester, - change_type + key, + change_type, + timestamp, + contract_location ); return; } - if ( - contractChange.changeType() === - fbTopology.ContractChangeType.PutFailure - ) { + if (now_change_type == ChangeType.PUT_REQUEST) { let { transaction, contract_id, target, requester, change_type, - } = parse_put_msg_data( + timestamp, + contract_location, + } = parse_put_request_msg_data( contractChange, - fbTopology.ContractChangeType.PutFailure + contractChange.changeType() ); - handlePutSuccess( + if (change_type == ChangeType.PUT_REQUEST) { + handlePutRequest( + transaction, + contract_id, + target, + requester, + change_type, + timestamp, + contract_location + ); + + return; + } + } + + if (now_change_type == ChangeType.PUT_SUCCESS) { + let { transaction, contract_id, target, requester, - change_type + change_type, + timestamp, + contract_location, + } = parse_put_success_msg_data( + contractChange, + contractChange.changeType() ); + if (change_type == ChangeType.PUT_SUCCESS) { + handlePutSuccess( + transaction, + contract_id, + target, + requester, + change_type, + timestamp, + contract_location + ); + + return; + } + } + + if ( + contractChange.changeType() === + fbTopology.ContractChangeType.PutFailure + ) { + console.log("Put Failure"); + return; } } catch (e) { console.error(e); + errors.push(e); } try { @@ -129,7 +198,13 @@ function handleChanges(event: MessageEvent) { handleChange(peerChange); return; - } catch (e) {} + } catch (e) { + errors.push(e); + } + + if (errors.length > 0) { + console.error("Failed to handle message:", errors); + } }) .catch((error) => { console.error("Failed to handle message:", error); diff --git a/network-monitor/src/contract-detail.tsx b/network-monitor/src/contract-detail.tsx index 1548b3c7b..0a7fe0b36 100644 --- a/network-monitor/src/contract-detail.tsx +++ b/network-monitor/src/contract-detail.tsx @@ -1,32 +1,28 @@ import { useEffect, useState } from "react"; -import { createRoot } from "react-dom/client"; import { TransactionDetailInterface, - TransactionPeerInterface, - TransactionData + TransactionData, + TransactionDetailPeersHistoryInterface, + FilterDictionaryInterface, + ContractHistoryInterface, + ChangeType, + RingVisualizationPoint } from "./type_definitions"; -import { PeerId } from "./topology"; -import { another_ring_visualization } from "./ring-visualization"; +import {filter_by_page, get_all_pages, get_peers_caching_the_contract, rust_timestamp_to_utc_string} from "./utils"; +import {Pagination} from "./pagination"; +import {RingVisualization} from "./ring-visualization"; -interface TransactionDetailPeersHistoryInterface { - tx_peer_list: Array; -} - -interface FilterInterface { - filter_type: string; - filter_value: string; -} - -interface FilterDictionaryInterface { - [key: string]: FilterInterface; -} - -let ring_mock_data = []; const ContractPeersHistory = ({ tx_peer_list, }: TransactionDetailPeersHistoryInterface) => { const [filter, set_filter] = useState({}); const [filtered_list, set_filtered_list] = useState(tx_peer_list); + const [order_by, set_order_by] = useState("timestamp"); + const [order_direction, set_order_direction] = useState("asc"); + const [order_is_loading, set_order_is_loading] = useState(false); + const [page, set_page] = useState(1); + const [inner_tx_list, set_inner_tx_list] = useState>([]); + const [active_peer_list, set_active_peer_list] = useState | null>(null); const add_filter = (filter_type: string, filter_value: string) => { if (check_if_contains_filter(filter_type)) { @@ -40,6 +36,8 @@ const ContractPeersHistory = ({ set_filter(filter); + set_page(1); + update_filtered_list(); }; @@ -57,6 +55,22 @@ const ContractPeersHistory = ({ }); }); + console.log("filtered_list", filtered_list); + + filtered_list = filtered_list.sort((a, b) => { + if (order_by === "timestamp") { + if (order_direction === "asc") { + return a.timestamp > b.timestamp ? 1 : -1; + } else { + return a.timestamp < b.timestamp ? 1 : -1; + } + } else { + return 0; + } + }); + + set_inner_tx_list(filter_by_page(filtered_list, page)); + set_filtered_list(filtered_list); }; @@ -71,58 +85,24 @@ const ContractPeersHistory = ({ useEffect(() => { update_filtered_list(); + + if (order_is_loading) { + setTimeout(() => { + set_order_is_loading(false); + }, 500) + } + }, [filter, order_by, order_direction]); + + useEffect(() => { + clear_all_filters(); + set_page(1); + }, [tx_peer_list]); + + useEffect(() => { + set_inner_tx_list(filter_by_page(filtered_list, page)); + }, [page, filtered_list]); + - let ring_mock_data = [ - { - id: new PeerId("1"), - currentLocation: 0.123485, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - { - id: new PeerId("2"), - currentLocation: 0.183485, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - { - id: new PeerId("3"), - currentLocation: 0.323485, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - { - id: new PeerId("4"), - currentLocation: 0.423485, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - { - id: new PeerId("5"), - currentLocation: 0.783285, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - ]; - - // ringHistogram(ring_mock_data); - - // const graphContainer = d3.select( - // document.getElementById("other-peer-conns-graph") - // ); - - // ringVisualization(ring_mock_data[0], graphContainer, 1.25); - }, [filter]); const check_if_contains_filter = (filter_type: string) => { return filter[filter_type] !== undefined; @@ -133,15 +113,20 @@ const ContractPeersHistory = ({ id="transaction-peers-history" className="block" style={{ marginTop: 20 }} + onMouseLeave={() => set_active_peer_list(null)} > + set_page(page)}/>

Contract Transactions History

{Object.keys(filter).length > 0 && (
-
)} + +
set_active_peer_list(null)}>{active_peer_list?.map((p, index) =>

{p}

)}
+ Contract Id {check_if_contains_filter("contract_id") && ( - )} + + - {filtered_list.map((tx) => ( - + {inner_tx_list.map((tx, index) => ( + + + ))} @@ -265,8 +277,10 @@ const ContractPeersHistory = ({ ); }; + + // TODO: use real types -const ContractHistory = ({ contract_history }: any) => ( +const ContractHistory = ({ contract_history }: ContractHistoryInterface) => (

Contract History

+ Requester
+ Peer Location +
Transaction Id {check_if_contains_filter("transaction_id") && ( - + (Upstream)
Requester {check_if_contains_filter("requester") && ( -
Target {check_if_contains_filter("target") && ( - Change Type {check_if_contains_filter("change_type") && ( - )} + Timestamp + + +
add_filter("contract_id", tx.contract_id) @@ -217,6 +220,9 @@ const ContractPeersHistory = ({ > {tx.contract_id.slice(-8)} + {tx.requester_location} + add_filter("transaction_id", tx.transaction_id) @@ -225,7 +231,7 @@ const ContractPeersHistory = ({ cursor: "pointer", }} > - {tx.transaction_id} + {tx.transaction_id.slice(-12)} @@ -235,6 +241,8 @@ const ContractPeersHistory = ({ cursor: "pointer", }} > + + {tx.change_type == ChangeType.BROADCAST_EMITTED &&

({tx.upstream?.slice(-8)})

} {tx.requester.slice(-8)}
{tx.change_type == ChangeType.BROADCAST_EMITTED && set_active_peer_list(tx.target)} } > - {tx.target.slice(-8)} + {tx.change_type == ChangeType.BROADCAST_EMITTED ? `${tx.target.length} peers` : tx.target.slice(-8)} @@ -257,6 +266,9 @@ const ContractPeersHistory = ({ > {tx.change_type} + {rust_timestamp_to_utc_string(tx.timestamp)} +
( +}: TransactionDetailInterface) => { + const [contract_location, set_contract_location] = useState(null); + const [caching_peers_locations, set_caching_peers_locations] = useState>([]); + + useEffect(() => { + if (!tx_history) { + return; + } + + console.log("tx_history", tx_history); + let caching_locations = get_peers_caching_the_contract(tx_history); + + console.log("caching_locations", caching_locations); + + set_contract_location({localization: tx_history[0].contract_location, peerId: "ideal"}); + set_caching_peers_locations(caching_locations); + }, [tx_history]); + + return (
Contract Details

Contract Key {transaction.contract_id}

+

Contract Location {transaction.contract_location}

Requester {transaction.requester}

Target {transaction.target}

{/*

Status {transaction.status}

@@ -359,9 +392,11 @@ export const ContractDetail = ({

Location Peers

+ + +
- {/*another_ring_visualization()*/}
{tx_history && ( @@ -372,5 +407,6 @@ export const ContractDetail = ({
); +} diff --git a/network-monitor/src/contracts.tsx b/network-monitor/src/contracts.tsx index 70f89b595..b9d62e79d 100644 --- a/network-monitor/src/contracts.tsx +++ b/network-monitor/src/contracts.tsx @@ -2,39 +2,112 @@ import { useEffect, useState } from "react"; import { TransactionData, TransactionPeerInterface, TxTableInterface } from "./type_definitions"; import {all_contracts} from "./transactions-data"; import {ContractDetail} from "./contract-detail"; +import {filter_by_page, get_all_pages, rust_timestamp_to_utc_string} from "./utils"; +import {Pagination} from "./pagination"; -export const ContractsTable = ({ open_tx_detail, tx_list }: TxTableInterface) => ( -
- - - - - - - - {/* - - */} - - - - { - tx_list?.map((tx, index) => ( - - - - - - - {/* - - */} - - )) +export const ContractsTable = ({ open_tx_detail, tx_list }: TxTableInterface) => { + const [ordered_tx_list, set_ordered_tx_list] = useState>([]); + const [inner_tx_list, set_inner_tx_list] = useState>([]); + const [order_by, set_order_by] = useState("timestamp"); + const [order_direction, set_order_direction] = useState("asc"); + const [loading, set_loading] = useState(true); + const [page, set_page] = useState(1); + + const order_tx_list = (tx_list: Array) => { + let updated_tx_list = tx_list; + updated_tx_list = updated_tx_list.sort((a, b) => { + if (order_by === "timestamp") { + if (order_direction === "asc") { + return a.timestamp > b.timestamp ? 1 : -1; + } else { + return a.timestamp < b.timestamp ? 1 : -1; + } + } else { + return 0; + } + }); + + return updated_tx_list; + } + + + + useEffect(() => { + if (tx_list) { + let ordered_list = order_tx_list(tx_list); + set_ordered_tx_list(ordered_list); + set_inner_tx_list(order_tx_list(filter_by_page(tx_list, page))); + + + if (loading) { + setTimeout(() => { + set_loading(false); + }, 1000); } - -
Contract KeyLast Requester Peer IdLast Target Peer IdLast Transaction IdLast TypeStatusStartedFinalized
open_tx_detail(tx.contract_id)} style={{cursor: "pointer"}}>{tx.contract_id.slice(-8)}{tx.requester.slice(-8)}{tx.target.slice(-8)}{tx.transaction_id.slice(-8)}{tx.change_type}{tx.status}{tx.started}{tx.finalized}
-); + } + }, [tx_list, order_by, order_direction]); + + + useEffect(() => { + if (tx_list) { + set_inner_tx_list(filter_by_page(ordered_tx_list, page)); + } + }, [page]); + + + return ( + <> + {set_page(page)}}/> + + + + + + + + + + + {/* + + */} + + + + { + inner_tx_list?.map((tx, index) => ( + + + + + + + + + {/* + + */} + + )) + } + + +
Contract KeyContract LocationLast Requester Peer IdLast Target Peer IdLast Transaction IdLast Type + Timestamp + + StatusStartedFinalized
open_tx_detail(tx.contract_id)} style={{cursor: "pointer"}}>{tx.contract_id.slice(-8)}{tx.contract_location}{tx.requester.slice(-8)}{tx.target.slice(-8)}{tx.transaction_id.slice(-8)}{tx.change_type}{rust_timestamp_to_utc_string(tx.timestamp)}{tx.status}{tx.started}{tx.finalized}
+ + ) +}; @@ -46,15 +119,18 @@ export function ContractsContainer() { const [tx_list, set_tx_list] = useState>([]); const open_tx_detail = (contract_id: string) => { + console.log("Opening contract detail for contract id: ", contract_id); + let contract_history = all_contracts.get(contract_id); if (!contract_history) { console.error("Transaction not found"); return; } + console.log("Contract history: ", contract_history); + set_transaction(contract_history[0]); set_transaction_history(contract_history); - // set_peers_history(mock_peers_in_tx[tx.id]); set_is_detail_open(true); window.scrollTo(0, 0); }; @@ -70,11 +146,10 @@ export function ContractsContainer() { updated_tx_list = updated_tx_list.map((tx) => tx[tx.length - 1]); - console.log(updated_tx_list); set_tx_list(updated_tx_list); } - document.addEventListener("keydown", (e: any) => { + document.addEventListener("keydown", (e: KeyboardEvent) => { if (e.key === "Escape") { close_detail(); } diff --git a/network-monitor/src/generated/topology.ts b/network-monitor/src/generated/topology.ts index 296d86e1c..a72d72306 100644 --- a/network-monitor/src/generated/topology.ts +++ b/network-monitor/src/generated/topology.ts @@ -1,6 +1,8 @@ // automatically generated by the FlatBuffers compiler, do not modify export { AddedConnection, AddedConnectionT } from "./topology/added-connection"; +export { BroadcastEmitted } from "./topology/broadcast-emitted"; +export { BroadcastReceived } from "./topology/broadcast-received"; export { ContractChange } from "./topology/contract-change"; export { ContractChangeType } from "./topology/contract-change-type"; export { ControllerResponse } from "./topology/controller-response"; diff --git a/network-monitor/src/generated/topology/broadcast-emitted.ts b/network-monitor/src/generated/topology/broadcast-emitted.ts new file mode 100644 index 000000000..c915be061 --- /dev/null +++ b/network-monitor/src/generated/topology/broadcast-emitted.ts @@ -0,0 +1,147 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class BroadcastEmitted { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):BroadcastEmitted { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsBroadcastEmitted(bb:flatbuffers.ByteBuffer, obj?:BroadcastEmitted):BroadcastEmitted { + return (obj || new BroadcastEmitted()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsBroadcastEmitted(bb:flatbuffers.ByteBuffer, obj?:BroadcastEmitted):BroadcastEmitted { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new BroadcastEmitted()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +transaction():string|null +transaction(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +transaction(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +upstream():string|null +upstream(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +upstream(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +broadcastTo(index: number):string +broadcastTo(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array +broadcastTo(index: number,optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null; +} + +broadcastToLength():number { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +broadcastedTo():number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; +} + +key():string|null +key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +key(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +sender():string|null +sender(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +sender(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +timestamp():bigint { + const offset = this.bb!.__offset(this.bb_pos, 16); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); +} + +contractLocation():number { + const offset = this.bb!.__offset(this.bb_pos, 18); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; +} + +static startBroadcastEmitted(builder:flatbuffers.Builder) { + builder.startObject(8); +} + +static addTransaction(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, transactionOffset, 0); +} + +static addUpstream(builder:flatbuffers.Builder, upstreamOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, upstreamOffset, 0); +} + +static addBroadcastTo(builder:flatbuffers.Builder, broadcastToOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, broadcastToOffset, 0); +} + +static createBroadcastToVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startBroadcastToVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static addBroadcastedTo(builder:flatbuffers.Builder, broadcastedTo:number) { + builder.addFieldInt32(3, broadcastedTo, 0); +} + +static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { + builder.addFieldOffset(4, keyOffset, 0); +} + +static addSender(builder:flatbuffers.Builder, senderOffset:flatbuffers.Offset) { + builder.addFieldOffset(5, senderOffset, 0); +} + +static addTimestamp(builder:flatbuffers.Builder, timestamp:bigint) { + builder.addFieldInt64(6, timestamp, BigInt('0')); +} + +static addContractLocation(builder:flatbuffers.Builder, contractLocation:number) { + builder.addFieldFloat64(7, contractLocation, 0.0); +} + +static endBroadcastEmitted(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + builder.requiredField(offset, 4) // transaction + builder.requiredField(offset, 6) // upstream + builder.requiredField(offset, 12) // key + builder.requiredField(offset, 14) // sender + return offset; +} + +static createBroadcastEmitted(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, upstreamOffset:flatbuffers.Offset, broadcastToOffset:flatbuffers.Offset, broadcastedTo:number, keyOffset:flatbuffers.Offset, senderOffset:flatbuffers.Offset, timestamp:bigint, contractLocation:number):flatbuffers.Offset { + BroadcastEmitted.startBroadcastEmitted(builder); + BroadcastEmitted.addTransaction(builder, transactionOffset); + BroadcastEmitted.addUpstream(builder, upstreamOffset); + BroadcastEmitted.addBroadcastTo(builder, broadcastToOffset); + BroadcastEmitted.addBroadcastedTo(builder, broadcastedTo); + BroadcastEmitted.addKey(builder, keyOffset); + BroadcastEmitted.addSender(builder, senderOffset); + BroadcastEmitted.addTimestamp(builder, timestamp); + BroadcastEmitted.addContractLocation(builder, contractLocation); + return BroadcastEmitted.endBroadcastEmitted(builder); +} +} diff --git a/network-monitor/src/generated/topology/broadcast-received.ts b/network-monitor/src/generated/topology/broadcast-received.ts new file mode 100644 index 000000000..865c42fb1 --- /dev/null +++ b/network-monitor/src/generated/topology/broadcast-received.ts @@ -0,0 +1,108 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class BroadcastReceived { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):BroadcastReceived { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsBroadcastReceived(bb:flatbuffers.ByteBuffer, obj?:BroadcastReceived):BroadcastReceived { + return (obj || new BroadcastReceived()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsBroadcastReceived(bb:flatbuffers.ByteBuffer, obj?:BroadcastReceived):BroadcastReceived { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new BroadcastReceived()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +transaction():string|null +transaction(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +transaction(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +target():string|null +target(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +target(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +requester():string|null +requester(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +requester(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +key():string|null +key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +key(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +timestamp():bigint { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); +} + +contractLocation():number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; +} + +static startBroadcastReceived(builder:flatbuffers.Builder) { + builder.startObject(6); +} + +static addTransaction(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, transactionOffset, 0); +} + +static addTarget(builder:flatbuffers.Builder, targetOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, targetOffset, 0); +} + +static addRequester(builder:flatbuffers.Builder, requesterOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, requesterOffset, 0); +} + +static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { + builder.addFieldOffset(3, keyOffset, 0); +} + +static addTimestamp(builder:flatbuffers.Builder, timestamp:bigint) { + builder.addFieldInt64(4, timestamp, BigInt('0')); +} + +static addContractLocation(builder:flatbuffers.Builder, contractLocation:number) { + builder.addFieldFloat64(5, contractLocation, 0.0); +} + +static endBroadcastReceived(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + builder.requiredField(offset, 4) // transaction + builder.requiredField(offset, 6) // target + builder.requiredField(offset, 8) // requester + builder.requiredField(offset, 10) // key + return offset; +} + +static createBroadcastReceived(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset, timestamp:bigint, contractLocation:number):flatbuffers.Offset { + BroadcastReceived.startBroadcastReceived(builder); + BroadcastReceived.addTransaction(builder, transactionOffset); + BroadcastReceived.addTarget(builder, targetOffset); + BroadcastReceived.addRequester(builder, requesterOffset); + BroadcastReceived.addKey(builder, keyOffset); + BroadcastReceived.addTimestamp(builder, timestamp); + BroadcastReceived.addContractLocation(builder, contractLocation); + return BroadcastReceived.endBroadcastReceived(builder); +} +} diff --git a/network-monitor/src/generated/topology/contract-change-type.ts b/network-monitor/src/generated/topology/contract-change-type.ts index 56824cf87..5f314c265 100644 --- a/network-monitor/src/generated/topology/contract-change-type.ts +++ b/network-monitor/src/generated/topology/contract-change-type.ts @@ -1,5 +1,7 @@ // automatically generated by the FlatBuffers compiler, do not modify +import { BroadcastEmitted } from "../topology/broadcast-emitted"; +import { BroadcastReceived } from "../topology/broadcast-received"; import { PutFailure } from "../topology/put-failure"; import { PutRequest } from "../topology/put-request"; import { PutSuccess } from "../topology/put-success"; @@ -12,15 +14,19 @@ export enum ContractChangeType { PutRequest = 1, PutSuccess = 2, PutFailure = 3, - UpdateRequest = 4, - UpdateSuccess = 5, - UpdateFailure = 6, + BroadcastEmitted = 4, + BroadcastReceived = 5, + UpdateRequest = 6, + UpdateSuccess = 7, + UpdateFailure = 8, } export function unionToContractChangeType( type: ContractChangeType, accessor: ( obj: + | BroadcastEmitted + | BroadcastReceived | PutFailure | PutRequest | PutSuccess @@ -28,6 +34,8 @@ export function unionToContractChangeType( | UpdateRequest | UpdateSuccess ) => + | BroadcastEmitted + | BroadcastReceived | PutFailure | PutRequest | PutSuccess @@ -36,6 +44,8 @@ export function unionToContractChangeType( | UpdateSuccess | null ): + | BroadcastEmitted + | BroadcastReceived | PutFailure | PutRequest | PutSuccess @@ -52,6 +62,10 @@ export function unionToContractChangeType( return accessor(new PutSuccess())! as PutSuccess; case "PutFailure": return accessor(new PutFailure())! as PutFailure; + case "BroadcastEmitted": + return accessor(new BroadcastEmitted())! as BroadcastEmitted; + case "BroadcastReceived": + return accessor(new BroadcastReceived())! as BroadcastReceived; case "UpdateRequest": return accessor(new UpdateRequest())! as UpdateRequest; case "UpdateSuccess": @@ -68,6 +82,8 @@ export function unionListToContractChangeType( accessor: ( index: number, obj: + | BroadcastEmitted + | BroadcastReceived | PutFailure | PutRequest | PutSuccess @@ -75,6 +91,8 @@ export function unionListToContractChangeType( | UpdateRequest | UpdateSuccess ) => + | BroadcastEmitted + | BroadcastReceived | PutFailure | PutRequest | PutSuccess @@ -84,6 +102,8 @@ export function unionListToContractChangeType( | null, index: number ): + | BroadcastEmitted + | BroadcastReceived | PutFailure | PutRequest | PutSuccess @@ -100,6 +120,13 @@ export function unionListToContractChangeType( return accessor(index, new PutSuccess())! as PutSuccess; case "PutFailure": return accessor(index, new PutFailure())! as PutFailure; + case "BroadcastEmitted": + return accessor(index, new BroadcastEmitted())! as BroadcastEmitted; + case "BroadcastReceived": + return accessor( + index, + new BroadcastReceived() + )! as BroadcastReceived; case "UpdateRequest": return accessor(index, new UpdateRequest())! as UpdateRequest; case "UpdateSuccess": diff --git a/network-monitor/src/generated/topology/put-request.ts b/network-monitor/src/generated/topology/put-request.ts index ce2a1ae0b..e033180cb 100644 --- a/network-monitor/src/generated/topology/put-request.ts +++ b/network-monitor/src/generated/topology/put-request.ts @@ -48,8 +48,18 @@ target(optionalEncoding?:any):string|Uint8Array|null { return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; } +timestamp():bigint { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); +} + +contractLocation():number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; +} + static startPutRequest(builder:flatbuffers.Builder) { - builder.startObject(4); + builder.startObject(6); } static addTransaction(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset) { @@ -68,6 +78,14 @@ static addTarget(builder:flatbuffers.Builder, targetOffset:flatbuffers.Offset) { builder.addFieldOffset(3, targetOffset, 0); } +static addTimestamp(builder:flatbuffers.Builder, timestamp:bigint) { + builder.addFieldInt64(4, timestamp, BigInt('0')); +} + +static addContractLocation(builder:flatbuffers.Builder, contractLocation:number) { + builder.addFieldFloat64(5, contractLocation, 0.0); +} + static endPutRequest(builder:flatbuffers.Builder):flatbuffers.Offset { const offset = builder.endObject(); builder.requiredField(offset, 4) // transaction @@ -77,12 +95,14 @@ static endPutRequest(builder:flatbuffers.Builder):flatbuffers.Offset { return offset; } -static createPutRequest(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset):flatbuffers.Offset { +static createPutRequest(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset, timestamp:bigint, contractLocation:number):flatbuffers.Offset { PutRequest.startPutRequest(builder); PutRequest.addTransaction(builder, transactionOffset); PutRequest.addKey(builder, keyOffset); PutRequest.addRequester(builder, requesterOffset); PutRequest.addTarget(builder, targetOffset); + PutRequest.addTimestamp(builder, timestamp); + PutRequest.addContractLocation(builder, contractLocation); return PutRequest.endPutRequest(builder); } } diff --git a/network-monitor/src/generated/topology/put-success.ts b/network-monitor/src/generated/topology/put-success.ts index ca1e950e2..14acda9f7 100644 --- a/network-monitor/src/generated/topology/put-success.ts +++ b/network-monitor/src/generated/topology/put-success.ts @@ -48,8 +48,18 @@ key(optionalEncoding?:any):string|Uint8Array|null { return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; } +timestamp():bigint { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); +} + +contractLocation():number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; +} + static startPutSuccess(builder:flatbuffers.Builder) { - builder.startObject(4); + builder.startObject(6); } static addTransaction(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset) { @@ -68,6 +78,14 @@ static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { builder.addFieldOffset(3, keyOffset, 0); } +static addTimestamp(builder:flatbuffers.Builder, timestamp:bigint) { + builder.addFieldInt64(4, timestamp, BigInt('0')); +} + +static addContractLocation(builder:flatbuffers.Builder, contractLocation:number) { + builder.addFieldFloat64(5, contractLocation, 0.0); +} + static endPutSuccess(builder:flatbuffers.Builder):flatbuffers.Offset { const offset = builder.endObject(); builder.requiredField(offset, 4) // transaction @@ -77,12 +95,14 @@ static endPutSuccess(builder:flatbuffers.Builder):flatbuffers.Offset { return offset; } -static createPutSuccess(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset):flatbuffers.Offset { +static createPutSuccess(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset, timestamp:bigint, contractLocation:number):flatbuffers.Offset { PutSuccess.startPutSuccess(builder); PutSuccess.addTransaction(builder, transactionOffset); PutSuccess.addRequester(builder, requesterOffset); PutSuccess.addTarget(builder, targetOffset); PutSuccess.addKey(builder, keyOffset); + PutSuccess.addTimestamp(builder, timestamp); + PutSuccess.addContractLocation(builder, contractLocation); return PutSuccess.endPutSuccess(builder); } } diff --git a/network-monitor/src/home-page-ring.tsx b/network-monitor/src/home-page-ring.tsx new file mode 100644 index 000000000..670df95dd --- /dev/null +++ b/network-monitor/src/home-page-ring.tsx @@ -0,0 +1,88 @@ +import React, {useEffect} from "react"; +import {RingVisualization} from "./ring-visualization"; +import {ring_mock_data} from "./mock_data"; +import {all_contracts} from "./transactions-data"; +import {ChangeType, RingVisualizationPoint} from "./type_definitions"; + + +export const HomePageRing = () => { + let [peers, setPeers] = React.useState(true); + let [contracts, setContracts] = React.useState(false); + + let [contractsData, setContractsData] = React.useState([]); + + let togglePeers = () => { + setPeers(!peers); + } + + let toggleContracts = () => { + setContracts(!contracts); + } + + useEffect(() => { + console.log("Peers visibility changed"); + console.log(peers); + }, [peers]); + + useEffect(() => { + console.log("Contracts visibility changed"); + console.log(contracts); + + updateContracts(); + + }, [contracts]); + + + const updateContracts = () => { + let all_contracts_locations = new Array(); + + + for (let key of all_contracts.keys()) { + let one_contract = all_contracts.get(key)!; + let put_success = one_contract.find(e => e.change_type == ChangeType.PUT_SUCCESS); + if (put_success) { + all_contracts_locations.push({ + localization: put_success.requester_location as number, + peerId: put_success.requester as string, + } as RingVisualizationPoint); + } + } + + console.log("all_contracts_locations", all_contracts_locations); + + let key_index = all_contracts.keys().next().value; + let one_contract = all_contracts.get(key_index); + + console.log("key_index", key_index); + console.log("one_contract", one_contract); + + setContractsData(all_contracts_locations); + + } + + + return ( +
+ + + + + +
+ ); +} + + + + +interface IButtonElements { + togglePeers: () => void; + toggleContracts: () => void; +} + +const ButtonsElements = ({togglePeers, toggleContracts}: IButtonElements) => ( +
+ + +
+); diff --git a/network-monitor/src/mock_data.ts b/network-monitor/src/mock_data.ts new file mode 100644 index 000000000..6319ff84f --- /dev/null +++ b/network-monitor/src/mock_data.ts @@ -0,0 +1,249 @@ +import { PeerId, RingVisualizationPoint } from "./type_definitions"; +import { + ChangeType, + MessageType, + OpState, + TransactionInterface, + TransactionStatus, + TxPeersTableInterface, +} from "./type_definitions"; + +export const ring_mock_data: RingVisualizationPoint[] = [ + { + peerId: "ideal", + localization: 0.123485, + }, + { + peerId: "6f3360a9-ca27-4930-9fe7-578eedb5c9e7", + localization: 0.802323, + }, + { + peerId: "38a93663-25e5-45ec-a708-7129d5eaf993", + localization: 0.313894, + }, + { + peerId: "5210d7a5-5cec-4021-b4c9-dab6cbddd4f1", + localization: 0.493189, + }, + { + peerId: "bf81df38-a14a-47ee-9673-aec6f49996a4", + localization: 0.733043, + }, + { + peerId: "f79bbd6e-12f4-458f-9cab-8f61849943a3", + localization: 0.900193, + }, + { + peerId: "aa97ae3d-858e-4f48-86ea-ae6dfbe13523", + localization: 0.779211, + }, +]; + +const mock_transaction: Array = [ + { + id: "123", + peer_id: "0xabc", + type: ChangeType.PUT_SUCCESS, + status: TransactionStatus.Finalized, + started: "12-01-2024", + finalized: "13-01-2024", + contract_id: "0x123", + }, + { + id: "124", + peer_id: "0xdef", + type: ChangeType.PUT_SUCCESS, + status: TransactionStatus.Received, + started: "12-01-2024", + finalized: "13-01-2024", + contract_id: "0x4892", + }, + { + id: "125", + peer_id: "0xabc", + type: ChangeType.PUT_REQUEST, + status: TransactionStatus.Ongoing, + started: "12-02-2024", + finalized: "13-02-2024", + contract_id: "0x783", + }, +]; + +const mock_peers_in_tx: TxPeersTableInterface = { + "123": [ + // create a mock object + { + peer_id: "0xabc", + location: "0.1789234", + last_state: OpState.BroadcastOngoing, + last_message: MessageType.Broadcasting, + started: "12-01-2024", + finalized: "13-01-2024", + }, + { + peer_id: "0xdef", + location: "0.16234", + last_state: OpState.Finished, + last_message: MessageType.SuccessfulUpdate, + started: "18-01-2024", + finalized: "19-01-2024", + }, + { + peer_id: "0xghi", + location: "0.234234", + last_state: OpState.AwaitingResponse, + last_message: MessageType.RequestUpdate, + started: "19-01-2024", + finalized: "20-01-2024", + }, + { + peer_id: "0xjkl", + location: "0.267127", + last_state: OpState.AwaitingResponse, + last_message: MessageType.RequestUpdate, + started: "21-01-2024", + finalized: "22-01-2024", + }, + { + peer_id: "0xdef", + location: "0.1789234", + last_state: OpState.BroadcastOngoing, + last_message: MessageType.Broadcasting, + started: "12-01-2024", + finalized: "13-01-2024", + }, + { + peer_id: "0xabc", + location: "0.16234", + last_state: OpState.Finished, + last_message: MessageType.SuccessfulUpdate, + started: "18-01-2024", + finalized: "19-01-2024", + }, + { + peer_id: "0xjkl", + location: "0.234234", + last_state: OpState.AwaitingResponse, + last_message: MessageType.RequestUpdate, + started: "19-01-2024", + finalized: "20-01-2024", + }, + { + peer_id: "0xghi", + location: "0.267127", + last_state: OpState.AwaitingResponse, + last_message: MessageType.RequestUpdate, + started: "21-01-2024", + finalized: "22-01-2024", + }, + ], + "124": [ + { + peer_id: "0xdef", + location: "0.1789234", + last_state: OpState.BroadcastOngoing, + last_message: MessageType.Broadcasting, + started: "12-01-2024", + finalized: "13-01-2024", + }, + { + peer_id: "0xabc", + location: "0.16234", + last_state: OpState.Finished, + last_message: MessageType.SuccessfulUpdate, + started: "18-01-2024", + finalized: "19-01-2024", + }, + { + peer_id: "0xghi", + location: "0.234234", + last_state: OpState.ReceivedRequest, + last_message: MessageType.BroadcastTo, + started: "19-01-2024", + finalized: "20-01-2024", + }, + { + peer_id: "0xjkl", + location: "0.267127", + last_state: OpState.AwaitingResponse, + last_message: MessageType.RequestUpdate, + started: "21-01-2024", + finalized: "22-01-2024", + }, + { + peer_id: "0xdef", + location: "0.1789234", + last_state: OpState.Finished, + last_message: MessageType.SuccessfulUpdate, + started: "12-01-2024", + finalized: "13-01-2024", + }, + { + peer_id: "0xabc", + location: "0.16234", + last_state: OpState.Finished, + last_message: MessageType.SuccessfulUpdate, + started: "18-01-2024", + finalized: "19-01-2024", + }, + { + peer_id: "0xjkl", + location: "0.234234", + last_state: OpState.AwaitingResponse, + last_message: MessageType.RequestUpdate, + started: "19-01-2024", + finalized: "20-01-2024", + }, + { + peer_id: "0xghi", + location: "0.267127", + last_state: OpState.BroadcastOngoing, + last_message: MessageType.Broadcasting, + started: "21-01-2024", + finalized: "22-01-2024", + }, + ], +}; + +let another_ring_mock_data = [ + { + id: new PeerId("1"), + currentLocation: 0.123485, + connectionTimestamp: 1234567890, + connections: [], + history: [], + locationHistory: [], + }, + { + id: new PeerId("2"), + currentLocation: 0.183485, + connectionTimestamp: 1234567890, + connections: [], + history: [], + locationHistory: [], + }, + { + id: new PeerId("3"), + currentLocation: 0.323485, + connectionTimestamp: 1234567890, + connections: [], + history: [], + locationHistory: [], + }, + { + id: new PeerId("4"), + currentLocation: 0.423485, + connectionTimestamp: 1234567890, + connections: [], + history: [], + locationHistory: [], + }, + { + id: new PeerId("5"), + currentLocation: 0.783285, + connectionTimestamp: 1234567890, + connections: [], + history: [], + locationHistory: [], + }, +]; diff --git a/network-monitor/src/pagination.tsx b/network-monitor/src/pagination.tsx new file mode 100644 index 000000000..b09723d8d --- /dev/null +++ b/network-monitor/src/pagination.tsx @@ -0,0 +1,65 @@ +interface PaginationInterface { + currentPage: number; + totalPages: number; + onPageChange: (page: number) => void; +} + +export const Pagination = ({ currentPage, totalPages, onPageChange }: PaginationInterface) => { + + const render_all_pages = () => { + let return_values = []; + + let start = currentPage - 2; + + if (start < 1) { + start = 1; + } + + let end = start + 4; + + if (end > totalPages) { + end = totalPages; + } + + if (start > 1) { + return_values.push( +
  • + +
  • + ); + } + + + for (let i = start; i <= end; i++) { + return_values.push( +
  • + +
  • + ); + } + + if (end < totalPages) { + + return_values.push( +
  • + +
  • + ); + } + + return return_values; + } + + return ( + + ); + +} diff --git a/network-monitor/src/react-init.tsx b/network-monitor/src/react-init.tsx index 0b7299aec..f0ac766f5 100644 --- a/network-monitor/src/react-init.tsx +++ b/network-monitor/src/react-init.tsx @@ -1,15 +1,50 @@ import { ContractsTable } from "./contracts"; import { TransactionContainer } from "./transactions"; import { ContractsContainer } from "./contracts"; -import {another_ring_visualization} from "./ring-visualization"; +import {RingVisualization} from "./ring-visualization"; +import {useEffect} from "react"; +import {createRoot} from "react-dom/client"; +import React from "react"; +import {ring_mock_data} from "./mock_data"; +import {HomePageRing} from "./home-page-ring"; + +declare global { + interface Window { + mermaid: any; + } +} + +const ReactContainer = () => { + const ring_react_element = ; + + useEffect(() => { + // we need to wait here for the histogram to be initiated first. If we move all to React code we can remove this. + setTimeout(() => { + // Append the SVG element. + const peers_container = document.getElementById("peers-histogram")!; + + const ring_container = document.createElement("div"); + + const root = createRoot(ring_container); + root.render(ring_react_element); + + peers_container.appendChild(ring_container); + + + console.log("React container mounted"); + + }, 4000); + + window.mermaid.contentLoaded(); + }, []); + -function ReactContainer() { return (
    - {another_ring_visualization({peerId: "abc", localization: 0.1}, [{peerId: "0x593b", localization: 0.3}, {peerId: "0x593b", localization: 0.5}, {peerId: "0x593b", localization: 0.7}, {peerId: "0x593b", localization: 0.9}])} - - + + +
    @@ -18,18 +53,3 @@ function ReactContainer() { export const component = ; - - // const localizations = [0.0001, 0.5498, 0.865, 0.988]; - - // const points = localizations.map((x) => { - // return { - // x: Math.cos(2 * Math.PI * x), - // y: Math.sin(2 * Math.PI * x), - // }; - // } -// -// -// - // - // - // diff --git a/network-monitor/src/ring-visualization.tsx b/network-monitor/src/ring-visualization.tsx index bcccec040..eec069972 100644 --- a/network-monitor/src/ring-visualization.tsx +++ b/network-monitor/src/ring-visualization.tsx @@ -1,14 +1,17 @@ import { local } from "d3"; +import React, {useEffect} from "react"; +import {createRoot} from "react-dom/client"; +import {RingVisualizationPoint, RingVisualizationProps} from "./type_definitions"; -interface RingVisualizationPoint { - peerId: string; - localization: number; -} -export const another_ring_visualization = ( - main_peer: RingVisualizationPoint, - other_peers: RingVisualizationPoint[] -) => { +export const RingVisualization = ({main_peer, other_peers, selected_text = "Peer"}: RingVisualizationProps) => { + const [selected_peer, setSelectedPeer] = React.useState(main_peer); + + useEffect(() => { + console.log("Selected peer changed"); + setSelectedPeer(main_peer); + }, [main_peer]); + // Declare the chart dimensions and margins. const width = 640; const height = 400; @@ -44,16 +47,211 @@ export const another_ring_visualization = ( // let scale = 3; - console.log(calculate_point(other_peers[0].localization, scale)); - console.log(calculate_point(other_peers[1].localization, scale)); - let tooltip_x = 100; let tooltip_y = 100; let tooltips_visibility = {}; - let a = ( - + const draw_points = (internal_other_peers: RingVisualizationPoint[]) => { + return internal_other_peers.map((peer, index) => { + let return_values = ( + <> + { + document.querySelector(`.svg-tooltip-${peer.peerId}`)!.removeAttribute("style"); + document.querySelector(`.svg-tooltip-${peer.peerId}`)!.setAttribute("style", "display: block;"); + }} + onMouseLeave={() => { + document.querySelector(`.svg-tooltip-${peer.peerId}`)!.removeAttribute("style"); + document.querySelector(`.svg-tooltip-${peer.peerId}`)!.setAttribute("style", "display: none;"); + }} + style={{zIndex: 999}} + onClick={() => { + setSelectedPeer(peer); + }} + + /> + + + 0.35 ? -130 : 0) + (peer.localization > 0.9 || peer.localization < 0.15 ? 10 : 0) + }`} + y={`${ + calculate_point(peer.localization, scale).y + (peer.localization > 0.7 && peer.localization < 0.9 ? -10 : 0) + (peer.localization > 0.15 && peer.localization < 0.35 ? 30 : 0) + }`} + className={`svg-tooltip-${peer.peerId}`} + style={{backgroundColor: "white", padding: 5, zIndex: 999, display: "none"}} + fontWeight={100} + fontSize={13} + > + {peer.peerId.slice(-8)} + @ {peer.localization.toString().slice(0, 8)} + + + + + + ); + + document.styleSheets[2].addRule( + `.svg-tooltip-${peer.localization + .toString() + .replace(".", "")}`, + "display: none" + ); + return return_values; + }) + } + + const draw_connecting_lines_from_main_peer_to_other_peers = (internal_other_peers: RingVisualizationPoint[]) => { + if (!main_peer) { + return <>; + } + + return internal_other_peers.map((peer, index) => { + let return_values = ( + <> + { + // document.querySelector(selectors) + + document.querySelector(`.svg-tooltip-distance-${peer.peerId}`)!.removeAttribute("style"); + document.querySelector(`.svg-tooltip-distance-${peer.peerId}`)!.setAttribute("style", "display: block;"); + + // document.styleSheets[2].addRule( + // `.svg-tooltip-distance-${peer.localization + // .toString() + // .replace(".", "")}`, + // "display: block" + // ); + }} + onMouseLeave={() => { + // document.querySelector(selectors) + + document.querySelector(`.svg-tooltip-distance-${peer.peerId}`)!.removeAttribute("style"); + document.querySelector(`.svg-tooltip-distance-${peer.peerId}`)!.setAttribute("style", "display: none;"); + + // document.styleSheets[2].addRule( + // `.svg-tooltip-distance-${peer.localization + // .toString() + // .replace(".", "")}`, + // "display: none" + // ); + + }} + /> + + + distance: {Math.abs(peer.localization - main_peer.localization)} + + + + + ); + + + return return_values; + }) + } + + const draw_main_peer_text = (main_peer: RingVisualizationPoint | undefined, scale: number) => { + if (!main_peer) { + return <>; + } + return ( + 0.64 && main_peer.localization < 0.9 ? -20 : 0) + (main_peer.localization > 0.15 && main_peer.localization < 0.35 ? 30 : 0)}`} + className={`svg-tooltip-${main_peer.localization + .toString() + .replace(".", "")}`} + fontWeight={100} + onClick={() => { + setSelectedPeer(main_peer); + }} + style={{zIndex: 999}} + + > + {main_peer.peerId} + @ {main_peer.localization.toString().slice(0, 8)} + + + ); + }; + + const draw_main_peer = (main_peer: RingVisualizationPoint | undefined, scale: number) => { + if (!main_peer) { + return <>; + } + + return ( + + ); + } + + const draw_selected_peer_text = (selected_peer: RingVisualizationPoint | undefined) => { + if (!selected_peer) { + return <>; + } + return ( + + Selected {selected_text}: + {" "}{selected_peer.peerId.slice(-8)} + @ {selected_peer.localization.toString().slice(0, 8)} + + ); + } + + return ( +
    + - + {draw_main_peer(main_peer, scale)} - {other_peers.map((peer, index) => { - let return_values = ( - <> - { - document.styleSheets[2].addRule( - `.svg-tooltip-${peer.localization - .toString() - .replace(".", "")}`, - "display: block" - ); - }} - onMouseLeave={() => { - document.styleSheets[2].addRule( - `.svg-tooltip-${peer.localization - .toString() - .replace(".", "")}`, - "display: none" - ); - }} - /> - - - {peer.peerId}: {peer.localization} - - - ); - - document.styleSheets[2].addRule( - `.svg-tooltip-${peer.localization - .toString() - .replace(".", "")}`, - "display: none" - ); - return return_values; - })} - - {other_peers.map((peer, index) => { - let return_values = ( - <> - { - document.styleSheets[2].addRule( - `.svg-tooltip-distance-${peer.localization - .toString() - .replace(".", "")}`, - "display: block" - ); - }} - onMouseLeave={() => { - document.styleSheets[2].addRule( - `.svg-tooltip-distance-${peer.localization - .toString() - .replace(".", "")}`, - "display: none" - ); - }} - /> - - - distance: {Math.abs(peer.localization - main_peer.localization)} - - - - ); - - - document.styleSheets[2].addRule( - `.svg-tooltip-distance-${peer.localization - .toString() - .replace(".", "")}`, - "display: none" - ); - - return return_values; - })} + {draw_connecting_lines_from_main_peer_to_other_peers(other_peers)} + + {draw_points(other_peers)} + + {draw_main_peer_text(main_peer, scale)} + + {draw_selected_peer_text(selected_peer)} + + + +
    ); - // Append the SVG element. - return a; + }; const calculate_point = (localization: number, scale: number) => { diff --git a/network-monitor/src/topology.ts b/network-monitor/src/topology.ts index 806d03448..0edc81a32 100644 --- a/network-monitor/src/topology.ts +++ b/network-monitor/src/topology.ts @@ -3,59 +3,22 @@ import * as d3 from "d3"; import { BaseType } from "d3-selection"; import { createRoot } from "react-dom/client"; import { component } from "./react-init"; +import { + ChangeInfo, + Connection, + Peer, + PeerId, + PeerList, +} from "./type_definitions"; export let peers: PeerList = {}; -interface PeerList { - [id: string]: Peer; -} - -interface Peer { - id: PeerId; - currentLocation: number; - connectionTimestamp: number; - connections: Connection[]; - history: ChangeInfo[]; - locationHistory: { location: number; timestamp: number }[]; -} - -interface Connection { - transaction: string | null; - id: PeerId; - location: number; -} - -interface ChangeInfo { - type: "Added" | "Removed"; - from: Connection; - to: Connection; - timestamp: number; -} - -export class PeerId { - private id: string; - - constructor(id: string | Uint8Array) { - if (id instanceof Uint8Array) { - this.id = new TextDecoder().decode(id); - } else { - this.id = id; - } - } - - get short() { - return this.id.slice(-8); - } - - get full() { - return this.id; - } -} - export function handleChange(peerChange: fbTopology.PeerChange) { const previousPeers = Object.keys(peers).length; + try { const unpacked = peerChange.unpack(); + switch (unpacked.changeType) { case fbTopology.PeerChangeType.AddedConnection: handleAddedConnection( @@ -100,6 +63,7 @@ export function handleAddedConnection( return; } const added = peerChange; + const from = new PeerId(added.from!); const to = new PeerId(added.to!); diff --git a/network-monitor/src/transaction-detail.tsx b/network-monitor/src/transaction-detail.tsx index 5f2350911..4ebc14995 100644 --- a/network-monitor/src/transaction-detail.tsx +++ b/network-monitor/src/transaction-detail.tsx @@ -1,31 +1,29 @@ import { useEffect, useState } from "react"; -import { createRoot } from "react-dom/client"; import { TransactionDetailInterface, - TransactionPeerInterface, - TransactionData + TransactionData, + TransactionDetailPeersHistoryInterface, + FilterDictionaryInterface, + TranscationHistoryInterface, + ChangeType, } from "./type_definitions"; -import { PeerId } from "./topology"; +import {get_peers_description_to_render, refresh_peers_tree, rust_timestamp_to_utc_string} from "./utils"; -interface TransactionDetailPeersHistoryInterface { - tx_peer_list: Array; +declare global { + interface Window { + drawNomNomlCanvas: (text_to_render: string) => void; + } } -interface FilterInterface { - filter_type: string; - filter_value: string; -} - -interface FilterDictionaryInterface { - [key: string]: FilterInterface; -} - -let ring_mock_data = []; const TransactionPeersHistory = ({ tx_peer_list, }: TransactionDetailPeersHistoryInterface) => { const [filter, set_filter] = useState({}); const [filtered_list, set_filtered_list] = useState(tx_peer_list); + const [order_by, set_order_by] = useState("timestamp"); + const [order_direction, set_order_direction] = useState("asc"); + const [loading, set_loading] = useState(false); + const [mermaid_text, set_mermaid_text] = useState(""); const add_filter = (filter_type: string, filter_value: string) => { if (check_if_contains_filter(filter_type)) { @@ -56,6 +54,20 @@ const TransactionPeersHistory = ({ }); }); + + filtered_list = filtered_list.sort((a, b) => { + if (order_by === "timestamp") { + if (order_direction === "asc") { + return a.timestamp > b.timestamp ? 1 : -1; + } else { + return a.timestamp < b.timestamp ? 1 : -1; + } + } else { + return 0; + } + }); + + set_filtered_list(filtered_list); }; @@ -69,59 +81,38 @@ const TransactionPeersHistory = ({ }; useEffect(() => { + update_filtered_list(); - let ring_mock_data = [ - { - id: new PeerId("1"), - currentLocation: 0.123485, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - { - id: new PeerId("2"), - currentLocation: 0.183485, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - { - id: new PeerId("3"), - currentLocation: 0.323485, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - { - id: new PeerId("4"), - currentLocation: 0.423485, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - { - id: new PeerId("5"), - currentLocation: 0.783285, - connectionTimestamp: 1234567890, - connections: [], - history: [], - locationHistory: [], - }, - ]; - - // ringHistogram(ring_mock_data); - - // const graphContainer = d3.select( - // document.getElementById("other-peer-conns-graph") - // ); - - // ringVisualization(ring_mock_data[0], graphContainer, 1.25); - }, [filter]); + if (loading) { + setTimeout(() => { + set_loading(false); + }, 1000); + } + + }, [filter, order_by, order_direction]); + + useEffect(() => { + let transaction_description_to_render = get_peers_description_to_render(tx_peer_list); + + console.log("Transaction description to render=", transaction_description_to_render); + set_mermaid_text(transaction_description_to_render); + + setTimeout(() => { + }, 1000); + + clear_all_filters(); + }, [tx_peer_list]); + + + useEffect(() => { + if (mermaid_text === "") { + return; + } + + refresh_peers_tree(mermaid_text); + }, [mermaid_text]); + const check_if_contains_filter = (filter_type: string) => { return filter[filter_type] !== undefined; @@ -133,10 +124,16 @@ const TransactionPeersHistory = ({ className="block" style={{ marginTop: 20 }} > + +
    +
    +                    {mermaid_text}
    +                
    +

    Transaction Peers History

    {Object.keys(filter).length > 0 && (
    -
    @@ -150,7 +147,7 @@ const TransactionPeersHistory = ({ Transaction Id {check_if_contains_filter("transaction_id") && ( - )} + + Contract Location + + + Timestamp + + + {filtered_list.map((tx) => ( - + add_filter("transaction_id", tx.transaction_id) @@ -214,7 +228,7 @@ const TransactionPeersHistory = ({ cursor: "pointer", }} > - {tx.transaction_id} + {tx.transaction_id.slice(-8)} @@ -234,7 +248,14 @@ const TransactionPeersHistory = ({ cursor: "pointer", }} > - {tx.target.slice(-8)} + {tx.change_type == ChangeType.BROADCAST_EMITTED ? + tx.target.map((t:string, index: number) => { + + let t_location = t.split(" (@")[1].split(")")[0].slice(0, 8); + t = t.split(" (@")[0].slice(-8); + + return

    {t} @ {t_location}

    + }) : tx.target.slice(-8)} @@ -256,6 +277,13 @@ const TransactionPeersHistory = ({ > {tx.contract_id.slice(-8)} + + {tx.contract_location} + + + {rust_timestamp_to_utc_string(tx.timestamp)} + + ))} @@ -264,8 +292,9 @@ const TransactionPeersHistory = ({ ); }; + // TODO: use real types -const TransactionHistory = ({ tx_history }: any) => ( +const TransactionHistory = ({ tx_history }: TranscationHistoryInterface) => (

    Transaction History

    Requester {transaction.requester}

    Target {transaction.target}

    Contract Key {transaction.contract_id}

    +

    Contract Location {transaction.contract_location}

    @@ -374,60 +404,5 @@ const TransactionDetail = ({
    ); -const another_ring_visualization = () => { - // Declare the chart dimensions and margins. - const width = 640; - const height = 400; - const marginTop = 20; - const marginRight = 20; - const marginBottom = 30; - const marginLeft = 40; - - // // Declare the x (horizontal position) scale. - // const x = d3 - // .scaleUtc() - // .domain([new Date("2023-01-01"), new Date("2024-01-01")]) - // .range([marginLeft, width - marginRight]); - - // // Declare the y (vertical position) scale. - // const y = d3 - // .scaleLinear() - // .domain([0, 100]) - // .range([height - marginBottom, marginTop]); - - // // Create the SVG container. - // const svg = d3.create("svg").attr("width", width).attr("height", height); - - // // Add the x-axis. - // svg.append("g") - // .attr("transform", `translate(0,${height - marginBottom})`) - // .call(d3.axisBottom(x)); - - // // Add the y-axis. - // svg.append("g") - // .attr("transform", `translate(${marginLeft},0)`) - // .call(d3.axisLeft(y)); - - let a = ( - - - - - - - - - - - ); - - // Append the SVG element. - return a; -}; export default TransactionDetail; diff --git a/network-monitor/src/transactions-data.ts b/network-monitor/src/transactions-data.ts index 407925352..fb6df386e 100644 --- a/network-monitor/src/transactions-data.ts +++ b/network-monitor/src/transactions-data.ts @@ -14,13 +14,15 @@ export function handlePutRequest( contract_id: string, target: string, requester: string, - change_type: ChangeType + change_type: ChangeType, + timestamp: number, + contract_location: number ) { - console.log("Put Request"); - console.log("tx", transaction_id); - console.log("contract key", contract_id); - console.log("target", target); - console.log("requester", requester); + let requester_location = parseFloat( + requester.split(" (@ ")[1].split(")")[0] + ); + + requester = requester.split(" (@")[0]; let obj_data = { change_type, @@ -28,11 +30,11 @@ export function handlePutRequest( contract_id, target, requester, - status: null, - started: null, - finalized: null, + requester_location, unique_id: transaction_id + contract_id + target + requester + change_type, + timestamp, + contract_location, } as TransactionData; if ( @@ -57,13 +59,15 @@ export function handlePutSuccess( contract_id: string, target: string, requester: string, - change_type: ChangeType + change_type: ChangeType, + timestamp: number, + contract_location: number ) { - console.log("Put Success"); - console.log("tx", transaction_id); - console.log("contract key", contract_id); - console.log("target", target); - console.log("requester", requester); + let requester_location = parseFloat( + requester.split(" (@ ")[1].split(")")[0] + ); + + requester = requester.split(" (@")[0]; let obj_data = { change_type, @@ -71,12 +75,15 @@ export function handlePutSuccess( contract_id, target, requester, - status: null, - started: null, - finalized: null, + requester_location, + status: undefined, + started: undefined, + finalized: undefined, unique_id: transaction_id + contract_id + target + requester + change_type, - }; + timestamp, + contract_location, + } as TransactionData; if ( all_tx @@ -94,3 +101,93 @@ export function handlePutSuccess( } all_contracts.get(contract_id)!.push(obj_data); } + +export function handleBroadcastEmitted( + transaction_id: string, + upstream: string, + broadcast_to: any[], + key: string, + sender: string, + timestamp: number, + contract_location: number +) { + let sender_location = parseFloat(sender.split(" (@")[1].split(")")[0]); + sender = sender.split(" (@")[0]; + + let upstream_location = upstream.split(" (@")[1].split(")")[0]; + upstream = upstream.split(" (@")[0]; + + let obj_data = { + change_type: ChangeType.BROADCAST_EMITTED, + transaction_id, + contract_id: key, + target: broadcast_to, + requester: sender, + requester_location: sender_location, + unique_id: transaction_id + key + broadcast_to[0] + sender, + timestamp, + contract_location, + upstream, + } as TransactionData; + + if ( + all_tx + .get(transaction_id) + ?.find((obj) => obj.unique_id === obj_data.unique_id) + ) { + return; + } + + all_tx.get(transaction_id)!.push(obj_data); + + const this_contract_data = all_contracts.get(key); + if (!this_contract_data) { + console.error("Contract not found when logging Broadcast Emitted"); + } + all_contracts.get(key)!.push(obj_data); +} + +export function handleBroadcastReceived( + transaction_id: string, + target: string, + requester: string, + key: string, + change_type: ChangeType, + timestamp: number, + contract_location: number +) { + let requester_location = parseFloat( + requester.split(" (@")[1].split(")")[0] + ); + + requester = requester.split(" (@")[0]; + + let obj_data = { + change_type, + transaction_id, + contract_id: key, + target, + requester, + requester_location, + unique_id: transaction_id + key + target + requester, + timestamp, + contract_location, + } as TransactionData; + + if ( + all_tx + .get(transaction_id) + ?.find((obj) => obj.unique_id === obj_data.unique_id) + ) { + return; + } + + all_tx.get(transaction_id)!.push(obj_data); + + const this_contract_data = all_contracts.get(key); + if (!this_contract_data) { + console.error("Contract not found when logging Broadcast Received"); + } + + all_contracts.get(key)!.push(obj_data); +} diff --git a/network-monitor/src/transactions.tsx b/network-monitor/src/transactions.tsx index 28dffcd80..d3ecbb0f5 100644 --- a/network-monitor/src/transactions.tsx +++ b/network-monitor/src/transactions.tsx @@ -1,214 +1,117 @@ import { useEffect, useState } from "react"; import { createRoot } from "react-dom/client"; import TransactionDetail from "./transaction-detail"; -import { all_tx} from "./transactions-data"; -import {TransactionInterface, TransactionStatus, TransactionType, TransactionData, TxPeersTableInterface, OpState, MessageType, TxTableInterface, TransactionPeerInterface, ChangeType } from "./type_definitions"; -import {another_ring_visualization} from "./ring-visualization"; +import { all_tx } from "./transactions-data"; +import { TransactionData, TxTableInterface, TransactionPeerInterface, ChangeType } from "./type_definitions"; +import { filter_by_page, get_all_pages, rust_timestamp_to_utc_string } from "./utils"; +import {Pagination} from "./pagination"; + +const TransactionsTable = ({ open_tx_detail, tx_list }: TxTableInterface) => { + const [ordered_tx_list, set_ordered_tx_list] = useState>([]); + const [inner_tx_list, set_inner_tx_list] = useState>([]); + const [order_by, set_order_by] = useState("timestamp"); + const [order_direction, set_order_direction] = useState("asc"); + const [loading, set_loading] = useState(true); + const [page, set_page] = useState(1); + + + const order_tx_list = (tx_list: Array) => { + let updated_tx_list = tx_list; + updated_tx_list = updated_tx_list.sort((a, b) => { + if (order_by === "timestamp") { + if (order_direction === "asc") { + return a.timestamp > b.timestamp ? 1 : -1; + } else { + return a.timestamp < b.timestamp ? 1 : -1; + } + } else { + return 0; + } + }); + return updated_tx_list; + } -const mock_transaction: Array = [ - { - id: "123", - peer_id: "0xabc", - type: ChangeType.PUT_SUCCESS, - status: TransactionStatus.Finalized, - started: "12-01-2024", - finalized: "13-01-2024", - contract_id: "0x123", - }, - { - id: "124", - peer_id: "0xdef", - type: ChangeType.PUT_SUCCESS, - status: TransactionStatus.Received, - started: "12-01-2024", - finalized: "13-01-2024", - contract_id: "0x4892", - }, - { - id: "125", - peer_id: "0xabc", - type: ChangeType.PUT_REQUEST, - status: TransactionStatus.Ongoing, - started: "12-02-2024", - finalized: "13-02-2024", - contract_id: "0x783", - }, -]; + useEffect(() => { + if (tx_list) { + let ordered_list = order_tx_list(tx_list); + set_ordered_tx_list(ordered_list); + set_inner_tx_list(order_tx_list(filter_by_page(ordered_list, page))); -const mock_peers_in_tx: TxPeersTableInterface = { - "123": [ - // create a mock object - { - peer_id: "0xabc", - location: "0.1789234", - last_state: OpState.BroadcastOngoing, - last_message: MessageType.Broadcasting, - started: "12-01-2024", - finalized: "13-01-2024", - }, - { - peer_id: "0xdef", - location: "0.16234", - last_state: OpState.Finished, - last_message: MessageType.SuccessfulUpdate, - started: "18-01-2024", - finalized: "19-01-2024", - }, - { - peer_id: "0xghi", - location: "0.234234", - last_state: OpState.AwaitingResponse, - last_message: MessageType.RequestUpdate, - started: "19-01-2024", - finalized: "20-01-2024", - }, - { - peer_id: "0xjkl", - location: "0.267127", - last_state: OpState.AwaitingResponse, - last_message: MessageType.RequestUpdate, - started: "21-01-2024", - finalized: "22-01-2024", - }, - { - peer_id: "0xdef", - location: "0.1789234", - last_state: OpState.BroadcastOngoing, - last_message: MessageType.Broadcasting, - started: "12-01-2024", - finalized: "13-01-2024", - }, - { - peer_id: "0xabc", - location: "0.16234", - last_state: OpState.Finished, - last_message: MessageType.SuccessfulUpdate, - started: "18-01-2024", - finalized: "19-01-2024", - }, - { - peer_id: "0xjkl", - location: "0.234234", - last_state: OpState.AwaitingResponse, - last_message: MessageType.RequestUpdate, - started: "19-01-2024", - finalized: "20-01-2024", - }, - { - peer_id: "0xghi", - location: "0.267127", - last_state: OpState.AwaitingResponse, - last_message: MessageType.RequestUpdate, - started: "21-01-2024", - finalized: "22-01-2024", - }, - ], - "124": [ - { - peer_id: "0xdef", - location: "0.1789234", - last_state: OpState.BroadcastOngoing, - last_message: MessageType.Broadcasting, - started: "12-01-2024", - finalized: "13-01-2024", - }, - { - peer_id: "0xabc", - location: "0.16234", - last_state: OpState.Finished, - last_message: MessageType.SuccessfulUpdate, - started: "18-01-2024", - finalized: "19-01-2024", - }, - { - peer_id: "0xghi", - location: "0.234234", - last_state: OpState.ReceivedRequest, - last_message: MessageType.BroadcastTo, - started: "19-01-2024", - finalized: "20-01-2024", - }, - { - peer_id: "0xjkl", - location: "0.267127", - last_state: OpState.AwaitingResponse, - last_message: MessageType.RequestUpdate, - started: "21-01-2024", - finalized: "22-01-2024", - }, - { - peer_id: "0xdef", - location: "0.1789234", - last_state: OpState.Finished, - last_message: MessageType.SuccessfulUpdate, - started: "12-01-2024", - finalized: "13-01-2024", - }, - { - peer_id: "0xabc", - location: "0.16234", - last_state: OpState.Finished, - last_message: MessageType.SuccessfulUpdate, - started: "18-01-2024", - finalized: "19-01-2024", - }, - { - peer_id: "0xjkl", - location: "0.234234", - last_state: OpState.AwaitingResponse, - last_message: MessageType.RequestUpdate, - started: "19-01-2024", - finalized: "20-01-2024", - }, - { - peer_id: "0xghi", - location: "0.267127", - last_state: OpState.BroadcastOngoing, - last_message: MessageType.Broadcasting, - started: "21-01-2024", - finalized: "22-01-2024", - }, - - ], -} + if (loading) { + setTimeout(() => { + set_loading(false); + }, 1000); + } + } + }, [tx_list, order_by, order_direction]); + + useEffect(() => { + if (tx_list) { + set_inner_tx_list(filter_by_page(ordered_tx_list, page)); + } + }, [page, ordered_tx_list]); + return ( + <> + {set_page(page)}}/> +
    + + + + + + + + + + {/* + + */} + + + + { + inner_tx_list?.map((tx: TransactionData, index) => ( + + + + + + + + + + {/* + + */} + + )) + } + +
    Transaction IdRequester Peer IdTarget Peer IdTypeContract KeyContract Location + Timestamp + + + StatusStartedFinalized
    open_tx_detail(tx.transaction_id)} style={{cursor: "pointer"}}>{tx.transaction_id.slice(-8)}{tx.requester.slice(-8)} + {tx.change_type == ChangeType.BROADCAST_EMITTED ? `${tx.target.length} peers` : tx.target.slice(-8)} + {tx.change_type}{tx.contract_id.slice(-8)}{tx.contract_location}{rust_timestamp_to_utc_string(tx.timestamp)}{tx.status}{tx.started}{tx.finalized}
    + + ); -const TransactionsTable = ({ open_tx_detail, tx_list }: TxTableInterface) => ( - - - - - - - - - {/* - - */} - - - - { - tx_list?.map((tx, index) => ( - - - - - - - {/* - - */} - - )) - } - -
    Transaction IdRequester Peer IdTarget Peer IdTypeContract KeyStatusStartedFinalized
    open_tx_detail(tx.transaction_id)} style={{cursor: "pointer"}}>{tx.transaction_id.slice(-8)}{tx.requester.slice(-8)}{tx.target.slice(-8)}{tx.change_type}{tx.contract_id.slice(-8)}{tx.status}{tx.started}{tx.finalized}
    -); +}; export function TransactionContainer() { const [is_detail_open, set_is_detail_open] = useState(false); @@ -224,9 +127,10 @@ export function TransactionContainer() { return; } + console.log("tx_history", tx_history); + set_transaction(tx_history[0]); set_transaction_history(tx_history); - // set_peers_history(mock_peers_in_tx[tx.id]); set_is_detail_open(true); window.scrollTo(0, 0); }; @@ -242,11 +146,10 @@ export function TransactionContainer() { updated_tx_list = updated_tx_list.flat(); - console.log(updated_tx_list); set_tx_list(updated_tx_list); } - document.addEventListener("keydown", (e: any) => { + document.addEventListener("keydown", (e: KeyboardEvent) => { if (e.key === "Escape") { close_detail(); } diff --git a/network-monitor/src/type_definitions.ts b/network-monitor/src/type_definitions.ts index 52fc621d0..8375da717 100644 --- a/network-monitor/src/type_definitions.ts +++ b/network-monitor/src/type_definitions.ts @@ -5,18 +5,24 @@ export enum ChangeType { PUT_REQUEST = "Put Request", PUT_SUCCESS = "Put Success", PUT_FAILURE = "Put Failure", + BROADCAST_EMITTED = "Broadcast Emitted", + BROADCAST_RECEIVED = "Broadcast Received", } export type TransactionData = { change_type: ChangeType; transaction_id: string; contract_id: string; - target: string; + target: any; requester: string; - status: string | null; - started: string | null; - finalized: string | null; unique_id: string; + timestamp: number; + contract_location: number; + status?: string; + started?: string; + finalized?: string; + upstream?: string; + requester_location?: number; }; export interface TransactionInterface { @@ -44,6 +50,7 @@ export interface TransactionDetailInterface { close_detail: () => void; peers_history?: Array; tx_history?: Array; + mermaid_text?: string; } export interface TxTableInterface { @@ -83,3 +90,100 @@ export enum OpState { PrepareRequest = "PrepareRequest", BroadcastOngoing = "BroadcastOngoing", } + +export type PutMsgData = { + transaction: string; + contract_id: string; + target: string; + requester: string; + change_type: ChangeType; + timestamp: number; + contract_location: number; +}; + +export interface TransactionDetailPeersHistoryInterface { + tx_peer_list: Array; +} + +export interface FilterInterface { + filter_type: string; + filter_value: string; +} + +export interface FilterDictionaryInterface { + [key: string]: FilterInterface; +} + +export interface ContractHistoryInterface { + contract_history: Array; +} + +export interface RingVisualizationPoint { + peerId: string; + localization: number; +} + +export interface RingVisualizationProps { + main_peer?: RingVisualizationPoint; + other_peers: RingVisualizationPoint[]; + selected_text?: string; +} + +export interface PeerList { + [id: string]: Peer; +} + +export interface Peer { + id: PeerId; + currentLocation: number; + connectionTimestamp: number; + connections: Connection[]; + history: ChangeInfo[]; + locationHistory: { location: number; timestamp: number }[]; +} + +export interface Connection { + transaction: string | null; + id: PeerId; + location: number; +} + +export interface ChangeInfo { + type: "Added" | "Removed"; + from: Connection; + to: Connection; + timestamp: number; +} + +export class PeerId { + private id: string; + + constructor(id: string | Uint8Array) { + if (id instanceof Uint8Array) { + this.id = new TextDecoder().decode(id); + } else { + this.id = id; + } + } + + get short() { + return this.id.slice(-8); + } + + get full() { + return this.id; + } +} + +export interface TransactionDetailPeersHistoryInterface { + tx_peer_list: Array; +} + +export interface FilterInterface { + filter_type: string; + filter_value: string; +} + +export interface TranscationHistoryInterface { + tx_history: Array; +} diff --git a/network-monitor/src/utils.ts b/network-monitor/src/utils.ts index af8d7fa06..953441186 100644 --- a/network-monitor/src/utils.ts +++ b/network-monitor/src/utils.ts @@ -1,4 +1,9 @@ -import { ChangeType } from "./type_definitions"; +import { + ChangeType, + PutMsgData, + RingVisualizationPoint, + TransactionData, +} from "./type_definitions"; import { ContractChange } from "./generated/topology"; import * as fbTopology from "./generated/topology"; @@ -12,6 +17,10 @@ export const get_change_type = ( return ChangeType.PUT_SUCCESS; case fbTopology.ContractChangeType.PutFailure: return ChangeType.PUT_FAILURE; + case fbTopology.ContractChangeType.BroadcastEmitted: + return ChangeType.BROADCAST_EMITTED; + case fbTopology.ContractChangeType.BroadcastReceived: + return ChangeType.BROADCAST_RECEIVED; default: new Error("Invalid change type"); } @@ -19,27 +28,321 @@ export const get_change_type = ( return null; }; -export const parse_put_msg_data = ( +export const parse_put_request_msg_data = ( contractChange: ContractChange, changeType: fbTopology.ContractChangeType -): any => { +): PutMsgData => { let put_request_obj = contractChange.change(new fbTopology.PutRequest()); - let transaction = put_request_obj.transaction()!; + let transaction = put_request_obj.transaction(); - let contract_id = contractChange.contractId()!; + if (!transaction) { + throw new Error("Transaction ID not found"); + } + + let contract_id = contractChange.contractId(); + + if (!contract_id) { + throw new Error("Contract ID not found"); + } + + let target = put_request_obj.target(); + + if (!target) { + throw new Error("Target Peer not found"); + } + + let requester = put_request_obj.requester(); - let target = put_request_obj.target()!; + if (!requester) { + throw new Error("Requester Peer not found"); + } - let requester = put_request_obj.requester()!; + let timestamp = put_request_obj.timestamp()!; let change_type = get_change_type(changeType)!; + let contract_location = put_request_obj.contractLocation()!; + return { transaction, contract_id, target, requester, change_type, + timestamp, + contract_location, + } as PutMsgData; +}; + +export const parse_put_success_msg_data = ( + contractChange: ContractChange, + changeType: fbTopology.ContractChangeType +): PutMsgData => { + let put_request_obj = contractChange.change(new fbTopology.PutSuccess()); + + let transaction = put_request_obj.transaction(); + + if (!transaction) { + throw new Error("Transaction ID not found"); + } + + let contract_id = contractChange.contractId(); + + if (!contract_id) { + throw new Error("Contract ID not found"); + } + + let target = put_request_obj.target(); + + if (!target) { + throw new Error("Target Peer not found"); + } + + let requester = put_request_obj.requester(); + + if (!requester) { + throw new Error("Requester Peer not found"); + } + + let timestamp = put_request_obj.timestamp()!; + + let change_type = get_change_type(changeType)!; + + let contract_location = put_request_obj.contractLocation()!; + + return { + transaction, + contract_id, + target, + requester, + change_type, + timestamp, + contract_location, + } as PutMsgData; +}; + +export const parse_broadcast_emitted_msg = ( + contractChange: ContractChange, + changeType: fbTopology.ContractChangeType +) => { + let broadcast_emitted_obj = contractChange.change( + new fbTopology.BroadcastEmitted() + ); + + let transaction = broadcast_emitted_obj.transaction(); + + if (!transaction) { + throw new Error("Transaction ID not found"); + } + + let upstream = broadcast_emitted_obj.upstream(); + + if (!upstream) { + throw new Error("Upstream Peer not found"); + } + + let broadcast_to = []; + + for (let i = 0; i < broadcast_emitted_obj.broadcastToLength(); i++) { + broadcast_to.push(broadcast_emitted_obj.broadcastTo(i)!); + } + + // console.log("broadcastTo", broadcast_to); + + if (broadcast_to.length == 0) { + throw new Error("Broadcast To Peers not found"); + } + + let broadcasted_to = broadcast_emitted_obj.broadcastedTo()!; + + // console.log(broadcasted_to); + + let contract_key = broadcast_emitted_obj.key(); + + if (!contract_key) { + throw new Error("Contract Key not found"); + } + + let sender = broadcast_emitted_obj.sender(); + + if (!sender) { + throw new Error("Sender Peer not found"); + } + + let timestamp = broadcast_emitted_obj.timestamp()!; + + let change_type = get_change_type(changeType)!; + + let contract_location = broadcast_emitted_obj.contractLocation()!; + + return { + transaction, + upstream, + broadcast_to, + key: contract_key, + requester: sender, + change_type, + timestamp, + contract_location, + }; +}; + +export const parse_broadcast_received_msg = ( + contractChange: ContractChange, + changeType: fbTopology.ContractChangeType +) => { + let broadcast_received_obj = contractChange.change( + new fbTopology.BroadcastReceived() + ); + + let transaction = broadcast_received_obj.transaction(); + + if (!transaction) { + throw new Error("Transaction ID not found"); + } + + let target = broadcast_received_obj.target(); + if (!target) { + throw new Error("Target Peer not found"); + } + + let requester = broadcast_received_obj.requester(); + + if (!requester) { + throw new Error("Requester Peer not found"); + } + + let contract_key = broadcast_received_obj.key(); + + if (!contract_key) { + throw new Error("Contract Key not found"); + } + + let timestamp = broadcast_received_obj.timestamp()!; + + let change_type = get_change_type(changeType)!; + + let contract_location = broadcast_received_obj.contractLocation()!; + + return { + transaction, + target, + requester, + key: contract_key, + change_type, + timestamp, + contract_location, }; }; + +export const rust_timestamp_to_utc_string = (timestamp: number): string => { + return new Date(parseInt(timestamp.toString()) * 1000).toUTCString(); +}; + +export const transactions_per_page = 10; + +export const get_all_pages = (tx_list: Array) => { + return Math.ceil(tx_list.length / transactions_per_page); +}; + +export const filter_by_page = ( + tx_list: Array, + page: number +) => { + let updated_tx_list = tx_list; + let start = (page - 1) * transactions_per_page; + let end = start + transactions_per_page; + + updated_tx_list = updated_tx_list.slice(start, end); + + return updated_tx_list; +}; + +export const get_peers_description_to_render = ( + tx_peer_list: TransactionData[] +) => { + let peer_description = "graph TD\n"; + + for (const peer of tx_peer_list) { + let peer_id = peer.requester; + let peer_location = peer.contract_location; + let change_type = peer.change_type; + let peer_target = peer.target; + + if (typeof peer_target == "string") { + //peer_target = peer_target.split(" (@")[0].slice(-8); + peer_target = [peer_target]; + } + + let sliced_id = peer_id.slice(-8); + + let connection_type; + let node_styling; + + if (change_type == ChangeType.BROADCAST_EMITTED) { + connection_type = "-.->"; + } else if ( + change_type == ChangeType.PUT_REQUEST || + change_type == ChangeType.PUT_SUCCESS + ) { + connection_type = "==>"; + } else { + connection_type = "-->"; + } + + node_styling = + change_type == ChangeType.PUT_REQUEST + ? "style " + sliced_id + " stroke:#1B2A41,stroke-width:3px" + : null; + + for (let one_peer of peer_target) { + one_peer = one_peer.split(" (@")[0].slice(-8); + + let peer_connection = `${sliced_id} ${connection_type}|${change_type}| ${one_peer}`; + + if (node_styling) { + peer_connection += "\n" + node_styling; + } + + peer_description += peer_connection + "\n"; + } + } + + return peer_description; +}; + +export const refresh_peers_tree = async (graph_definition: string) => { + let element = document.querySelector("#transactions-tree-graph")!; + const { svg, bindFunctions } = await window.mermaid.render( + "mermaid-tree", + graph_definition + ); + element.innerHTML = svg; + bindFunctions?.(element); +}; + +export const get_peers_caching_the_contract = ( + tx_peer_list: TransactionData[] +): RingVisualizationPoint[] => { + let peers_caching_contract: RingVisualizationPoint[] = []; + + for (const peer of tx_peer_list) { + if (peer.change_type == ChangeType.PUT_SUCCESS) { + if ( + peers_caching_contract.filter( + (data) => data.peerId == peer.requester + ).length != 0 + ) { + continue; + } + + peers_caching_contract.push({ + localization: peer.requester_location as number, + peerId: peer.requester as string, + } as RingVisualizationPoint); + } + } + + return peers_caching_contract; +}; diff --git a/network-monitor/tests/topology.test.ts b/network-monitor/tests/topology.test.ts index 41ec74900..ab9831f08 100644 --- a/network-monitor/tests/topology.test.ts +++ b/network-monitor/tests/topology.test.ts @@ -3,91 +3,96 @@ */ import { - AddedConnectionT, - RemovedConnectionT, + AddedConnectionT, + RemovedConnectionT, } from "../src/generated/topology"; import { - handleAddedConnection, - handleRemovedConnection, - peers, - PeerId, + handleAddedConnection, + handleRemovedConnection, + peers, } from "../src/topology"; +import { PeerId } from "../src/type_definitions"; + describe("Network Monitor App", () => { - afterEach(() => { - jest.clearAllMocks(); - }); + afterEach(() => { + jest.clearAllMocks(); + }); - test("should update peers table when receiving added connection", () => { - const mockAddedConnection = new AddedConnectionT( - "tx1", - "peer1", - 0.6254, - "peer2", - 0.2875 - ); - handleAddedConnection(mockAddedConnection); + test("should update peers table when receiving added connection", () => { + const mockAddedConnection = new AddedConnectionT( + "tx1", + "peer1", + 0.6254, + "peer2", + 0.2875 + ); + handleAddedConnection(mockAddedConnection); - const peer1 = new PeerId("peer1"); - const peer2 = new PeerId("peer2"); - expect(peers).toEqual({ - peer1: { - id: peer1, - locationHistory: [], - currentLocation: 0.6254, - connectionTimestamp: expect.any(Number), - connections: [{ id: peer2, location: 0.2875, transaction: "tx1" }], - history: [ - { - type: "Added", - from: { - id: peer1, - location: 0.6254, - transaction: "tx1", - }, - to: { - id: peer2, - location: 0.2875, - transaction: "tx1", + const peer1 = new PeerId("peer1"); + const peer2 = new PeerId("peer2"); + expect(peers).toEqual({ + peer1: { + id: peer1, + locationHistory: [], + currentLocation: 0.6254, + connectionTimestamp: expect.any(Number), + connections: [ + { id: peer2, location: 0.2875, transaction: "tx1" }, + ], + history: [ + { + type: "Added", + from: { + id: peer1, + location: 0.6254, + transaction: "tx1", + }, + to: { + id: peer2, + location: 0.2875, + transaction: "tx1", + }, + timestamp: expect.any(Number), + }, + ], }, - timestamp: expect.any(Number), - }, - ], - }, - peer2: { - id: peer2, - locationHistory: [], - currentLocation: 0.2875, - connectionTimestamp: expect.any(Number), - connections: [{ id: peer1, location: 0.6254, transaction: "tx1" }], - history: [ - { - type: "Added", - from: { - id: peer1, - location: 0.6254, - transaction: "tx1", + peer2: { + id: peer2, + locationHistory: [], + currentLocation: 0.2875, + connectionTimestamp: expect.any(Number), + connections: [ + { id: peer1, location: 0.6254, transaction: "tx1" }, + ], + history: [ + { + type: "Added", + from: { + id: peer1, + location: 0.6254, + transaction: "tx1", + }, + to: { + id: peer2, + location: 0.2875, + transaction: "tx1", + }, + timestamp: expect.any(Number), + }, + ], }, - to: { - id: peer2, - location: 0.2875, - transaction: "tx1", - }, - timestamp: expect.any(Number), - }, - ], - }, + }); }); - }); - test("should update peers table when receiving removed connection", () => { - const removedConnection = new RemovedConnectionT("peer1", "peer2"); + test("should update peers table when receiving removed connection", () => { + const removedConnection = new RemovedConnectionT("peer1", "peer2"); - handleRemovedConnection(removedConnection); + handleRemovedConnection(removedConnection); - expect(peers["peer1"].connections).toHaveLength(0); - expect(peers["peer2"].connections).toHaveLength(0); - expect(peers["peer1"].history).toHaveLength(2); - expect(peers["peer2"].history).toHaveLength(2); - }); + expect(peers["peer1"].connections).toHaveLength(0); + expect(peers["peer2"].connections).toHaveLength(0); + expect(peers["peer1"].history).toHaveLength(2); + expect(peers["peer2"].history).toHaveLength(2); + }); }); diff --git a/schemas/flatbuffers/topology.fbs b/schemas/flatbuffers/topology.fbs index eecf8d52f..ec1ae17f7 100644 --- a/schemas/flatbuffers/topology.fbs +++ b/schemas/flatbuffers/topology.fbs @@ -47,6 +47,8 @@ table PutRequest { key: string(required); requester: string(required); target: string(required); + timestamp: uint64; + contract_location: float64; } table UpdateRequest { @@ -61,6 +63,8 @@ table PutSuccess { requester: string(required); target: string(required); key: string(required); + timestamp: uint64; + contract_location: float64; } table PutFailure { @@ -84,10 +88,33 @@ table UpdateFailure { key: string(required); } +table BroadcastEmitted { + transaction: string(required); + upstream: string(required); + broadcast_to: [string]; + broadcasted_to: uint32; + key: string(required); + sender: string(required); + + timestamp: uint64; + contract_location: float64; +} + +table BroadcastReceived { + transaction: string(required); + target: string(required); + requester: string(required); + key: string(required); + timestamp: uint64; + contract_location: float64; +} + union ContractChangeType { PutRequest, PutSuccess, PutFailure, + BroadcastEmitted, + BroadcastReceived, UpdateRequest, UpdateSuccess, UpdateFailure, diff --git a/schemas/flatbuffers/topology.ts b/schemas/flatbuffers/topology.ts index 587590dc4..2f3dead61 100644 --- a/schemas/flatbuffers/topology.ts +++ b/schemas/flatbuffers/topology.ts @@ -1,18 +1,20 @@ // automatically generated by the FlatBuffers compiler, do not modify -export { AddedConnection } from './topology/added-connection.js'; -export { ContractChange } from './topology/contract-change.js'; -export { ContractChangeType } from './topology/contract-change-type.js'; -export { ControllerResponse } from './topology/controller-response.js'; -export { Error } from './topology/error.js'; -export { Ok } from './topology/ok.js'; -export { PeerChange } from './topology/peer-change.js'; -export { PeerChangeType } from './topology/peer-change-type.js'; -export { PutFailure } from './topology/put-failure.js'; -export { PutRequest } from './topology/put-request.js'; -export { PutSuccess } from './topology/put-success.js'; -export { RemovedConnection } from './topology/removed-connection.js'; -export { Response } from './topology/response.js'; -export { UpdateFailure } from './topology/update-failure.js'; -export { UpdateRequest } from './topology/update-request.js'; -export { UpdateSuccess } from './topology/update-success.js'; +export { AddedConnection } from "./topology/added-connection.js"; +export { BroadcastEmitted } from "./topology/broadcast-emitted.js"; +export { BroadcastReceived } from "./topology/broadcast-received.js"; +export { ContractChange } from "./topology/contract-change.js"; +export { ContractChangeType } from "./topology/contract-change-type.js"; +export { ControllerResponse } from "./topology/controller-response.js"; +export { Error } from "./topology/error.js"; +export { Ok } from "./topology/ok.js"; +export { PeerChange } from "./topology/peer-change.js"; +export { PeerChangeType } from "./topology/peer-change-type.js"; +export { PutFailure } from "./topology/put-failure.js"; +export { PutRequest } from "./topology/put-request.js"; +export { PutSuccess } from "./topology/put-success.js"; +export { RemovedConnection } from "./topology/removed-connection.js"; +export { Response } from "./topology/response.js"; +export { UpdateFailure } from "./topology/update-failure.js"; +export { UpdateRequest } from "./topology/update-request.js"; +export { UpdateSuccess } from "./topology/update-success.js"; diff --git a/schemas/flatbuffers/topology/broadcast-emitted.ts b/schemas/flatbuffers/topology/broadcast-emitted.ts new file mode 100644 index 000000000..c915be061 --- /dev/null +++ b/schemas/flatbuffers/topology/broadcast-emitted.ts @@ -0,0 +1,147 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class BroadcastEmitted { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):BroadcastEmitted { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsBroadcastEmitted(bb:flatbuffers.ByteBuffer, obj?:BroadcastEmitted):BroadcastEmitted { + return (obj || new BroadcastEmitted()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsBroadcastEmitted(bb:flatbuffers.ByteBuffer, obj?:BroadcastEmitted):BroadcastEmitted { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new BroadcastEmitted()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +transaction():string|null +transaction(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +transaction(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +upstream():string|null +upstream(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +upstream(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +broadcastTo(index: number):string +broadcastTo(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array +broadcastTo(index: number,optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null; +} + +broadcastToLength():number { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +broadcastedTo():number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; +} + +key():string|null +key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +key(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +sender():string|null +sender(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +sender(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +timestamp():bigint { + const offset = this.bb!.__offset(this.bb_pos, 16); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); +} + +contractLocation():number { + const offset = this.bb!.__offset(this.bb_pos, 18); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; +} + +static startBroadcastEmitted(builder:flatbuffers.Builder) { + builder.startObject(8); +} + +static addTransaction(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, transactionOffset, 0); +} + +static addUpstream(builder:flatbuffers.Builder, upstreamOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, upstreamOffset, 0); +} + +static addBroadcastTo(builder:flatbuffers.Builder, broadcastToOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, broadcastToOffset, 0); +} + +static createBroadcastToVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startBroadcastToVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static addBroadcastedTo(builder:flatbuffers.Builder, broadcastedTo:number) { + builder.addFieldInt32(3, broadcastedTo, 0); +} + +static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { + builder.addFieldOffset(4, keyOffset, 0); +} + +static addSender(builder:flatbuffers.Builder, senderOffset:flatbuffers.Offset) { + builder.addFieldOffset(5, senderOffset, 0); +} + +static addTimestamp(builder:flatbuffers.Builder, timestamp:bigint) { + builder.addFieldInt64(6, timestamp, BigInt('0')); +} + +static addContractLocation(builder:flatbuffers.Builder, contractLocation:number) { + builder.addFieldFloat64(7, contractLocation, 0.0); +} + +static endBroadcastEmitted(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + builder.requiredField(offset, 4) // transaction + builder.requiredField(offset, 6) // upstream + builder.requiredField(offset, 12) // key + builder.requiredField(offset, 14) // sender + return offset; +} + +static createBroadcastEmitted(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, upstreamOffset:flatbuffers.Offset, broadcastToOffset:flatbuffers.Offset, broadcastedTo:number, keyOffset:flatbuffers.Offset, senderOffset:flatbuffers.Offset, timestamp:bigint, contractLocation:number):flatbuffers.Offset { + BroadcastEmitted.startBroadcastEmitted(builder); + BroadcastEmitted.addTransaction(builder, transactionOffset); + BroadcastEmitted.addUpstream(builder, upstreamOffset); + BroadcastEmitted.addBroadcastTo(builder, broadcastToOffset); + BroadcastEmitted.addBroadcastedTo(builder, broadcastedTo); + BroadcastEmitted.addKey(builder, keyOffset); + BroadcastEmitted.addSender(builder, senderOffset); + BroadcastEmitted.addTimestamp(builder, timestamp); + BroadcastEmitted.addContractLocation(builder, contractLocation); + return BroadcastEmitted.endBroadcastEmitted(builder); +} +} diff --git a/schemas/flatbuffers/topology/broadcast-received.ts b/schemas/flatbuffers/topology/broadcast-received.ts new file mode 100644 index 000000000..865c42fb1 --- /dev/null +++ b/schemas/flatbuffers/topology/broadcast-received.ts @@ -0,0 +1,108 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class BroadcastReceived { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):BroadcastReceived { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsBroadcastReceived(bb:flatbuffers.ByteBuffer, obj?:BroadcastReceived):BroadcastReceived { + return (obj || new BroadcastReceived()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsBroadcastReceived(bb:flatbuffers.ByteBuffer, obj?:BroadcastReceived):BroadcastReceived { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new BroadcastReceived()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +transaction():string|null +transaction(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +transaction(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +target():string|null +target(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +target(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +requester():string|null +requester(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +requester(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +key():string|null +key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +key(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +timestamp():bigint { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); +} + +contractLocation():number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; +} + +static startBroadcastReceived(builder:flatbuffers.Builder) { + builder.startObject(6); +} + +static addTransaction(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, transactionOffset, 0); +} + +static addTarget(builder:flatbuffers.Builder, targetOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, targetOffset, 0); +} + +static addRequester(builder:flatbuffers.Builder, requesterOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, requesterOffset, 0); +} + +static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { + builder.addFieldOffset(3, keyOffset, 0); +} + +static addTimestamp(builder:flatbuffers.Builder, timestamp:bigint) { + builder.addFieldInt64(4, timestamp, BigInt('0')); +} + +static addContractLocation(builder:flatbuffers.Builder, contractLocation:number) { + builder.addFieldFloat64(5, contractLocation, 0.0); +} + +static endBroadcastReceived(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + builder.requiredField(offset, 4) // transaction + builder.requiredField(offset, 6) // target + builder.requiredField(offset, 8) // requester + builder.requiredField(offset, 10) // key + return offset; +} + +static createBroadcastReceived(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset, timestamp:bigint, contractLocation:number):flatbuffers.Offset { + BroadcastReceived.startBroadcastReceived(builder); + BroadcastReceived.addTransaction(builder, transactionOffset); + BroadcastReceived.addTarget(builder, targetOffset); + BroadcastReceived.addRequester(builder, requesterOffset); + BroadcastReceived.addKey(builder, keyOffset); + BroadcastReceived.addTimestamp(builder, timestamp); + BroadcastReceived.addContractLocation(builder, contractLocation); + return BroadcastReceived.endBroadcastReceived(builder); +} +} diff --git a/schemas/flatbuffers/topology/put-request.ts b/schemas/flatbuffers/topology/put-request.ts index ce2a1ae0b..e033180cb 100644 --- a/schemas/flatbuffers/topology/put-request.ts +++ b/schemas/flatbuffers/topology/put-request.ts @@ -48,8 +48,18 @@ target(optionalEncoding?:any):string|Uint8Array|null { return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; } +timestamp():bigint { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); +} + +contractLocation():number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; +} + static startPutRequest(builder:flatbuffers.Builder) { - builder.startObject(4); + builder.startObject(6); } static addTransaction(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset) { @@ -68,6 +78,14 @@ static addTarget(builder:flatbuffers.Builder, targetOffset:flatbuffers.Offset) { builder.addFieldOffset(3, targetOffset, 0); } +static addTimestamp(builder:flatbuffers.Builder, timestamp:bigint) { + builder.addFieldInt64(4, timestamp, BigInt('0')); +} + +static addContractLocation(builder:flatbuffers.Builder, contractLocation:number) { + builder.addFieldFloat64(5, contractLocation, 0.0); +} + static endPutRequest(builder:flatbuffers.Builder):flatbuffers.Offset { const offset = builder.endObject(); builder.requiredField(offset, 4) // transaction @@ -77,12 +95,14 @@ static endPutRequest(builder:flatbuffers.Builder):flatbuffers.Offset { return offset; } -static createPutRequest(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset):flatbuffers.Offset { +static createPutRequest(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset, timestamp:bigint, contractLocation:number):flatbuffers.Offset { PutRequest.startPutRequest(builder); PutRequest.addTransaction(builder, transactionOffset); PutRequest.addKey(builder, keyOffset); PutRequest.addRequester(builder, requesterOffset); PutRequest.addTarget(builder, targetOffset); + PutRequest.addTimestamp(builder, timestamp); + PutRequest.addContractLocation(builder, contractLocation); return PutRequest.endPutRequest(builder); } } diff --git a/schemas/flatbuffers/topology/put-success.ts b/schemas/flatbuffers/topology/put-success.ts index ca1e950e2..14acda9f7 100644 --- a/schemas/flatbuffers/topology/put-success.ts +++ b/schemas/flatbuffers/topology/put-success.ts @@ -48,8 +48,18 @@ key(optionalEncoding?:any):string|Uint8Array|null { return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; } +timestamp():bigint { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); +} + +contractLocation():number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; +} + static startPutSuccess(builder:flatbuffers.Builder) { - builder.startObject(4); + builder.startObject(6); } static addTransaction(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset) { @@ -68,6 +78,14 @@ static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { builder.addFieldOffset(3, keyOffset, 0); } +static addTimestamp(builder:flatbuffers.Builder, timestamp:bigint) { + builder.addFieldInt64(4, timestamp, BigInt('0')); +} + +static addContractLocation(builder:flatbuffers.Builder, contractLocation:number) { + builder.addFieldFloat64(5, contractLocation, 0.0); +} + static endPutSuccess(builder:flatbuffers.Builder):flatbuffers.Offset { const offset = builder.endObject(); builder.requiredField(offset, 4) // transaction @@ -77,12 +95,14 @@ static endPutSuccess(builder:flatbuffers.Builder):flatbuffers.Offset { return offset; } -static createPutSuccess(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset):flatbuffers.Offset { +static createPutSuccess(builder:flatbuffers.Builder, transactionOffset:flatbuffers.Offset, requesterOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset, keyOffset:flatbuffers.Offset, timestamp:bigint, contractLocation:number):flatbuffers.Offset { PutSuccess.startPutSuccess(builder); PutSuccess.addTransaction(builder, transactionOffset); PutSuccess.addRequester(builder, requesterOffset); PutSuccess.addTarget(builder, targetOffset); PutSuccess.addKey(builder, keyOffset); + PutSuccess.addTimestamp(builder, timestamp); + PutSuccess.addContractLocation(builder, contractLocation); return PutSuccess.endPutSuccess(builder); } }