diff --git a/Cargo.toml b/Cargo.toml index aeb7344..d9ecb46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,31 +6,30 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -sovereign-sdk = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "e848baea380880d7c95d3d5cfbf7486c51fe3b79" } -tendermint = "0.32" -tendermint-proto = "0.32" - +borsh = { version = "0.10.3", features = ["bytes"] } prost = "0.11" prost-types = "0.11" -borsh = { version = "0.10.3", features = ["bytes"] } +tendermint = "0.32" +tendermint-proto = "0.32" # Convenience -reqwest = { version = "0.11.13", features = ["blocking"], optional = true } -tokio = { version = "1", features = ["full"], optional = true } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -serde_cbor = "0.11.2" +anyhow = "1.0.62" +base64 = "0.13.1" hex = { version = "0.4.3", features = ["serde"] } hex-literal = "0.3.4" -base64 = "0.13.1" -anyhow = "1.0.62" jsonrpsee = { version = "0.16.2", features = ["http-client"], optional = true } +reqwest = { version = "0.11.13", features = ["blocking"], optional = true } +serde = { version = "1", features = ["derive"] } +serde_cbor = "0.11.2" +serde_json = "1" +tokio = { version = "1", features = ["full"], optional = true } tracing = "0.1.37" -nmt-rs = { git = "https://github.com/Sovereign-Labs/nmt-rs.git", rev = "aec2dcdc279b381162537f5b20ce43d1d46dc42f", features = ["serde", "borsh"] } +sovereign-sdk = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "3f948c098cf37040de3aaf2a86a18a1d91d082be" } +nmt-rs = { git = "https://github.com/Sovereign-Labs/nmt-rs.git", rev = "dd37588444fca72825d11fe4a46838f66525c49f", features = ["serde", "borsh"] } [dev-dependencies] -postcard = { version = "1", features = ["use-std"]} +postcard = { version = "1", features = ["use-std"] } [build-dependencies] prost-build = { version = "0.11" } diff --git a/src/celestia.rs b/src/celestia.rs index 2993690..ff1c483 100644 --- a/src/celestia.rs +++ b/src/celestia.rs @@ -1,3 +1,4 @@ +use std::fmt::{Display, Formatter}; use std::{cell::RefCell, ops::Range}; use borsh::{BorshDeserialize, BorshSerialize}; @@ -43,7 +44,7 @@ pub struct PartialBlockId { /// a tendermint::block::Header from being deserialized in most formats except JSON. However /// it also provides a significant efficiency benefit over the standard tendermint type, which /// performs a complete protobuf serialization every time `.hash()` is called. -#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] pub struct CompactHeader { /// Header version pub version: Vec, @@ -182,9 +183,7 @@ impl CompactHeader { } } -#[derive( - PartialEq, Debug, Clone, Deserialize, serde::Serialize, BorshDeserialize, BorshSerialize, -)] +#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct DataAvailabilityHeader { pub row_roots: Vec, pub column_roots: Vec, @@ -224,16 +223,17 @@ pub struct CelestiaHeaderResponse { pub dah: MarshalledDataAvailabilityHeader, } -#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] pub struct NamespacedSharesResponse { pub shares: Option>, pub height: u64, } -#[derive(Debug, PartialEq, Clone, Deserialize, serde::Serialize)] +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct CelestiaHeader { pub dah: DataAvailabilityHeader, pub header: CompactHeader, + #[borsh_skip] #[serde(skip)] cached_prev_hash: RefCell>, } @@ -260,7 +260,7 @@ impl CanonicalHash for CelestiaHeader { } } -#[derive(PartialEq, Clone, Debug, BorshDeserialize, BorshSerialize)] +#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] pub struct BlobWithSender { pub blob: Blob, pub sender: CelestiaAddress, @@ -283,7 +283,7 @@ impl BlockHeader for CelestiaHeader { ) .expect("must not call prev_hash on block with no predecessor") .hash; - *cached_hash = Some(TmHash(hash.clone())); + *cached_hash = Some(TmHash(hash)); TmHash(hash) } } @@ -329,6 +329,21 @@ impl<'a> TryFrom<&'a [u8]> for H160 { anyhow::bail!("Adress is not exactly 20 bytes"); } } + +impl From<[u8; 32]> for H160 { + fn from(value: [u8; 32]) -> Self { + let mut addr = [0u8; 20]; + addr.copy_from_slice(&value[12..]); + Self(addr) + } +} + +impl Display for H160 { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "0x{}", hex::encode(self.0)) + } +} + impl Address for H160 {} pub fn parse_pfb_namespace( diff --git a/src/da_service.rs b/src/da_service.rs index bf06120..0d163ac 100644 --- a/src/da_service.rs +++ b/src/da_service.rs @@ -1,12 +1,16 @@ use std::{collections::HashMap, future::Future, pin::Pin}; -use jsonrpsee::{core::client::ClientT, http_client::HttpClient}; +use jsonrpsee::{ + core::client::ClientT, + http_client::{HeaderMap, HttpClient}, +}; use nmt_rs::NamespaceId; use sovereign_sdk::services::da::DaService; use tracing::{debug, info, span, Level}; // 0x736f762d74657374 = b"sov-test" -// pub const ROLLUP_NAMESPACE: NamespaceId = NamespaceId(b"sov-test"); +// For testing, use this NamespaceId (b"sov-test"): +// pub const ROLLUP_NAMESPACE: NamespaceId = NamespaceId([115, 111, 118, 45, 116, 101, 115, 116]); use crate::{ parse_pfb_namespace, @@ -17,7 +21,7 @@ use crate::{ verifier::{ address::CelestiaAddress, proofs::{CompletenessProof, CorrectnessProof}, - CelestiaSpec, PFB_NAMESPACE, ROLLUP_NAMESPACE, + CelestiaSpec, RollupParams, PFB_NAMESPACE, }, BlobWithSender, CelestiaHeader, CelestiaHeaderResponse, DataAvailabilityHeader, }; @@ -25,25 +29,28 @@ use crate::{ #[derive(Debug, Clone)] pub struct CelestiaService { client: HttpClient, + rollup_namespace: NamespaceId, } impl CelestiaService { - pub fn with_client(client: HttpClient) -> Self { - Self { client } + pub fn with_client(client: HttpClient, nid: NamespaceId) -> Self { + Self { + client, + rollup_namespace: nid, + } } } -impl CelestiaService {} - /// Fetch the rollup namespace shares and etx data. Returns a tuple `(rollup_shares, etx_shares)` -pub async fn fetch_needed_shares_by_header( +async fn fetch_needed_shares_by_header( + rollup_namespace: NamespaceId, client: &HttpClient, header: &serde_json::Value, ) -> Result<(NamespaceGroup, NamespaceGroup), BoxError> { let dah = header .get("dah") .ok_or(BoxError::msg("missing dah in block header"))?; - let rollup_namespace_str = base64::encode(ROLLUP_NAMESPACE).into(); + let rollup_namespace_str = base64::encode(rollup_namespace).into(); let rollup_shares_future = { let params: Vec<&serde_json::Value> = vec![dah, &rollup_namespace_str]; client.request::("share.GetSharesByNamespace", params) @@ -77,6 +84,26 @@ pub async fn fetch_needed_shares_by_header( Ok((rollup_shares, tx_data)) } +/// Runtime configuration for the DA service +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +pub struct DaServiceConfig { + /// The jwt used to authenticate with the Celestia rpc server + pub celestia_rpc_auth_token: String, + /// The address of the Celestia rpc server + #[serde(default = "default_rpc_addr")] + pub celestia_rpc_address: String, + /// The maximum size of a Celestia RPC response, in bytes + #[serde(default = "default_max_response_size")] + pub max_celestia_response_body_size: u32, +} + +fn default_rpc_addr() -> String { + "http://localhost:11111/".into() +} + +fn default_max_response_size() -> u32 { + 1024 * 1024 * 100 // 100 MB +} impl DaService for CelestiaService { type FilteredBlock = FilteredCelestiaBlock; @@ -87,8 +114,30 @@ impl DaService for CelestiaService { type Error = BoxError; + type RuntimeConfig = DaServiceConfig; + + fn new(config: Self::RuntimeConfig, chain_params: RollupParams) -> Self { + let client = { + let mut headers = HeaderMap::new(); + headers.insert( + "Authorization", + format!("Bearer {}", config.celestia_rpc_auth_token) + .parse() + .unwrap(), + ); + jsonrpsee::http_client::HttpClientBuilder::default() + .set_headers(headers) + .max_request_body_size(config.max_celestia_response_body_size) // 100 MB + .build(&config.celestia_rpc_address) + } + .expect("Client initialization is valid"); + + Self::with_client(client, chain_params.namespace) + } + fn get_finalized_at(&self, height: u64) -> Self::Future { let client = self.client.clone(); + let rollup_namespace = self.rollup_namespace.clone(); Box::pin(async move { let _span = span!(Level::TRACE, "fetching finalized block", height = height); // Fetch the header and relevant shares via RPC @@ -98,7 +147,8 @@ impl DaService for CelestiaService { .await?; debug!(header_result = ?header); info!("Fetching shares..."); - let (rollup_shares, tx_data) = fetch_needed_shares_by_header(&client, &header).await?; + let (rollup_shares, tx_data) = + fetch_needed_shares_by_header(rollup_namespace, &client, &header).await?; info!("Fetching EDS..."); // Fetch entire extended data square @@ -120,7 +170,7 @@ impl DaService for CelestiaService { .await?; // Parse out all of the rows containing rollup data let rollup_rows = get_rows_containing_namespace( - ROLLUP_NAMESPACE, + rollup_namespace, &dah, data_square.rows()?.into_iter(), ) @@ -132,7 +182,7 @@ impl DaService for CelestiaService { let mut pfd_map = HashMap::new(); for tx in pfds { for (idx, nid) in tx.0.namespace_ids.iter().enumerate() { - if nid == &ROLLUP_NAMESPACE.0[..] { + if nid == &rollup_namespace.0[..] { // TODO: Retool this map to avoid cloning txs pfd_map.insert(tx.0.share_commitments[idx].clone(), tx.clone()); } @@ -190,7 +240,8 @@ impl DaService for CelestiaService { ) { let relevant_txs = self.extract_relevant_txs(block.clone()); let etx_proofs = CorrectnessProof::for_block(&block, &relevant_txs); - let rollup_row_proofs = CompletenessProof::from_filtered_block(&block); + let rollup_row_proofs = + CompletenessProof::from_filtered_block(&block, self.rollup_namespace); (relevant_txs, etx_proofs.0, rollup_row_proofs.0) } diff --git a/src/header_response.json b/src/header_response.json new file mode 100644 index 0000000..0e38a05 --- /dev/null +++ b/src/header_response.json @@ -0,0 +1,1566 @@ +{ + "validator_set": { + "validators": [ + { + "address": "762CBA617226A799D898F134DD12661C7F1129EB", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "6bdjjKHELaN9colwYy/ad+xh3MUgOVq106ZFucK46LE=" + }, + "voting_power": "21002592", + "proposer_priority": "-180122426" + }, + { + "address": "F5BB6F48121E1C99D26BCD27B8F00893C1DCADCF", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "vfOT6bT2LXrfBsjpirOcVxdHhTAjVqoD9Q0TOKFAbkA=" + }, + "voting_power": "20772846", + "proposer_priority": "20772846" + }, + { + "address": "4B7A5D6E4A2AC4753C1B7645D784DEC12C5383AA", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "68dDxVgm9Ahj8BW82g3nY1gfvq2muEeoeDdnJ340LWs=" + }, + "voting_power": "20440785", + "proposer_priority": "20440785" + }, + { + "address": "BA8A15ED6466EBE3B132D91CD86F98867B28B006", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "MYb6LWgYFVekDhYajl/nI8KDGa7Stv2YsEZkrWcrvIw=" + }, + "voting_power": "20394270", + "proposer_priority": "20394270" + }, + { + "address": "2F192A85E9117A3C166584F8AB20B315D8788C5E", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "eBoP7WNwXdpB1AGb2Ny4Rwi1DP3x/3m72h2GVZqdwik=" + }, + "voting_power": "20181600", + "proposer_priority": "20181600" + }, + { + "address": "8FBEF0DBAAE51D918F9ABFD96653F4932171870E", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "J8wAKpZrD9kRbewJDMLQAuYkYNh33PhCg+wcdVcGxIw=" + }, + "voting_power": "19900303", + "proposer_priority": "19900303" + }, + { + "address": "F14BA4525613719E6E8DD72BB40628B585D5CA53", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "g/tHi4xmmiav/N012t0TsqyWuJzWEb13h+VO0kbjEwQ=" + }, + "voting_power": "19819201", + "proposer_priority": "19819201" + }, + { + "address": "E1570712868BE0B12622BBAE08D96F5840F9D018", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "OHADjBcHrd2mld9DQre1MkiFKYN+7vlFou+eB6Ia/qc=" + }, + "voting_power": "19633245", + "proposer_priority": "19633245" + }, + { + "address": "0B76107110A486E8767FA1997EA0C4B40B7851AF", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "D3wP4IWMZcMt9UHVzFP2J19FDCP/732nvtT/f3CIatQ=" + }, + "voting_power": "19432240", + "proposer_priority": "19432240" + }, + { + "address": "3ACD2DA41FFBB07743A99A74A0FACEACF3A9E474", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "z4VR8LSO7jeupkwifkLevWc+dSloLq9dMME7k0nVqOQ=" + }, + "voting_power": "18000056", + "proposer_priority": "18000056" + }, + { + "address": "10C13814B94303B35EFFFAB319301714A4D69399", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "FULjq8Uf1zsGbs3izSZSBYRvr6k597hLmIEeBwHuEEc=" + }, + "voting_power": "500422", + "proposer_priority": "500422" + }, + { + "address": "6BDDFED21432C64D5F71E325CD6AF6FB16790391", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "fe6/iNJr7px2M5mr1aXkvt7f26+2qDM+LHo3eZHA/38=" + }, + "voting_power": "210358", + "proposer_priority": "210358" + }, + { + "address": "4875AD200AADE12185455050EA07E424D945FF64", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "gGsm+RV9RdfpNnrXbg8eZamm2fMtMh1P4E/eZRtFk1g=" + }, + "voting_power": "51092", + "proposer_priority": "51092" + }, + { + "address": "BB408FA902A7B6A938C788957B2A874153261EC5", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "7rE47Ol0HqaZhnQQqlx5BD8rNGv6yTcRQANXtMY7y4g=" + }, + "voting_power": "20856", + "proposer_priority": "20856" + }, + { + "address": "41FE068E3E8537EB35932A517836C1694C804746", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "2UV7v+AE3lX51fGs+h42FgLimv/SIYW0twAdOekck78=" + }, + "voting_power": "11693", + "proposer_priority": "11693" + }, + { + "address": "2E008FC8A683B806F82206DE091A9433515319CA", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "v5y5IraSyBzvIfcInHZ4groGSn1hokTe1k71QHtxbzE=" + }, + "voting_power": "11599", + "proposer_priority": "11599" + }, + { + "address": "6C3E4F3C92DE15FBC788F91747D8944586E9A1C0", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "y67VON5o65OicItNcd0S8MNd/22e1CGlRZpZXetC6DA=" + }, + "voting_power": "11366", + "proposer_priority": "11366" + }, + { + "address": "793B51BF408858FD72EC4198140D385C4076A208", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "x+JRxnYtuwPeHmNQOZ541uZzxoJd1cTUUGQ2+YmkMO8=" + }, + "voting_power": "11339", + "proposer_priority": "11339" + }, + { + "address": "7E2CB2FA8C46CDCA5BE02B0D656A0D61533445EC", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "yU84HuMOysbfwrWM6TA0PnCvn5jptbo5mYFHuZwo67c=" + }, + "voting_power": "11216", + "proposer_priority": "11216" + }, + { + "address": "22089FFD99FBBED4B77B88948F7D749C2784A1CF", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "MlFR9fiA74zWCEViKydSIlUo1igsgyq0JRhUQ7wi7WA=" + }, + "voting_power": "11196", + "proposer_priority": "11196" + }, + { + "address": "7C9538967D87E25FAD17A1180EEB6F174E8BAD84", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "I8gELA5RucvoH6gYz6iNErFmaQ4ZeMQkHWpAOe7NoGM=" + }, + "voting_power": "11158", + "proposer_priority": "11158" + }, + { + "address": "5808D8604443E8C1B11835FA8D7250FCFDAAB8AE", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "sJfNT8M3V8mMTvzHFJhKcgH5OgsTP9TCTPU/mgAMM3o=" + }, + "voting_power": "11027", + "proposer_priority": "11027" + }, + { + "address": "9C4395A21313734E9E322D55655EC55DEB9ABA81", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "IvkUe2jzMHymGsbvo0Ctu42gv7kS371g2VsC7PKA+ms=" + }, + "voting_power": "10860", + "proposer_priority": "10860" + }, + { + "address": "0590EF6F6AB31A98C786B2D4B639C62CB39F954B", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "VlBSILXJpT55YzMfgibI49GTnDqhzHZsfRtn457kMlI=" + }, + "voting_power": "10815", + "proposer_priority": "10815" + }, + { + "address": "22EFAD458C05DDDD14A001C52FEF84EC3D17A688", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "dD3BcTI3BXW8fEytVHFHOPcb759/02vxBju3fzeMSRA=" + }, + "voting_power": "10697", + "proposer_priority": "10697" + }, + { + "address": "80726DCD4E975716843F213C7E5A36400ABCFDFE", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "sAD409SvbABZBr0vCmjL6JK6XVQgQP4RM7v/Oiz/f88=" + }, + "voting_power": "10646", + "proposer_priority": "10646" + }, + { + "address": "7763A9F623F458DF0FEB7298E3FE1D67CECDA1FD", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "UQrlm/vvxj/tEKUf/G05seIT09ygG7q29r4czyemwSQ=" + }, + "voting_power": "10625", + "proposer_priority": "10625" + }, + { + "address": "CF238AB6BAF500A7623789F8EA7F3BCB95150574", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "jI1cMvsmHEU86V0N5JsTV5o+Yv3eqBal+QgjGRhb/4w=" + }, + "voting_power": "10592", + "proposer_priority": "10592" + }, + { + "address": "38A9BFEBAD0FA8A5E9E5AFB1A0AE01C1EA85729C", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "Igw5QFJdLJEqOrsYxYVUdcWi1bbQDIIFLxbigfEXmqk=" + }, + "voting_power": "10464", + "proposer_priority": "10464" + }, + { + "address": "87697AD05E817F183CBAC23D6F711EFFC73E7CB1", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "yUsnxCQpmHyY7/UHKzgtx/k4l+n2g1OlP+DOpkdQztU=" + }, + "voting_power": "10386", + "proposer_priority": "10386" + }, + { + "address": "FD17755AE1B0FE464B4F9996598EF9A51F602DB3", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "yLHp1YFCKUSWf51N58x2aG6TRs9GKZdtE+InCL1Zj0o=" + }, + "voting_power": "10362", + "proposer_priority": "10362" + }, + { + "address": "813D78C65701B7A792FB5F2DB7D4DBDEFCD7EE66", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "Wn8yx1RrmPdby+gqI7ErqCOJlJP05T4alnvdnu7vnxY=" + }, + "voting_power": "10342", + "proposer_priority": "10342" + }, + { + "address": "0003D94C13CDF1FC0A119AB6CDF454E6BFBCA4C3", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "NfIcNuLvvTabv/qz+/rgozADT/B+Wc6Aw2SzxrijaqY=" + }, + "voting_power": "10327", + "proposer_priority": "10327" + }, + { + "address": "284DBBD8B2BBF32E4004A817473D05E3A66C5C4A", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "b7Y258ExeJsXOai7gP9DupujCVbf2AlrJv1mltTGi30=" + }, + "voting_power": "10280", + "proposer_priority": "10280" + }, + { + "address": "372FF124AF7D42DCE4FF40952E3E21D43C33C60D", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "Kbv0oySUstYPOiDcJyJypDSWHHkgbUdWvItYruU3jSw=" + }, + "voting_power": "10266", + "proposer_priority": "10266" + }, + { + "address": "38CECDD91DAE3D8F536C080742A69FEBB6EFDBFF", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "RYrMwDTpJWv67sFVwKtmS+UxlN7hljKGWJqOsutcB1s=" + }, + "voting_power": "10263", + "proposer_priority": "10263" + }, + { + "address": "21AECD90BAD73E77875F641299469C2A348D79CB", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "G6ZLhPaJHQCBqUvs1M2K3QJT9vcXM7Qi73Jjo28d9Dg=" + }, + "voting_power": "10213", + "proposer_priority": "10213" + }, + { + "address": "268BCEBBE4D9075F9DE971DE34A636B4316B5EC5", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "cYlH04/HHOVMAN/vOkS3R+jP2z4dyDQmnFKSnvOgPts=" + }, + "voting_power": "10196", + "proposer_priority": "10196" + }, + { + "address": "312ED92F9E7A65BC80DFDB59AB05BD85754E7E95", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "CWxVE0hu9cUZ4fGJrxkxW9ZYT1pH5mA4O04Y0JOnkvM=" + }, + "voting_power": "10133", + "proposer_priority": "10133" + }, + { + "address": "68D747F35AE07631AF2E94CFF06BA30A9EFC8712", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "ILj5kerxa/UjJ9L4eAgi3rpteIp5b63Smyqysn4T3WU=" + }, + "voting_power": "10131", + "proposer_priority": "10131" + }, + { + "address": "EA14DE7F3FE756943AFDFDC23A2C8720E80F2C79", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "JAgIlYqwwU+nW/CoSnXPVn1YV8Wg4zb19i84kKMbIwk=" + }, + "voting_power": "10127", + "proposer_priority": "10127" + }, + { + "address": "B5698E7725F2D206A6652D945F75E9FDA2219F9D", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "Y+07AMlGx0La8Sr9aTMTbMMI9cuv9mrHQCWom921Uug=" + }, + "voting_power": "10112", + "proposer_priority": "10112" + }, + { + "address": "887BB5E1B4DBFF7117434FE7567CB8F2DC1B1F38", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "FjLtJraEKp4JoQEy8cI6L6haRkgO9CHh9dTZwbQk3gM=" + }, + "voting_power": "10110", + "proposer_priority": "10110" + }, + { + "address": "407DF17CD5EB1967597FC14A15A9D883DE884C93", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "VkA34n9aydhX5Gl0mBga06j7/ThNuBljC/T33ZP/Cdk=" + }, + "voting_power": "10108", + "proposer_priority": "10108" + }, + { + "address": "EE927F115AD4FD4BC131CA311D332ADDAC62CCAC", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "SfFXATPCbIeRUsb9RP+BfdYOH0v7H2aGbPGx1HlR1I0=" + }, + "voting_power": "10107", + "proposer_priority": "10107" + }, + { + "address": "A133A0F5CF118D107DC6326322460783F380C0E5", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "bb8zgZaww2FRaACEhEB+R6P9N1CRuRW+mHP1vKOqc/0=" + }, + "voting_power": "10099", + "proposer_priority": "10099" + }, + { + "address": "E1F1D0F31F8DB86B829C8502AD1F6F1576C08A6D", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "4TpozS4FflJmfBg3MYhLw12UeVUSELod0fdnX4tAQgs=" + }, + "voting_power": "10099", + "proposer_priority": "10099" + }, + { + "address": "7EA692099F6AC9243306305AC28F565716FA742E", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "CVnpHUel7h9T/ABhMZeBD6gY93vA1fQAHhtSVwBJZ4E=" + }, + "voting_power": "10094", + "proposer_priority": "10094" + }, + { + "address": "CAE9614B39D1778BE2CD1762A64483560E5534B5", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "tZbAmUfwTL4+11BLl37z0TWm30T3FiX0YFb+jAP/RQ0=" + }, + "voting_power": "10068", + "proposer_priority": "10068" + }, + { + "address": "1C9D8799534B609225D4D82A44170DAF701353BC", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "veSz82g7u1EDkIy/6njEouXOn9SsUvPIdM2Lq17y/uE=" + }, + "voting_power": "10063", + "proposer_priority": "10063" + }, + { + "address": "6B52C0F9B4B0DF280F2B5D03BCA20A35C401DAD4", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "A6uzLPMTtomXe/MJedCaag1Ab6/c3+quxY0+aqsb3PY=" + }, + "voting_power": "10059", + "proposer_priority": "10059" + }, + { + "address": "65D4634E13C159BAA5614AE04AB89C7DF4B2942C", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "C4GYT5RIkZq70YG5YKQEksjrNdmf/7gfqVSVzgbjsJE=" + }, + "voting_power": "10056", + "proposer_priority": "10056" + }, + { + "address": "9B2FB5ABCB3B0289D03AF5A8577C76D9A37A32D3", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "D9iPx6VTH+xeewFFWfnI+a7dM6Y5Y9h/5S4WHro5wUQ=" + }, + "voting_power": "10056", + "proposer_priority": "10056" + }, + { + "address": "FD32C8FD6F4E01D67824BC6651F5848FD9833B60", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "G2oUHMcHFiLj80Xos7eZ79cmuckcGaVjvxJu6mo493s=" + }, + "voting_power": "10051", + "proposer_priority": "10051" + }, + { + "address": "EE60B0B33489E72FE69363A1D7F0C78626CD2D39", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "/WPPLH7f2moY5LysZFN/JTz4k7dWw9pXLM13OKAgFAs=" + }, + "voting_power": "10042", + "proposer_priority": "10042" + }, + { + "address": "435A073DEBA3A3C6A183D9CDA397B38B6AAEEAB2", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "qy+/bkSpy3ECas02SU9WTW54EASXH5LCVN59gQJCLRo=" + }, + "voting_power": "10039", + "proposer_priority": "10039" + }, + { + "address": "3AFA32AE613CCD73ACF136BC86FF4DEF87A33067", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "ub0Db6WsbwOhhJTTEcbMvXEIQzhU3PeAPtQ8thwfOy4=" + }, + "voting_power": "10020", + "proposer_priority": "10020" + }, + { + "address": "F9D6A9FA1C7090F710DD3AC5CEB0E9005C327C13", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "GF+zUO8Y2cj77V0PFYXh79w69fSBRyeU3aANKdEqAnI=" + }, + "voting_power": "10019", + "proposer_priority": "10019" + }, + { + "address": "F271741FA4B163F3204A5BC2570E74F146AA33D9", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "Y0SMVwQK9FHbFi7ykZSwah3TG56saeI0uTMXYvyb9dY=" + }, + "voting_power": "10011", + "proposer_priority": "10011" + }, + { + "address": "4520D7FA09B49EA0C0F39E6788E6EB3FD8065690", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "27PwyrHHY/ndxqNrL6SdHomL4hR3JAJ5QMdQFYRlS9I=" + }, + "voting_power": "10010", + "proposer_priority": "10010" + }, + { + "address": "DFE827625C00547FA79217CB67CF589918218C48", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "WnsbPkUFx6VaBJbCdVcxUTFrJCDTL+F62GvY4RcZlGk=" + }, + "voting_power": "10004", + "proposer_priority": "10004" + }, + { + "address": "F26493B9ECA784977CC180B87D63FFE6BAC17D7A", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "gGUWARrFV6eOXFztsDx3M0OkithkyB8dIwGcCZ09fDA=" + }, + "voting_power": "9997", + "proposer_priority": "9997" + }, + { + "address": "4267ED67A7D1BF6794AE82F8D753E2A0C3D64DC6", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "w8dRnys1OowhERYxNXutFVTmyO4OrGVnZvqp0rvjnyA=" + }, + "voting_power": "9993", + "proposer_priority": "9993" + }, + { + "address": "C1B5400696B35C32195A495D65EEFAC0384AF5CC", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "3ykhgEeQmtBkH5m41lVTsNUI6YbI1RfZQbf2N2alJ3Y=" + }, + "voting_power": "9961", + "proposer_priority": "9961" + }, + { + "address": "4DB394CEDF34FC204B77DB197D6109328976D60F", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "FFC5Gn/KC44bJbP7MsXXEU+TqcPQmr5WbTYyjSMFPU8=" + }, + "voting_power": "9540", + "proposer_priority": "9540" + }, + { + "address": "7F5741D855DEF211FD849490B7A3145E77B426D7", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "jScQj1XJP5LWrC2d2/K1rE7wQBJYKD1EUq/iSG8uA1I=" + }, + "voting_power": "9493", + "proposer_priority": "9493" + }, + { + "address": "362F53ADD7675FB953B8B3A464970DA4646C4E15", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "3FPbUrTA67ulv315kwLG7LKDYdCg116uZASh03XLe6k=" + }, + "voting_power": "9474", + "proposer_priority": "9474" + }, + { + "address": "872E62AC3C2FD1D15DCEF5EF6682D9FE9351D5DB", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "k6BfqvfCoF71+2qIPW93JDnMZCyq8Eqc6V7gH2e/gmE=" + }, + "voting_power": "9317", + "proposer_priority": "9317" + }, + { + "address": "621BC4A3D36FE764F265ADC923F61F5EA166535B", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "540IwDgI8G001UeKp/TVCmiVz4De1smsjPtX4VJFYWk=" + }, + "voting_power": "9202", + "proposer_priority": "9202" + }, + { + "address": "C2FE6292FC9E194D4CA1A7BF94EEB73AF9BFC942", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "MeCdisSprXXkpHbmMeyGahixpKGc/MqOykJ9lvM2B48=" + }, + "voting_power": "9015", + "proposer_priority": "9015" + }, + { + "address": "13E2D73B12F6A5D5EE0392D934FCCEDA180279F2", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "WI2fnwW67ArvQKJNygzaJtjfQxfHo4nRIliAMdXvDLE=" + }, + "voting_power": "9009", + "proposer_priority": "9009" + }, + { + "address": "110F48CDE021C66B9B00441D0A6B24D358608607", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "eXFJj8jJ0TwvoB1sqiDIIFy4UywE95w2YDLPaaVHxrk=" + }, + "voting_power": "8263", + "proposer_priority": "8263" + }, + { + "address": "D441D1654E5D553AA3ABFE79C1A83BD05D235481", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "jNcAWPD4QUo40mPd4gdN05SCz7J5lM2ul+HpKaXGZIk=" + }, + "voting_power": "8241", + "proposer_priority": "8241" + }, + { + "address": "E10AF7D9C4B73147556BD60F7F00D4329A6621D3", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "BM6w4poaymqrZxhVLanZVv9wYgUy14aNlU2xLsMCtlc=" + }, + "voting_power": "8090", + "proposer_priority": "8090" + }, + { + "address": "391992B82F055BFF434D33F77A9F948BD9E2589A", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "nzYiQ54mcjTNZKutjCMN2IOcrDOL9LIYz8g8TJWUPGM=" + }, + "voting_power": "8040", + "proposer_priority": "8040" + }, + { + "address": "2712C8EDD3AD2C26C172778DBBBB61A7526F6E42", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "XLHu1GTKY2fYQvuBNcXjTvLKehA6GHihyjuFwsjYtf4=" + }, + "voting_power": "8019", + "proposer_priority": "8019" + }, + { + "address": "01876159421B01400B604A934795331E8FA47B4C", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "f8IbP3iRCQcZwjRxbLFAg7zsqBFZ1nd+ZJQnba4gUdg=" + }, + "voting_power": "8013", + "proposer_priority": "8013" + }, + { + "address": "87DAF996F5A1DA31AED86F5DD561061B8FEDCC54", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "XW11O9X36REBo1s2UsCz9OvdtUACj3wuDNDYahZXZZ0=" + }, + "voting_power": "7539", + "proposer_priority": "7539" + }, + { + "address": "B6BAE3EF71F632D2413A2B885774E55BE6F80DCC", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "sMJkChpVRPjW4Q1Fu8uOaeWTiUkoY8Da6SnM9xqz7oA=" + }, + "voting_power": "7396", + "proposer_priority": "7396" + }, + { + "address": "508C89522C08EA0D8055169BB385049E7CA17713", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "3Jhy2NQuGHQJm+CG5w9eZCMqAEa9lDE9qDpEm+Q8oZY=" + }, + "voting_power": "7360", + "proposer_priority": "7360" + }, + { + "address": "78C3EA77FAAE609808CD9B370747FE91AC975975", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "Jxx3aSz4P5vVNGutYBgnqRHzFadFWZU4k+Rw3/0pgvI=" + }, + "voting_power": "7197", + "proposer_priority": "7197" + }, + { + "address": "7F7262D42CB524A4CFB6FDEEEB12E544AE646AA6", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "W957lcHW6J+Go+flDcF1ieAWceEgAAdzsFFscLqTxjk=" + }, + "voting_power": "7167", + "proposer_priority": "7167" + }, + { + "address": "E81805AE862CBCA6340C601B6B760C9EF81E9924", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "ALaMW6hL7rhphdP+40F6Un6B1WZx37F+aYb7W0X3zSs=" + }, + "voting_power": "6633", + "proposer_priority": "6633" + }, + { + "address": "982DF85B40A0A57A9E497B8EC99896514AFD2AC1", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "XiXvtiUtyK7MgaxXxLTGKjZOEn8diBeoX29tfZsgdWM=" + }, + "voting_power": "6602", + "proposer_priority": "6602" + }, + { + "address": "7EFA1652F535CB4656BF875A989108A5D1516A58", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "576sT4WYt917pvGKNWwQAx8JkqkJTQGApvm1I06yVcE=" + }, + "voting_power": "6482", + "proposer_priority": "6482" + }, + { + "address": "AFC1C10252EEA4DE4D58C79B5E0CEDFE1B563B31", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "nDxk+ZJCcu11EnARaAVL4pWqZcVw3ZiDuERZnv/STpA=" + }, + "voting_power": "6135", + "proposer_priority": "6135" + }, + { + "address": "003CE561FE12D19F3724E383AD34B09163000048", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "RwRwkuOZrgQeQE+h/oHQN1GxM/1L0O+yDIWk/znMDPE=" + }, + "voting_power": "6024", + "proposer_priority": "6024" + }, + { + "address": "D77BA150C3AF6A439A2FA633335A279A09233B88", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "D8w1PQzJE4TQf5D9tcAT1koqBl/5kEe3xJVaunmrJ20=" + }, + "voting_power": "6000", + "proposer_priority": "6000" + }, + { + "address": "455A139106AC6CBDB8B37FC122484A18D3F08C07", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "3eIOFHYma7RENPkxPinJPriZj7t8fQtjdkPv4f3h4KY=" + }, + "voting_power": "5839", + "proposer_priority": "5839" + }, + { + "address": "4BC89C831A51124E7369972522A87F40B32EA123", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "zCqGKgAvyU35q74Fk07cQYu7NEnVV62vWoznhnyEF3c=" + }, + "voting_power": "5590", + "proposer_priority": "5590" + }, + { + "address": "FE589F7693F67ABF93BE9A09F86E2A88F78D98FE", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "ZLKB7N7d4GpLkpbeY+UHxCIpTUVA0ZUsChC7lef9I1Q=" + }, + "voting_power": "5529", + "proposer_priority": "5529" + }, + { + "address": "EB34C75A2B3770CD51E44DDB3B05CA6E4EE91092", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "Bv8W8qEPSg0VHE31zUQg33MOonibOUeFrqsbRqv3MjY=" + }, + "voting_power": "5238", + "proposer_priority": "5238" + }, + { + "address": "CD10B5095AC4541972E0C0FDE35A39CF92A040DA", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "cPgsoC0NIVUAe42qmzfbrLaznvYZCh1z92Q35D0KZOc=" + }, + "voting_power": "5083", + "proposer_priority": "5083" + }, + { + "address": "FD255FBDD520E45A8FDD0759023666F1FAEB2717", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "d4bugP3aJbyT8wzjTN9F3KgevJyc0sDe0UlcwPey39A=" + }, + "voting_power": "5022", + "proposer_priority": "5022" + }, + { + "address": "7258C2395933ABD935E87892938C524479C719BA", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "5dgQvunUGMrVCEoxcfzyhFaobgLcQhzzYDxD1dXGtYY=" + }, + "voting_power": "4931", + "proposer_priority": "4931" + }, + { + "address": "84E6AD7091614E72C39B6535E6202CDB21B80B75", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "4cH1l1egPZMt1zwy74++mxsgOosswUTcV15++xdkb6g=" + }, + "voting_power": "4616", + "proposer_priority": "4616" + }, + { + "address": "FAE6061472E8D5D9F334D84F616C9EF7AFDD7791", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "XzN7zj5Z3CVtfxgae1Xy4iGUpMB8xebR467TVfulfzM=" + }, + "voting_power": "4237", + "proposer_priority": "4237" + }, + { + "address": "19DF075073BF8F05041672EE46FE8CC8D4D76E7B", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "S2viPopSwW43/wJSp3npRR69Ct86quYn8s8mV75anvo=" + }, + "voting_power": "4168", + "proposer_priority": "4168" + }, + { + "address": "A156D613D6B5A5552FBCE6E1FDD4F2DE440C8EDE", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "D5XC1wIyYlxDM5aaTght0t2893hDe4xTzwEnU5QBo5w=" + }, + "voting_power": "4011", + "proposer_priority": "4011" + }, + { + "address": "843B76EBB527F82BB7A31B553745BD2675DB9FFE", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "qEOZMGp7fJ5pBa10fZfv5770XkJCBwhZwqGftFKeRdo=" + }, + "voting_power": "3140", + "proposer_priority": "3140" + } + ], + "proposer": { + "address": "762CBA617226A799D898F134DD12661C7F1129EB", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "6bdjjKHELaN9colwYy/ad+xh3MUgOVq106ZFucK46LE=" + }, + "voting_power": "21002592", + "proposer_priority": "-180122426" + } + }, + "header": { + "version": { + "block": "11" + }, + "chain_id": "mocha", + "height": "428545", + "time": "2023-03-11T15:43:19.088215294Z", + "last_block_id": { + "hash": "8FAB396B01B0781B309D2EB438F41FA6A76AA28308AF2FB84D200C756AB48975", + "parts": { + "total": 1, + "hash": "76A87FAAA0D8AF60A6D3DD8DE57FED54E9068B633D11A089ADC38D3C18922741" + } + }, + "last_commit_hash": "4FC44DDEF86A36A3AA544F7A913E2F1675A27CEF312E0034747A02D4A560251A", + "data_hash": "C6FA94EA5B4640A69C830C6A1BB6B86F04800B852F8650B28CDD5CE7E3A307DD", + "validators_hash": "FA8B443035B476A1D6B704C36CF1460D229D5927BCFD93197E680B2EB63F4568", + "next_validators_hash": "FA8B443035B476A1D6B704C36CF1460D229D5927BCFD93197E680B2EB63F4568", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "app_hash": "6B4205AE7CEE329C7E49E8C4A102D7B8107CB604AFAA0EE87CFAC1704E8D6461", + "last_results_hash": "EF4931FB9F6CCCA0C5FE8367BCF5044E785247ADDE925C6FE6B7C200E43EEFA5", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "proposer_address": "E1570712868BE0B12622BBAE08D96F5840F9D018" + }, + "commit": { + "height": "428545", + "round": 0, + "block_id": { + "hash": "32381A0B7262F15F081ACEF769EE59E6BB4C42C1013A3EEE23967FBF32B86AE6", + "parts": { + "total": 1, + "hash": "9CDA9660AB08F3DF418A00E7C26B80C7B10D0D8373DA0FAC079E07822404AA64" + } + }, + "signatures": [ + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "F5BB6F48121E1C99D26BCD27B8F00893C1DCADCF", + "timestamp": "2023-03-11T15:43:28.180810651Z", + "signature": "nWCjsA6fce/udBn+NhxuDFSNQEF8TBC0INjtCmaKib3ubgPDJPMU3RCccFnEu0c9RP+pzpE211BcPT/5tloVDw==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "BA8A15ED6466EBE3B132D91CD86F98867B28B006", + "timestamp": "2023-03-11T15:43:28.166418838Z", + "signature": "mKQmIV/y41YAlDToPkfr4bMtCnug3QLQjWSnNW0XjgSVjEUThP6yS3o5B71g2nyJ4CKcTGo0xj773YckxZWXCg==" + }, + { + "block_id_flag": 2, + "validator_address": "2F192A85E9117A3C166584F8AB20B315D8788C5E", + "timestamp": "2023-03-11T15:43:28.159821271Z", + "signature": "Zn7Qb8m5TRE1HyzmLl2pxpwPo/oE73N2A5MCvtPM0N28udvX5Cg6w507zx12wGmLgCjY3PA37v7vgL+c2CYQAQ==" + }, + { + "block_id_flag": 2, + "validator_address": "8FBEF0DBAAE51D918F9ABFD96653F4932171870E", + "timestamp": "2023-03-11T15:43:28.116803321Z", + "signature": "ObzC3chz1Ive1NKot4ObuF3678U4pSsHhWHeYdbArW6xwt1ed5y0ZYAYCjXmO/HAWG53i9N5BShe3WrR/F5UCg==" + }, + { + "block_id_flag": 2, + "validator_address": "F14BA4525613719E6E8DD72BB40628B585D5CA53", + "timestamp": "2023-03-11T15:43:28.110211047Z", + "signature": "JOuPaoMU0/ab4vx6IeZ/hfNQeD/8TbTI1ar60abs1XEynX3z6rHA0az/j8V6pFtXdzFNj6sDkvBexXI/RHFzCg==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "0B76107110A486E8767FA1997EA0C4B40B7851AF", + "timestamp": "2023-03-11T15:43:28.18262002Z", + "signature": "ZvEydFwPzG4j0wFw/yqprZYKxO281GiZZvE6h5QZ9TyJ0bikOkvtTGDgOfro/11RQguCChlk0pUH1nreEiXFCA==" + }, + { + "block_id_flag": 2, + "validator_address": "3ACD2DA41FFBB07743A99A74A0FACEACF3A9E474", + "timestamp": "2023-03-11T15:43:28.191434275Z", + "signature": "DtoPOkMC9IoCE1ClAHuoPPOB7ebQo49aAgS3SiHNZFHBxj8GzTHhzfifH5oo26fORF3hf92coIP1Ls+wd/00Dg==" + }, + { + "block_id_flag": 2, + "validator_address": "10C13814B94303B35EFFFAB319301714A4D69399", + "timestamp": "2023-03-11T15:43:28.082386636Z", + "signature": "11zo5OsAXtkNGrVTv3M4FX/hFr/CN1+azqPxYWkBittjMctIxmPHIujqxBjdsGv4e6SY+OGxlkSAsiaqHSuuBw==" + }, + { + "block_id_flag": 2, + "validator_address": "6BDDFED21432C64D5F71E325CD6AF6FB16790391", + "timestamp": "2023-03-11T15:43:28.797197235Z", + "signature": "N0somrqRykjuNofRVcMU7FUBziSwjdkm9iG6SsOnmUKy+dPTAfZdH2DMteNGpuSb1HV+/CtKDKUVo8G2Iq6FBQ==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "41FE068E3E8537EB35932A517836C1694C804746", + "timestamp": "2023-03-11T15:43:28.197002267Z", + "signature": "AtTZZyheuxt0qDD3OIOlFdET0qHZ/oI2xQRgYSAfSD2JJj7rmF92hZkQsimigbtADL1HSez2FpFz1FhXZaqNDQ==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "7C9538967D87E25FAD17A1180EEB6F174E8BAD84", + "timestamp": "2023-03-11T15:43:28.184183273Z", + "signature": "/+h7w6+wqAA/RnIV83jzlP02O14G1meD4Yne75eHbyQA7NoH7wqGpqZybELkroZC8lwBt82uPHsSmiCDRQb/DA==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "0590EF6F6AB31A98C786B2D4B639C62CB39F954B", + "timestamp": "2023-03-11T15:43:28.187945292Z", + "signature": "159pGRUzMiNthepaM7A2Iv05J8Ge7sRaoc3NqcRv0s0wolq/u86LOGLv2OmjyZz3Cc4Ym97qMI0iu8KtUCppAA==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "7763A9F623F458DF0FEB7298E3FE1D67CECDA1FD", + "timestamp": "2023-03-11T15:43:28.172179653Z", + "signature": "KXWBW4M5ksRDlfcTi9FdOD82iw6CH7/rCjunvEyDlEBP703kFFoD4ctXht+Fym1HdgIiaZH09TadvkpKCXUeAQ==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "38A9BFEBAD0FA8A5E9E5AFB1A0AE01C1EA85729C", + "timestamp": "2023-03-11T15:43:28.154111321Z", + "signature": "tBpuE1BtK3HjacyLVtUt9U2mN61AcIQGEmMNktaeXIZQiYWMuelSMU8VcIR1pqgzZSPqQU6zHQgN4Xm5yle1BA==" + }, + { + "block_id_flag": 2, + "validator_address": "87697AD05E817F183CBAC23D6F711EFFC73E7CB1", + "timestamp": "2023-03-11T15:43:28.111707597Z", + "signature": "qvsWM5V9ukiIv7AJXEZ5bsITlmU21x+LGVq3ewX+tqHK+uSKChVrMZK8qn3Lu2n4NUE5zGk9ppCbrwskK+CxCg==" + }, + { + "block_id_flag": 2, + "validator_address": "FD17755AE1B0FE464B4F9996598EF9A51F602DB3", + "timestamp": "2023-03-11T15:43:28.171876321Z", + "signature": "74FIf3xxDBMOHLQWILZ6PyyIWRh62v/T30T2ZuPkOrvPLVhptq/K8ddXe2z3/4WNCqBLI+EDQprI5O0ZzhY7Bw==" + }, + { + "block_id_flag": 2, + "validator_address": "813D78C65701B7A792FB5F2DB7D4DBDEFCD7EE66", + "timestamp": "2023-03-11T15:43:28.12952191Z", + "signature": "CVLnhHgWeUyCk+qaJM/2+g+nhwT//6PtMooSP7L/OExSnbWaWzKAYwKuq/kS8CxDIAnCklzQjha+cd+zEAIGCA==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "372FF124AF7D42DCE4FF40952E3E21D43C33C60D", + "timestamp": "2023-03-11T15:43:28.184599672Z", + "signature": "nDuFMIdBd57TUl80KVtdPpP9ZFtWfCwm2scfpEm2LHk37OnquYWjyoWzNDK55zKd1g2DONjGxaRRbbUEvxygDQ==" + }, + { + "block_id_flag": 2, + "validator_address": "38CECDD91DAE3D8F536C080742A69FEBB6EFDBFF", + "timestamp": "2023-03-11T15:43:28.102479327Z", + "signature": "Ve+nNvgiYH14ULfORC9wA0uLEAGxIKH1RPOSrzREw4Lg4ddFS25u3fpuWytU6p4c7ia4mgT2qCTc1vEvKsVRAw==" + }, + { + "block_id_flag": 2, + "validator_address": "21AECD90BAD73E77875F641299469C2A348D79CB", + "timestamp": "2023-03-11T15:43:28.15950634Z", + "signature": "+GdAN+eKIkh2jH9RwPrij9QMUDInPyv335Yj3gWKJFe3fPzsPuQ3h1I1uvQE+OGwh56Ll9Y516qZIlM7X+hSCg==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "312ED92F9E7A65BC80DFDB59AB05BD85754E7E95", + "timestamp": "2023-03-11T15:43:28.102779303Z", + "signature": "0R2w+uwVsBpcVHCLs43VoXf3w2PW9N7/JcIdCH6NIRV9np3cPRSyRFY6eLPnhahPNRW4NahFeiy4sZ4bDzzAAw==" + }, + { + "block_id_flag": 2, + "validator_address": "68D747F35AE07631AF2E94CFF06BA30A9EFC8712", + "timestamp": "2023-03-11T15:43:28.140514568Z", + "signature": "I6pJWs2LxzI7e6sCa2iucMhaKdle/Aey7uIR7k7kF/5XbJUwKzfuuAARZnQtp90pUh5YEvbMWeYrPE3ELg0rBw==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "B5698E7725F2D206A6652D945F75E9FDA2219F9D", + "timestamp": "2023-03-11T15:43:28.091291962Z", + "signature": "p6Zch1EezvNoBKqxOhNL8cDq4ZQd5SCTdQUAgu4AfZdtm6CfXepYKCdOlxZ5csBD4mJYjn4+gVt6U0c9cyDADQ==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "407DF17CD5EB1967597FC14A15A9D883DE884C93", + "timestamp": "2023-03-11T15:43:28.122551515Z", + "signature": "+NauxoI5IcY5Jp51ve04pailWNhadZdPUkmXA49QW26KsO1LH12gMg3KVyKtng2fINFbdFIi+kMfFYgR6duRCw==" + }, + { + "block_id_flag": 2, + "validator_address": "EE927F115AD4FD4BC131CA311D332ADDAC62CCAC", + "timestamp": "2023-03-11T15:43:28.128870097Z", + "signature": "AdUGKiCKKM4hIVUKwG4YIbDddZg4qMSpQHHedhevlRVia3e3Veot6Rm2K3HNTD0vduqZIEnnLlv0nB5eQnpFAw==" + }, + { + "block_id_flag": 2, + "validator_address": "A133A0F5CF118D107DC6326322460783F380C0E5", + "timestamp": "2023-03-11T15:43:28.125689429Z", + "signature": "DYE8EzkbBbLHpG58WQn9i4+3qgD3IOalZLM7F5UyMn2ruotswhlsoNdpIGG7Uh9MvQ6WGPWBbPsElzHJD7FXAg==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "CAE9614B39D1778BE2CD1762A64483560E5534B5", + "timestamp": "2023-03-11T15:43:28.133336889Z", + "signature": "Ui4VoxJg4p2/Qvqg5ntUhw8ijGIskrelG42Q2Cw2uy4KWofuWMi5muFzsg+vBRUp+HN1Lm0jh9C0a5rOfyG9CQ==" + }, + { + "block_id_flag": 2, + "validator_address": "1C9D8799534B609225D4D82A44170DAF701353BC", + "timestamp": "2023-03-11T15:43:28.145620704Z", + "signature": "2HMa6MJDd5LEOvJ4xlHzFlqObwFcLIyXZp7zAabsrhQvrbt5O5NV6iOfEySXnz9yK+vWeEyHoPjVzB58NAbuBw==" + }, + { + "block_id_flag": 2, + "validator_address": "6B52C0F9B4B0DF280F2B5D03BCA20A35C401DAD4", + "timestamp": "2023-03-11T15:43:28.134630891Z", + "signature": "qR/s2VoNl+sh30C+zX9Caf5uRztCSEnVY90Lxz+PbHQRJptddo7+j/GnNgcTfb2p0w6RzzbXDecuYPY48iKvCg==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "9B2FB5ABCB3B0289D03AF5A8577C76D9A37A32D3", + "timestamp": "2023-03-11T15:43:28.161802909Z", + "signature": "uG+3qzkV8qfFsjCZ486wFjN02sQqhlYU3I9ToNqqywKVxLg0Xs8t6mLEVrn8lDhZPjBNVkQntr1206W8SouhBA==" + }, + { + "block_id_flag": 2, + "validator_address": "FD32C8FD6F4E01D67824BC6651F5848FD9833B60", + "timestamp": "2023-03-11T15:43:28.114619598Z", + "signature": "i7EI8cWaYmViBjR7d4BcQYAMECg1x6G+mzmC7PnvShFndQtgPiamMO5xDn3J+XI2p5vk0topje70NUSbAltuDg==" + }, + { + "block_id_flag": 2, + "validator_address": "EE60B0B33489E72FE69363A1D7F0C78626CD2D39", + "timestamp": "2023-03-11T15:43:28.169993508Z", + "signature": "zIAeotO89zC+MWqB53YvLGw+NrgXnJCgStoiQzH6ztmEgzkp50s9uxIy1XrFNRWqhoVwHrhu1wIExHEv26bZAQ==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "F9D6A9FA1C7090F710DD3AC5CEB0E9005C327C13", + "timestamp": "2023-03-11T15:43:28.121051699Z", + "signature": "W0PHa1m6PeHgnutNB8Bb61Py6lYgN90sa5oobOFcMgB4U4mvTA1DacspyNpF/qiELsE8IEELgNMFXzyBLV15Dw==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "DFE827625C00547FA79217CB67CF589918218C48", + "timestamp": "2023-03-11T15:43:28.143278939Z", + "signature": "g8TuSiSquR9j5xADm/B9FdDx0LIGd0djgl9kWxeDvRQ2MFhZbzLy+TiY6MJVMcM4OI0X9bl6B+LG1ZgwX5MoCA==" + }, + { + "block_id_flag": 2, + "validator_address": "F26493B9ECA784977CC180B87D63FFE6BAC17D7A", + "timestamp": "2023-03-11T15:43:28.122476314Z", + "signature": "tcOfmQnS8VG/S8LHhwE4RkKqGdMJZL2HgqEUyJPJ8nPIqni6iJ8Cw/VwmuQ6MZZKoJbynmwuulUXpB2nh9ElBA==" + }, + { + "block_id_flag": 2, + "validator_address": "4267ED67A7D1BF6794AE82F8D753E2A0C3D64DC6", + "timestamp": "2023-03-11T15:43:28.174180977Z", + "signature": "wLSFI5fnXdAyD/4ETtaIW65gtotj7X7nhbyadiRYqjKaLDTelgVHLhEcewC5y3U+uE5mlpS98QTVjqsYA2F3Ag==" + }, + { + "block_id_flag": 2, + "validator_address": "C1B5400696B35C32195A495D65EEFAC0384AF5CC", + "timestamp": "2023-03-11T15:43:28.175152676Z", + "signature": "rMdkgjnbsNUucD4EleHmOX0b1yJjizQxwZW6LguBJusA2guwP+Gt290OkEA3BRoKhwkkEgUiRCawHWBSuB3jAg==" + }, + { + "block_id_flag": 2, + "validator_address": "4DB394CEDF34FC204B77DB197D6109328976D60F", + "timestamp": "2023-03-11T15:43:28.149473816Z", + "signature": "xL3qkwlIxqLwDAAbjJ6nsxSnOqmblbACi2F/sP6Mu0N9dCR1YqXL/NBWTjuIHYOGqouqsRz4gPgAat4wxyILCg==" + }, + { + "block_id_flag": 2, + "validator_address": "7F5741D855DEF211FD849490B7A3145E77B426D7", + "timestamp": "2023-03-11T15:43:28.174092385Z", + "signature": "T6xLvnkyLx44vrsAv6u3I7OW7XpWDj5VL6fsLYzUSwr+LuUl+nqijP5aZ5eMMJNhK0Fa2+aY1ewl2Tz999FeCA==" + }, + { + "block_id_flag": 2, + "validator_address": "362F53ADD7675FB953B8B3A464970DA4646C4E15", + "timestamp": "2023-03-11T15:43:28.186962924Z", + "signature": "XE1guOo/Y4Rw3WhPaOxEmrg9nXeMVt4VqmZwdDQOWjLNw4481w+kupM2yNeaX19dEtkKBXXHfAZlLL1l+CZfCQ==" + }, + { + "block_id_flag": 2, + "validator_address": "872E62AC3C2FD1D15DCEF5EF6682D9FE9351D5DB", + "timestamp": "2023-03-11T15:43:28.151013058Z", + "signature": "OrHdcGzn36iTYwht9l0FOfITaUNhlPmzP2YDvFpDmspoLmL+o+rAn7XHJkzgEjFgEZGRR3b8EKhnzVYfVRlyAQ==" + }, + { + "block_id_flag": 2, + "validator_address": "621BC4A3D36FE764F265ADC923F61F5EA166535B", + "timestamp": "2023-03-11T15:43:28.085265928Z", + "signature": "W6QbJZm1boSBjcYkEeI9flOnlDNdvYEXzfYP9rLZVT4/g7ccpa0V6rpFMXazzbqKduAbzEE6t/Flj4/SvdILAg==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "110F48CDE021C66B9B00441D0A6B24D358608607", + "timestamp": "2023-03-11T15:43:28.104358197Z", + "signature": "KYcf3YtU5WrNMjgMBsn+szYgOtQeygpXWkIR07+11wJgdX2+sNDBgfI5iXHfJTBI4LxMC0y33HGOyOGZHknSCg==" + }, + { + "block_id_flag": 2, + "validator_address": "D441D1654E5D553AA3ABFE79C1A83BD05D235481", + "timestamp": "2023-03-11T15:43:28.06374813Z", + "signature": "ctCt8z/GIQq7AaCiMW8CnYZikpfj4RWgePYK0rvgv5VeheFlr51V9DSDSVSOe+VTrJ/xrHGFKef2gFbYqqNNBA==" + }, + { + "block_id_flag": 2, + "validator_address": "E10AF7D9C4B73147556BD60F7F00D4329A6621D3", + "timestamp": "2023-03-11T15:43:28.203523322Z", + "signature": "Khn2Mtb6EWykAwPJcHuPv/dAjWYx/c24eGev99JP/GO6hTCkRTYdPIZZDqY5/URVkx8FAVwm/mYr9QpNH2zNAg==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "E81805AE862CBCA6340C601B6B760C9EF81E9924", + "timestamp": "2023-03-11T15:43:28.210441238Z", + "signature": "nnbtOvu1aVCNrwFyUwxL5zW9RvPA58yE+iAvIlK+Ye4oyfttj6ZmEKYc28yIoZeaj5QV6GvcK56rMY2ss4c/DQ==" + }, + { + "block_id_flag": 2, + "validator_address": "982DF85B40A0A57A9E497B8EC99896514AFD2AC1", + "timestamp": "2023-03-11T15:43:28.157904077Z", + "signature": "cks6RYIFjuAa8MhoQ6pPM60GQnuF+Xs4LfLRlFPdmoUKDieAqXVqg2NQIl0rP1vZ0TUOBvQoBy3xRap8DZQsCg==" + }, + { + "block_id_flag": 2, + "validator_address": "7EFA1652F535CB4656BF875A989108A5D1516A58", + "timestamp": "2023-03-11T15:43:28.155662397Z", + "signature": "VJyY2A1uVsAhZipMbEaTL2kAUoZFTcWYgB9uG0ba0R1zjluyp0TAloyojYVVpVNhDMSYyg8MLzPwUMlqGqbUBg==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "D77BA150C3AF6A439A2FA633335A279A09233B88", + "timestamp": "2023-03-11T15:43:28.159412663Z", + "signature": "Ra/rTH319KQ+bJXjs3sUbEGydUcL91HrekFLBw4H7IVDfZU8lyEaKoULVztzc3QyoqRVqKVWb4UgrtP94W0MCw==" + }, + { + "block_id_flag": 2, + "validator_address": "455A139106AC6CBDB8B37FC122484A18D3F08C07", + "timestamp": "2023-03-11T15:43:28.094776708Z", + "signature": "KhsvGtrUbabKp0QWjb3Bs1M/fSq5v9yrlSfPEAqmMMI4tBHQihLW9eqD6h+mURsPA0E0Z/3BbC/67WsNoVl1CA==" + }, + { + "block_id_flag": 2, + "validator_address": "4BC89C831A51124E7369972522A87F40B32EA123", + "timestamp": "2023-03-11T15:43:28.164019635Z", + "signature": "IrdYdBW+gM6W9pEs/VVR4FAt2VhjWqEdudgSLtd1gMFPW1sLHqvur4NBB36Wbu0kBdfXoItVwDu2S5W03wirCA==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "EB34C75A2B3770CD51E44DDB3B05CA6E4EE91092", + "timestamp": "2023-03-11T15:43:28.195390071Z", + "signature": "Go19bP0BNxVrKuvYlHh9Nv3D9rBYMlsBpjFoZng0YoZ/0RFLgXwUSKJb8pkAkWXkeMCDTRJjl7ooC4bBZvxKBg==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 2, + "validator_address": "84E6AD7091614E72C39B6535E6202CDB21B80B75", + "timestamp": "2023-03-11T15:43:28.124138509Z", + "signature": "D4q33fyR8mLi150PdejvM8OvGHgNnrKCZBTKZSLY2I7PzsCiIrH9/YwR775LovalrTAT1laxx0TKFMtq65ipBg==" + }, + { + "block_id_flag": 2, + "validator_address": "FAE6061472E8D5D9F334D84F616C9EF7AFDD7791", + "timestamp": "2023-03-11T15:43:28.108977997Z", + "signature": "c3/0C4P/upPe2u3kU53o0OLTIvIhUWveZUC26aTXb15PzmhO/sRHKFAjCjFgxdy1yy74bk+qSuSGbUS7rwuvDQ==" + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + }, + { + "block_id_flag": 1, + "validator_address": "", + "timestamp": "0001-01-01T00:00:00Z", + "signature": null + } + ] + }, + "dah": { + "row_roots": [ + "AAAAAAAAAAGpbEw4Tw+RieW43CdU+gLFx/8YYdMc49a7Kooxz3D4QwJ0QRqkfxky", + "//////////7//////////u49pdZvjLX9NygV7pZlYPtcUao36hMUtpGXKS6YNfLD", + "/////////////////////xR57uHxvfFHajjhen1YKqiYkVXZc86mB+rfzmhQzKkm", + "/////////////////////9SJm2MM6D9mhN7wqTID0ij7cUE2TycrUvZsniEXxFaQ" + ], + "column_roots": [ + "AAAAAAAAAAH//////////lDn69+UwNpzCmbc5R5ycngM6mZvYPlcPsfGxxidwOR9", + "qWxMOE8PkYn//////////hhrybvNXHGF3HvpX5bwHcA5afrU/E/XsXNrVfUtiJzw", + "/////////////////////8f5M8znb8YBW3FotHFI0KKkGhttXscg5y7sez/r6u1d", + "/////////////////////wrtjZVtTDxn4TBn2wxTwWa1oMjhuHRFA4OxzrV5qcXA" + ] + } +} diff --git a/src/shares.rs b/src/shares.rs index 40bb123..7046415 100644 --- a/src/shares.rs +++ b/src/shares.rs @@ -8,7 +8,7 @@ use prost::{ encoding::decode_varint, DecodeError, }; -use serde::{de::Error, Deserialize}; +use serde::{de::Error, Deserialize, Serialize}; use sovereign_sdk::{ core::crypto::hash::{sha2, Sha2Hash}, Bytes, @@ -173,7 +173,7 @@ impl Share { match self { Share::Continuation(_) => { let reserved_bytes_offset = NAMESPACE_ID_LEN + INFO_BYTE_LEN; - let mut raw = self.raw_inner().clone(); + let mut raw = self.raw_inner(); raw.advance(reserved_bytes_offset); let idx_of_next_start = raw.get_u32() as usize; if idx_of_next_start == 0 { @@ -182,7 +182,7 @@ impl Share { Some(idx_of_next_start - self.get_data_offset()) } } - // Start shares always have a sequence begining at the first byte + // Start shares always have a sequence beginning at the first byte Share::Start(_) => Some(0), } } @@ -294,7 +294,7 @@ impl NamespaceGroup { } pub fn from_b64_shares(encoded_shares: &Vec) -> Result { - if encoded_shares.len() == 0 { + if encoded_shares.is_empty() { return Ok(Self::Sparse(vec![])); } let mut shares = Vec::with_capacity(encoded_shares.len()); @@ -343,7 +343,7 @@ impl NamespaceGroup { } } } -#[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] pub struct Blob(pub Vec); impl<'a> From> for Blob { diff --git a/src/types.rs b/src/types.rs index cdbc0e0..ff17996 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,13 +3,11 @@ use std::collections::HashMap; use anyhow::ensure; use borsh::{BorshDeserialize, BorshSerialize}; use serde::{Deserialize, Serialize}; -use sovereign_sdk::{ - serial::{Decode, DecodeBorrowed, Encode}, - services::da::SlotData, - Bytes, -}; +use sovereign_sdk::{services::da::SlotData, Bytes}; use tendermint::{crypto::default::Sha256, merkle}; +pub use nmt_rs::NamespaceId; + use crate::{ pfb::MsgPayForBlobs, shares::{NamespaceGroup, Share}, @@ -17,7 +15,8 @@ use crate::{ verifier::PARITY_SHARES_NAMESPACE, CelestiaHeader, TxPosition, }; -#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] pub struct RpcNamespacedShares { #[serde(rename = "Proof")] pub proof: JsonNamespaceProof, @@ -25,7 +24,7 @@ pub struct RpcNamespacedShares { pub shares: Vec, } -#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] pub struct JsonNamespaceProof { #[serde(rename = "Start")] start: usize, @@ -35,7 +34,7 @@ pub struct JsonNamespaceProof { nodes: Option>, } -#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] pub struct ExtendedDataSquare { pub data_square: Vec, pub codec: String, @@ -66,7 +65,7 @@ impl ExtendedDataSquare { } } -#[derive(Debug, Clone, PartialEq, Deserialize, serde::Serialize)] +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct FilteredCelestiaBlock { pub header: CelestiaHeader, pub rollup_data: NamespaceGroup, @@ -79,28 +78,6 @@ pub struct FilteredCelestiaBlock { pub pfb_rows: Vec, } -impl Encode for FilteredCelestiaBlock { - fn encode(&self, target: &mut impl std::io::Write) { - serde_cbor::ser::to_writer(target, self).expect("serializing to writer should not fail"); - } -} - -impl Decode for FilteredCelestiaBlock { - type Error = anyhow::Error; - - fn decode(target: &mut R) -> Result::Error> { - Ok(serde_cbor::de::from_reader(target)?) - } -} - -impl<'de> DecodeBorrowed<'de> for FilteredCelestiaBlock { - type Error = anyhow::Error; - - fn decode_from_slice(target: &'de [u8]) -> Result { - Ok(serde_cbor::de::from_slice(target)?) - } -} - impl SlotData for FilteredCelestiaBlock { fn hash(&self) -> [u8; 32] { match self.header.header.hash() { @@ -109,6 +86,7 @@ impl SlotData for FilteredCelestiaBlock { } } } + impl FilteredCelestiaBlock { pub fn square_size(&self) -> usize { self.header.square_size() @@ -158,9 +136,7 @@ impl CelestiaHeader { } } -#[derive( - Debug, Clone, PartialEq, serde::Serialize, Deserialize, BorshDeserialize, BorshSerialize, -)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] pub struct Row { pub shares: Vec, pub root: NamespacedHash, @@ -226,18 +202,16 @@ fn ns_hash_from_b64(input: &str) -> NamespacedHash { #[cfg(test)] mod tests { - use nmt_rs::{NamespaceProof, NamespacedSha2Hasher}; - - use crate::verifier::ROLLUP_NAMESPACE; + // use nmt_rs::{NamespaceProof, NamespacedSha2Hasher}; - use super::{ns_hash_from_b64, RpcNamespacedSharesResponse}; + // use super::{ns_hash_from_b64, RpcNamespacedSharesResponse}; - const ROW_ROOTS: &[&'static str] = &[ - "AAAAAAAAAAEAAAAAAAAAAT4A1HvHQCYkf1sQ7zmTJH11jd1Hxn+YCcC9mIGbl1WJ", - "c292LXRlc3T//////////vSMLQPlgfwCOf4QTkOhMnQxk6ra3lI+ybCMfUyanYSd", - "/////////////////////wp55V2JEu8z3LhdNIIqxbq6uvpyGSGu7prq67ajVVAt", - "/////////////////////7gaLStbqIBiy2pxi1D68MFUpq6sVxWBB4zdQHWHP/Tl", - ]; + // const ROW_ROOTS: &[&'static str] = &[ + // "AAAAAAAAAAEAAAAAAAAAAT4A1HvHQCYkf1sQ7zmTJH11jd1Hxn+YCcC9mIGbl1WJ", + // "c292LXRlc3T//////////vSMLQPlgfwCOf4QTkOhMnQxk6ra3lI+ybCMfUyanYSd", + // "/////////////////////wp55V2JEu8z3LhdNIIqxbq6uvpyGSGu7prq67ajVVAt", + // "/////////////////////7gaLStbqIBiy2pxi1D68MFUpq6sVxWBB4zdQHWHP/Tl", + // ]; // TODO: Re-enable this test after Celestia releases an endpoint which returns nmt proofs instead of // ipld.Proofs diff --git a/src/verifier/address.rs b/src/verifier/address.rs index ab87ec0..ff2def2 100644 --- a/src/verifier/address.rs +++ b/src/verifier/address.rs @@ -1,7 +1,9 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use sovereign_sdk::core::traits::AddressTrait as Address; +use serde::{Deserialize, Serialize}; +use sovereign_sdk::core::traits::AddressTrait; +use std::fmt::{Display, Formatter}; -#[derive(Debug, PartialEq, Clone, Eq, BorshDeserialize, BorshSerialize)] +#[derive(Debug, PartialEq, Clone, Eq, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] pub struct CelestiaAddress(pub Vec); impl AsRef<[u8]> for CelestiaAddress { @@ -9,7 +11,6 @@ impl AsRef<[u8]> for CelestiaAddress { self.0.as_ref() } } -impl Address for CelestiaAddress {} impl<'a> TryFrom<&'a [u8]> for CelestiaAddress { type Error = anyhow::Error; @@ -18,3 +19,17 @@ impl<'a> TryFrom<&'a [u8]> for CelestiaAddress { Ok(Self(value.to_vec())) } } + +impl From<[u8; 32]> for CelestiaAddress { + fn from(value: [u8; 32]) -> Self { + Self(value.to_vec()) + } +} + +impl Display for CelestiaAddress { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "0x{}", hex::encode(&self.0)) + } +} + +impl AddressTrait for CelestiaAddress {} diff --git a/src/verifier/mod.rs b/src/verifier/mod.rs index bbe08b4..1a5c79b 100644 --- a/src/verifier/mod.rs +++ b/src/verifier/mod.rs @@ -1,8 +1,7 @@ use nmt_rs::NamespaceId; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use sovereign_sdk::{ da::{self, BlobTransactionTrait, BlockHashTrait as BlockHash, DaSpec}, - serial::{Decode, DecodeBorrowed, DeserializationError, Encode}, Bytes, }; @@ -20,14 +19,16 @@ use proofs::*; use self::address::CelestiaAddress; -pub struct CelestiaVerifier; +pub struct CelestiaVerifier { + pub rollup_namespace: NamespaceId, +} -pub const ROLLUP_NAMESPACE: NamespaceId = NamespaceId([115, 111, 118, 45, 116, 101, 115, 116]); pub const PFB_NAMESPACE: NamespaceId = NamespaceId(hex_literal::hex!("0000000000000004")); pub const PARITY_SHARES_NAMESPACE: NamespaceId = NamespaceId(hex_literal::hex!("ffffffffffffffff")); -impl BlobTransactionTrait for BlobWithSender { +impl BlobTransactionTrait for BlobWithSender { type Data = BlobIterator; + type Address = CelestiaAddress; fn sender(&self) -> CelestiaAddress { self.sender.clone() } @@ -36,8 +37,11 @@ impl BlobTransactionTrait for BlobWithSender { self.blob.clone().into_iter() } } -#[derive(Debug, PartialEq, Clone, Eq, Hash, serde::Serialize, Deserialize)] +#[derive(Debug, PartialEq, Clone, Eq, Hash, Serialize, Deserialize)] +// Important: #[repr(transparent)] is required for safety as long as we're using +// std::mem::transmute to implement AsRef for tendermint::Hash +#[repr(transparent)] pub struct TmHash(pub tendermint::Hash); impl AsRef<[u8]> for TmHash { @@ -57,54 +61,20 @@ impl TmHash { impl AsRef for tendermint::Hash { fn as_ref(&self) -> &TmHash { + // Safety: #[repr(transparent)] guarantees that the memory layout of TmHash is + // the same as tendermint::Hash, so this `transmute` is sound. + // See https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent unsafe { std::mem::transmute(self) } } } impl BlockHash for TmHash {} -impl Decode for TmHash { - type Error = sovereign_sdk::serial::DeserializationError; - - fn decode(target: &mut R) -> Result::Error> { - // TODO: make this reasonable - let mut out = [0u8; 32]; - target - .read_exact(&mut out) - .map_err(|_| DeserializationError::DataTooShort { - expected: 32, - got: 1, - })?; - Ok(TmHash(tendermint::Hash::Sha256(out))) - } -} - -impl<'de> DecodeBorrowed<'de> for TmHash { - type Error = sovereign_sdk::serial::DeserializationError; - - fn decode_from_slice(target: &'de [u8]) -> Result { - let mut out = [0u8; 32]; - out.copy_from_slice(&target[..32]); - Ok(TmHash(tendermint::Hash::Sha256(out))) - } -} - -impl Encode for TmHash { - fn encode(&self, target: &mut impl std::io::Write) { - // TODO: make this reasonable - target - .write_all(self.as_ref()) - .expect("Serialization should not fail") - } -} - pub struct CelestiaSpec; impl DaSpec for CelestiaSpec { type SlotHash = TmHash; - type Address = CelestiaAddress; - type BlockHeader = CelestiaHeader; type BlobTransaction = BlobWithSender; @@ -112,6 +82,13 @@ impl DaSpec for CelestiaSpec { type InclusionMultiProof = Vec; type CompletenessProof = Vec; + + type ChainParams = RollupParams; +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct RollupParams { + pub namespace: NamespaceId, } impl da::DaVerifier for CelestiaVerifier { @@ -119,6 +96,12 @@ impl da::DaVerifier for CelestiaVerifier { type Error = ValidationError; + fn new(params: ::ChainParams) -> Self { + Self { + rollup_namespace: params.namespace, + } + } + fn verify_relevant_tx_list( &self, block_header: &::BlockHeader, @@ -131,7 +114,7 @@ impl da::DaVerifier for CelestiaVerifier { // Check the validity and completeness of the rollup row proofs, against the DAH. // Extract the data from the row proofs and build a namespace_group from it - let rollup_shares_u8 = Self::verify_row_proofs(completeness_proof, &block_header.dah)?; + let rollup_shares_u8 = self.verify_row_proofs(completeness_proof, &block_header.dah)?; if rollup_shares_u8.is_empty() { if txs.is_empty() { return Ok(()); @@ -198,7 +181,7 @@ impl da::DaVerifier for CelestiaVerifier { // Verify the sender and data of each blob which was sent into this namespace for (blob_idx, nid) in pfb.namespace_ids.iter().enumerate() { - if nid != &ROLLUP_NAMESPACE.0[..] { + if nid != &self.rollup_namespace.0[..] { continue; } let tx = tx_iter.next().ok_or(ValidationError::MissingTx)?; @@ -227,6 +210,7 @@ impl da::DaVerifier for CelestiaVerifier { impl CelestiaVerifier { pub fn verify_row_proofs( + &self, row_proofs: Vec, dah: &DataAvailabilityHeader, ) -> Result>, ValidationError> { @@ -235,11 +219,11 @@ impl CelestiaVerifier { let mut rollup_shares_u8: Vec> = Vec::new(); for row_root in dah.row_roots.iter() { // TODO: short circuit this loop at the first row after the rollup namespace - if row_root.contains(ROLLUP_NAMESPACE) { + if row_root.contains(self.rollup_namespace) { let row_proof = row_proofs.next().ok_or(ValidationError::InvalidRowProof)?; row_proof .proof - .verify_complete_namespace(row_root, &row_proof.leaves, ROLLUP_NAMESPACE) + .verify_complete_namespace(row_root, &row_proof.leaves, self.rollup_namespace) .expect("Proofs must be valid"); for leaf in row_proof.leaves { diff --git a/src/verifier/proofs.rs b/src/verifier/proofs.rs index 20f495b..87039db 100644 --- a/src/verifier/proofs.rs +++ b/src/verifier/proofs.rs @@ -1,19 +1,18 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use nmt_rs::{NamespaceProof, NamespacedSha2Hasher}; +use nmt_rs::{NamespaceId, NamespaceProof, NamespacedSha2Hasher}; +use serde::{Deserialize, Serialize}; use crate::{ share_commit::recreate_commitment, shares::BlobRef, types::FilteredCelestiaBlock, BlobWithSender, }; -use super::ROLLUP_NAMESPACE; - -#[derive(Debug, PartialEq, Clone, BorshDeserialize, BorshSerialize)] +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] pub struct EtxProof { pub proof: Vec, } -#[derive(Debug, PartialEq, Clone, BorshDeserialize, BorshSerialize)] +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] pub struct EtxRangeProof { pub shares: Vec>, pub proof: NamespaceProof, @@ -21,8 +20,7 @@ pub struct EtxRangeProof { pub start_offset: usize, } -#[derive(Debug, PartialEq, Clone, BorshDeserialize, BorshSerialize)] - +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] pub struct RelevantRowProof { pub leaves: Vec>, pub proof: NamespaceProof, @@ -32,11 +30,11 @@ pub struct RelevantRowProof { pub struct CompletenessProof(pub Vec); impl CompletenessProof { - pub fn from_filtered_block(block: &FilteredCelestiaBlock) -> Self { + pub fn from_filtered_block(block: &FilteredCelestiaBlock, namespace: NamespaceId) -> Self { let mut row_proofs = Vec::new(); for row in block.rollup_rows.iter() { let mut nmt = row.merklized(); - let (leaves, proof) = nmt.get_namespace_with_proof(ROLLUP_NAMESPACE); + let (leaves, proof) = nmt.get_namespace_with_proof(namespace); let row_proof = RelevantRowProof { leaves, proof }; row_proofs.push(row_proof) }