mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Restore publish_transaction RPC to Serai
This commit is contained in:
@@ -14,18 +14,16 @@ use borsh::BorshDeserialize;
|
||||
pub use serai_abi as abi;
|
||||
use abi::{
|
||||
primitives::{BlockHash, network_id::ExternalNetworkId},
|
||||
Block, Event,
|
||||
Transaction, Block, Event,
|
||||
};
|
||||
|
||||
use async_lock::RwLock;
|
||||
|
||||
/// RPC client functionality for the coins module.
|
||||
pub mod coins;
|
||||
use coins::*;
|
||||
mod coins;
|
||||
pub use coins::Coins;
|
||||
|
||||
/// RPC client functionality for the validator sets module.
|
||||
pub mod validator_sets;
|
||||
use validator_sets::*;
|
||||
mod validator_sets;
|
||||
pub use validator_sets::ValidatorSets;
|
||||
|
||||
/// An error from the RPC.
|
||||
#[derive(Debug, Error)]
|
||||
@@ -164,6 +162,16 @@ impl Serai {
|
||||
Self::block_internal(self.call("blockchain/block", &format!(r#"{{ "block": {block} }}"#))).await
|
||||
}
|
||||
|
||||
/// Publish a transaction onto the Serai blockchain.
|
||||
pub async fn publish_transaction(&self, transaction: &Transaction) -> Result<(), RpcError> {
|
||||
self
|
||||
.call(
|
||||
"blockchain/publish_transaction",
|
||||
&format!(r#"{{ "transaction": {} }}"#, hex::encode(borsh::to_vec(transaction).unwrap())),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Scope this RPC client to the state as of a specific block.
|
||||
///
|
||||
/// This will yield an error if the block chosen isn't finalized. This ensures, given an honest
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::{sync::Arc, ops::Deref, collections::HashSet};
|
||||
use core::{ops::Deref, future::Future};
|
||||
use std::{sync::Arc, collections::HashSet};
|
||||
|
||||
use rand_core::{RngCore, OsRng};
|
||||
|
||||
@@ -8,8 +9,9 @@ use sp_consensus::BlockStatus;
|
||||
use sp_block_builder::BlockBuilder;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sc_client_api::BlockBackend;
|
||||
use sc_transaction_pool_api::TransactionPool;
|
||||
|
||||
use serai_abi::{primitives::prelude::*, SubstrateBlock as Block};
|
||||
use serai_abi::{primitives::prelude::*, Transaction, SubstrateBlock as Block};
|
||||
|
||||
use serai_runtime::SeraiApi;
|
||||
|
||||
@@ -27,6 +29,7 @@ pub(crate) fn module<
|
||||
+ ProvideRuntimeApi<Block, Api: SeraiApi<Block>>,
|
||||
>(
|
||||
client: Arc<C>,
|
||||
pool: Arc<impl 'static + TransactionPool<Block = Block>>,
|
||||
) -> Result<RpcModule<impl 'static + Send + Sync>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut module = RpcModule::new(client);
|
||||
|
||||
@@ -80,5 +83,36 @@ pub(crate) fn module<
|
||||
)
|
||||
})?;
|
||||
|
||||
module.register_async_method("blockchain/publish_transaction", move |params, client, _ext| {
|
||||
let pool = pool.clone();
|
||||
async move {
|
||||
#[derive(sp_core::serde::Deserialize)]
|
||||
#[serde(crate = "sp_core::serde")]
|
||||
struct TransactionRequest {
|
||||
transaction: String,
|
||||
};
|
||||
let Ok(transaction) = params.parse::<TransactionRequest>() else {
|
||||
return Err(Error::InvalidRequest(r#"missing `string` "transaction" field"#));
|
||||
};
|
||||
let Ok(transaction) = hex::decode(transaction.transaction) else {
|
||||
Err(Error::InvalidRequest(r#"transaction was not hex-encoded"#))?
|
||||
};
|
||||
let Ok(transaction) =
|
||||
<Transaction as borsh::BorshDeserialize>::deserialize_reader(&mut transaction.as_slice())
|
||||
else {
|
||||
Err(Error::InvalidRequest(r#"transaction could not be deserialized"#))?
|
||||
};
|
||||
pool
|
||||
.submit_one(
|
||||
client.info().best_hash,
|
||||
sc_transaction_pool_api::TransactionSource::External,
|
||||
transaction,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| Error::InvalidTransaction(format!("{e}")))?;
|
||||
Ok(())
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
@@ -36,14 +36,14 @@ pub fn create_full<
|
||||
+ HeaderBackend<Block>
|
||||
+ HeaderMetadata<Block, Error = BlockchainError>
|
||||
+ BlockBackend<Block>,
|
||||
P: 'static + TransactionPool,
|
||||
P: 'static + TransactionPool<Block = Block>,
|
||||
>(
|
||||
deps: FullDeps<C, P>,
|
||||
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let FullDeps { id, client, pool, authority_discovery } = deps;
|
||||
|
||||
let mut root = RpcModule::new(());
|
||||
root.merge(blockchain::module(client.clone())?)?;
|
||||
root.merge(blockchain::module(client.clone(), pool)?)?;
|
||||
root.merge(validator_sets::module(client.clone()))?;
|
||||
if let Some(authority_discovery) = authority_discovery {
|
||||
root.merge(p2p_validators::module(id, client, authority_discovery)?)?;
|
||||
|
||||
@@ -7,6 +7,7 @@ pub(super) enum Error {
|
||||
Internal(&'static str),
|
||||
InvalidRequest(&'static str),
|
||||
InvalidStateReference,
|
||||
InvalidTransaction(String),
|
||||
}
|
||||
|
||||
impl From<Error> for jsonrpsee::types::error::ErrorObjectOwned {
|
||||
@@ -19,10 +20,15 @@ impl From<Error> for jsonrpsee::types::error::ErrorObjectOwned {
|
||||
jsonrpsee::types::error::ErrorObjectOwned::owned(-2, str, Option::<()>::None)
|
||||
}
|
||||
Error::InvalidStateReference => jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-4,
|
||||
-3,
|
||||
"the block used as the reference was not locally held",
|
||||
Option::<()>::None,
|
||||
),
|
||||
Error::InvalidTransaction(str) => jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-4,
|
||||
format!("transaction was not accepted to the mempool: {str}"),
|
||||
Option::<()>::None,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user