diff --git a/ethexe/common/src/primitives.rs b/ethexe/common/src/primitives.rs
index 070e5052d5a..a7fba6d2935 100644
--- a/ethexe/common/src/primitives.rs
+++ b/ethexe/common/src/primitives.rs
@@ -78,7 +78,7 @@ pub struct SimpleBlockData {
pub header: BlockHeader,
}
-#[cfg_attr(feature = "serde", derive(Hash))]
+#[cfg_attr(feature = "serde", derive(Hash, serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, Encode, Decode, TypeInfo, PartialEq, Eq, derive_more::Display)]
#[display(
"Announce(block: {block_hash}, parent: {parent}, gas: {gas_allowance:?}, txs: {injected_transactions:?})"
@@ -140,7 +140,7 @@ pub enum PromisePolicy {
}
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, Default, Encode, Decode, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize))]
+#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct StateHashWithQueueSize {
pub hash: H256,
pub canonical_queue_size: u8,
diff --git a/ethexe/rpc/src/apis/announce.rs b/ethexe/rpc/src/apis/announce.rs
new file mode 100644
index 00000000000..13923f55f60
--- /dev/null
+++ b/ethexe/rpc/src/apis/announce.rs
@@ -0,0 +1,89 @@
+// This file is part of Gear.
+//
+// Copyright (C) 2026 Gear Technologies Inc.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+use crate::{errors, utils};
+use ethexe_common::{Announce, ProgramStates, db::AnnounceStorageRO, gear::StateTransition};
+use ethexe_db::Database;
+use jsonrpsee::{
+ core::{RpcResult, async_trait},
+ proc_macros::rpc,
+};
+use sp_core::H256;
+
+#[cfg_attr(not(feature = "client"), rpc(server))]
+#[cfg_attr(feature = "client", rpc(server, client))]
+pub trait Announce {
+ #[method(name = "announce_by_hash")]
+ async fn announce(&self, announce_hash: Option) -> RpcResult<(H256, Announce)>;
+
+ #[method(name = "announce_outcome")]
+ async fn announce_outcome(
+ &self,
+ announce_hash: Option,
+ ) -> RpcResult>;
+
+ #[method(name = "announce_program_states")]
+ async fn announce_program_states(
+ &self,
+ announce_hash: Option,
+ ) -> RpcResult;
+}
+
+#[derive(Debug, Clone)]
+pub struct AnnounceApi {
+ db: Database,
+}
+
+impl AnnounceApi {
+ pub fn new(db: Database) -> Self {
+ Self { db }
+ }
+}
+
+#[async_trait]
+impl AnnounceServer for AnnounceApi {
+ async fn announce(&self, announce_hash: Option) -> RpcResult<(H256, Announce)> {
+ let hash = utils::announce_at_or_latest_computed(&self.db, announce_hash)?;
+ let announce = self
+ .db
+ .announce(hash)
+ .ok_or_else(|| errors::db("Announce wasn't found"))?;
+
+ Ok((hash.inner(), announce))
+ }
+
+ async fn announce_outcome(
+ &self,
+ announce_hash: Option,
+ ) -> RpcResult> {
+ let hash = utils::announce_at_or_latest_computed(&self.db, announce_hash)?;
+ self.db
+ .announce_outcome(hash)
+ .ok_or_else(|| errors::db("Announce outcome wasn't found"))
+ }
+
+ async fn announce_program_states(
+ &self,
+ announce_hash: Option,
+ ) -> RpcResult {
+ let hash = utils::announce_at_or_latest_computed(&self.db, announce_hash)?;
+ self.db
+ .announce_program_states(hash)
+ .ok_or_else(|| errors::db("Announce program states weren't found"))
+ }
+}
diff --git a/ethexe/rpc/src/apis/mod.rs b/ethexe/rpc/src/apis/mod.rs
index 8ed642f4ca1..1c4ec34bbef 100644
--- a/ethexe/rpc/src/apis/mod.rs
+++ b/ethexe/rpc/src/apis/mod.rs
@@ -16,11 +16,13 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+mod announce;
mod block;
mod code;
mod injected;
mod program;
+pub use announce::{AnnounceApi, AnnounceServer};
pub use block::{BlockApi, BlockServer};
pub use code::{CodeApi, CodeServer};
pub use injected::{InjectedApi, InjectedServer};
@@ -28,5 +30,6 @@ pub use program::{FullProgramState, ProgramApi, ProgramServer};
#[cfg(feature = "client")]
pub use crate::apis::{
- block::BlockClient, code::CodeClient, injected::InjectedClient, program::ProgramClient,
+ announce::AnnounceClient, block::BlockClient, code::CodeClient, injected::InjectedClient,
+ program::ProgramClient,
};
diff --git a/ethexe/rpc/src/lib.rs b/ethexe/rpc/src/lib.rs
index 4a142649b76..300533cd913 100644
--- a/ethexe/rpc/src/lib.rs
+++ b/ethexe/rpc/src/lib.rs
@@ -17,12 +17,14 @@
// along with this program. If not, see .
#[cfg(feature = "client")]
-pub use crate::apis::{BlockClient, CodeClient, FullProgramState, InjectedClient, ProgramClient};
+pub use crate::apis::{
+ AnnounceClient, BlockClient, CodeClient, FullProgramState, InjectedClient, ProgramClient,
+};
use anyhow::Result;
use apis::{
- BlockApi, BlockServer, CodeApi, CodeServer, InjectedApi, InjectedServer, ProgramApi,
- ProgramServer,
+ AnnounceApi, AnnounceServer, BlockApi, BlockServer, CodeApi, CodeServer, InjectedApi,
+ InjectedServer, ProgramApi, ProgramServer,
};
use ethexe_common::injected::{
AddressedInjectedTransaction, InjectedTransactionAcceptance, SignedPromise,
@@ -113,6 +115,7 @@ impl RpcServer {
let server_apis = RpcServerApis {
code: CodeApi::new(self.db.clone()),
block: BlockApi::new(self.db.clone()),
+ announce: AnnounceApi::new(self.db.clone()),
program: ProgramApi::new(self.db.clone(), processor, self.config.gas_allowance),
injected: InjectedApi::new(rpc_sender),
};
@@ -181,6 +184,7 @@ impl FusedStream for RpcService {
struct RpcServerApis {
pub block: BlockApi,
+ pub announce: AnnounceApi,
pub code: CodeApi,
pub injected: InjectedApi,
pub program: ProgramApi,
@@ -193,6 +197,9 @@ impl RpcServerApis {
module
.merge(BlockServer::into_rpc(self.block))
.expect("No conflicts");
+ module
+ .merge(AnnounceServer::into_rpc(self.announce))
+ .expect("No conflicts");
module
.merge(CodeServer::into_rpc(self.code))
.expect("No conflicts");