mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 21:01:05 +00:00
Introduce Backend trait to allow different RPC (or other) backends to be implemented (#1126)
* WIP backend trait * WIP converting higher level stuff to using Backend impl * more implementing new backend trait, mainly storage focused * Get core code compiling with new backend bits * subxt crate checks passing * fix tests * cargo fmt * clippy/fixes * merging and other fixes * fix test * fix lightclient code * Fix some broken doc links * another book link fix * fix broken test when moving default_rpc_client * fix dry_run test * fix more tests; lightclient and wasm * fix wasm tests * fix some doc examples * use next() instead of next_item() * missing next_item() -> next()s * move legacy RPc methods to LegacyRpcMethods type to host generic param instead of RpcClient * standardise on all RpcClient types prefixed with Rpc, and 'raw' trait types prefixed with RawRpc so it's less ocnfusing which is which * rename fixes * doc fixes * Add back system_dryRun RPC method and rename tx.dry_run() to tx.validate(), to signal that the calls are different * Add a test that we return the correct extrinsic hash from submit() * add TransactionValid details back, and protect against out of range bytes * add test for decoding transaction validation from empty bytes * fix clippy warning
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::{client::OnlineClientT, error::Error, events::Events, rpc::types::StorageKey, Config};
|
||||
use crate::backend::{Backend, BackendExt, BlockRef};
|
||||
use crate::{client::OnlineClientT, error::Error, events::Events, Config};
|
||||
use derivative::Derivative;
|
||||
use std::future::Future;
|
||||
|
||||
@@ -38,12 +39,12 @@ where
|
||||
/// but may run into errors attempting to work with them.
|
||||
pub fn at(
|
||||
&self,
|
||||
block_hash: T::Hash,
|
||||
block_ref: impl Into<BlockRef<T::Hash>>,
|
||||
) -> impl Future<Output = Result<Events<T>, Error>> + Send + 'static {
|
||||
self.at_or_latest(Some(block_hash))
|
||||
self.at_or_latest(Some(block_ref.into()))
|
||||
}
|
||||
|
||||
/// Obtain events at the latest block hash.
|
||||
/// Obtain events for the latest block.
|
||||
pub fn at_latest(&self) -> impl Future<Output = Result<Events<T>, Error>> + Send + 'static {
|
||||
self.at_or_latest(None)
|
||||
}
|
||||
@@ -51,49 +52,45 @@ where
|
||||
/// Obtain events at some block hash.
|
||||
fn at_or_latest(
|
||||
&self,
|
||||
block_hash: Option<T::Hash>,
|
||||
block_ref: Option<BlockRef<T::Hash>>,
|
||||
) -> impl Future<Output = Result<Events<T>, Error>> + Send + 'static {
|
||||
// Clone and pass the client in like this so that we can explicitly
|
||||
// return a Future that's Send + 'static, rather than tied to &self.
|
||||
let client = self.client.clone();
|
||||
async move {
|
||||
// If block hash is not provided, get the hash
|
||||
// for the latest block and use that.
|
||||
let block_hash = match block_hash {
|
||||
Some(hash) => hash,
|
||||
None => client
|
||||
.rpc()
|
||||
.block_hash(None)
|
||||
.await?
|
||||
.expect("didn't pass a block number; qed"),
|
||||
// If a block ref isn't provided, we'll get the latest best block to use.
|
||||
let block_ref = match block_ref {
|
||||
Some(r) => r,
|
||||
None => client.backend().latest_best_block_ref().await?,
|
||||
};
|
||||
|
||||
let event_bytes = get_event_bytes(&client, Some(block_hash)).await?;
|
||||
Ok(Events::new(client.metadata(), block_hash, event_bytes))
|
||||
let event_bytes = get_event_bytes(client.backend(), block_ref.hash()).await?;
|
||||
Ok(Events::new(
|
||||
client.metadata(),
|
||||
block_ref.hash(),
|
||||
event_bytes,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The storage key needed to access events.
|
||||
fn system_events_key() -> StorageKey {
|
||||
let mut storage_key = sp_core_hashing::twox_128(b"System").to_vec();
|
||||
storage_key.extend(sp_core_hashing::twox_128(b"Events").to_vec());
|
||||
StorageKey(storage_key)
|
||||
fn system_events_key() -> [u8; 32] {
|
||||
let a = sp_core_hashing::twox_128(b"System");
|
||||
let b = sp_core_hashing::twox_128(b"Events");
|
||||
let mut res = [0; 32];
|
||||
res[0..16].clone_from_slice(&a);
|
||||
res[16..32].clone_from_slice(&b);
|
||||
res
|
||||
}
|
||||
|
||||
// Get the event bytes from the provided client, at the provided block hash.
|
||||
pub(crate) async fn get_event_bytes<T, Client>(
|
||||
client: &Client,
|
||||
block_hash: Option<T::Hash>,
|
||||
) -> Result<Vec<u8>, Error>
|
||||
where
|
||||
T: Config,
|
||||
Client: OnlineClientT<T>,
|
||||
{
|
||||
Ok(client
|
||||
.rpc()
|
||||
.storage(&system_events_key().0, block_hash)
|
||||
pub(crate) async fn get_event_bytes<T: Config>(
|
||||
backend: &dyn Backend<T>,
|
||||
block_hash: T::Hash,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
Ok(backend
|
||||
.storage_fetch_value(system_events_key().to_vec(), block_hash)
|
||||
.await?
|
||||
.map(|e| e.0)
|
||||
.unwrap_or_else(Vec::new))
|
||||
.unwrap_or_default())
|
||||
}
|
||||
|
||||
@@ -69,36 +69,13 @@ impl<T: Config> Events<T> {
|
||||
|
||||
/// Obtain the events from a block hash given custom metadata and a client.
|
||||
///
|
||||
/// This method gives users the ability to inspect the events of older blocks,
|
||||
/// where the metadata changed. For those cases, the user is responsible for
|
||||
/// providing a valid metadata.
|
||||
/// # Notes
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use subxt::{ OnlineClient, PolkadotConfig, events::Events };
|
||||
///
|
||||
/// let client = OnlineClient::<PolkadotConfig>::new().await.unwrap();
|
||||
///
|
||||
/// // Get the hash of an older block.
|
||||
/// let block_hash = client
|
||||
/// .rpc()
|
||||
/// .block_hash(Some(1u32.into()))
|
||||
/// .await?
|
||||
/// .expect("didn't pass a block number; qed");
|
||||
/// // Fetch the metadata of the given block.
|
||||
/// let metadata = client.rpc().metadata_legacy(Some(block_hash)).await?;
|
||||
/// // Fetch the events from the client.
|
||||
/// let events = Events::new_from_client(metadata, block_hash, client);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// Prefer to use [`crate::events::EventsClient::at`] to obtain the events.
|
||||
/// - Prefer to use [`crate::events::EventsClient::at`] to obtain the events.
|
||||
/// - Subxt may fail to decode things that aren't from a runtime using the
|
||||
/// latest metadata version.
|
||||
/// - The client may not be able to obtain the block at the given hash. Only
|
||||
/// archive nodes keep hold of all past block information.
|
||||
pub async fn new_from_client<Client>(
|
||||
metadata: Metadata,
|
||||
block_hash: T::Hash,
|
||||
@@ -107,7 +84,7 @@ impl<T: Config> Events<T> {
|
||||
where
|
||||
Client: OnlineClientT<T>,
|
||||
{
|
||||
let event_bytes = get_event_bytes(&client, Some(block_hash)).await?;
|
||||
let event_bytes = get_event_bytes(client.backend(), block_hash).await?;
|
||||
Ok(Events::new(metadata, block_hash, event_bytes))
|
||||
}
|
||||
|
||||
@@ -669,7 +646,7 @@ mod tests {
|
||||
// construst an Events object to iterate them:
|
||||
let event = Event::A(1, true, vec!["Hi".into()]);
|
||||
let events = events::<Event>(
|
||||
metadata.clone(),
|
||||
metadata,
|
||||
vec![event_record(Phase::ApplyExtrinsic(123), event)],
|
||||
);
|
||||
|
||||
@@ -711,7 +688,7 @@ mod tests {
|
||||
let event3 = Event::A(234);
|
||||
|
||||
let events = events::<Event>(
|
||||
metadata.clone(),
|
||||
metadata,
|
||||
vec![
|
||||
event_record(Phase::Initialization, event1),
|
||||
event_record(Phase::ApplyExtrinsic(123), event2),
|
||||
@@ -782,7 +759,7 @@ mod tests {
|
||||
// Encode our events in the format we expect back from a node, and
|
||||
// construst an Events object to iterate them:
|
||||
let events = events_raw(
|
||||
metadata.clone(),
|
||||
metadata,
|
||||
event_bytes,
|
||||
3, // 2 "good" events, and then it'll hit the naff bytes.
|
||||
);
|
||||
@@ -833,7 +810,7 @@ mod tests {
|
||||
// Encode our events in the format we expect back from a node, and
|
||||
// construst an Events object to iterate them:
|
||||
let events = events::<Event>(
|
||||
metadata.clone(),
|
||||
metadata,
|
||||
vec![event_record(Phase::Finalization, Event::A(1))],
|
||||
);
|
||||
|
||||
@@ -870,7 +847,7 @@ mod tests {
|
||||
// Encode our events in the format we expect back from a node, and
|
||||
// construct an Events object to iterate them:
|
||||
let events = events::<Event>(
|
||||
metadata.clone(),
|
||||
metadata,
|
||||
vec![event_record(
|
||||
Phase::Finalization,
|
||||
Event::A(CompactWrapper(1)),
|
||||
@@ -914,7 +891,7 @@ mod tests {
|
||||
// Encode our events in the format we expect back from a node, and
|
||||
// construct an Events object to iterate them:
|
||||
let events = events::<Event>(
|
||||
metadata.clone(),
|
||||
metadata,
|
||||
vec![event_record(Phase::Finalization, Event::A(MyType::B))],
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user