-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Publish indexed transactions with BLAKE2b hashes to IPFS DHT #10468
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
f12fc2c
b2411ad
d6c06f6
9a963c7
f2af1ea
f2386bd
294ea60
2b999d1
3861b6d
5d08673
c0daab0
e27395d
4294ffb
deeeb18
392f5be
626760b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| title: Publish indexed transactions with BLAKE2b hashes to IPFS DHT | ||
| doc: | ||
| - audience: [Node Dev, Node Operator] | ||
| description: Add `--ipfs-bootnodes` flag for specifying IPFS bootnodes. If passed | ||
| along with `--ipfs-server`, the node will register as a content provider in IPFS | ||
| DHT of indexed transactions with BLAKE2b hashes of the last two weeks (or pruning | ||
| depth if smaller). | ||
| crates: | ||
| - name: sc-network | ||
| bump: major | ||
| - name: sc-network-types | ||
| bump: minor | ||
| - name: cumulus-client-pov-recovery | ||
| bump: minor | ||
| - name: sc-client-api | ||
| bump: major | ||
| - name: sc-client-db | ||
| bump: minor | ||
| - name: sc-rpc-spec-v2 | ||
| bump: patch | ||
| - name: sc-service | ||
| bump: major | ||
| - name: sp-blockchain | ||
| bump: minor | ||
| - name: cumulus-relay-chain-minimal-node | ||
| bump: patch | ||
| - name: sc-cli | ||
| bump: major |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ | |
| //! A set of APIs supported by the client along with their primitives. | ||
|
|
||
| use sp_consensus::BlockOrigin; | ||
| use sp_core::storage::StorageKey; | ||
| use sp_core::{storage::StorageKey, H256}; | ||
| use sp_runtime::{ | ||
| generic::SignedBlock, | ||
| traits::{Block as BlockT, NumberFor}, | ||
|
|
@@ -132,13 +132,19 @@ pub trait BlockBackend<Block: BlockT> { | |
| hash: Block::Hash, | ||
| ) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>; | ||
|
|
||
| /// Get all indexed transactions for a block, | ||
| /// including renewed transactions. | ||
| /// Get all indexed transactions for a block, including renewed transactions. | ||
| /// | ||
| /// Note that this will only fetch transactions | ||
| /// that are indexed by the runtime with `storage_index_transaction`. | ||
| /// Note that this will only fetch transactions that are indexed by the runtime with | ||
| /// `storage_index_transaction`. | ||
| fn block_indexed_body(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>>; | ||
|
|
||
| /// Get the BLAKE2b-256 hashes of all indexed transactions in a block, including renewed | ||
| /// transactions. | ||
| /// | ||
| /// Note that this will only fetch transactions that are indexed by the runtime with | ||
| /// `storage_index_transaction`. | ||
| fn block_indexed_hashes(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<H256>>>; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dq: Should we keep generic over the returned values (ie replace H256 with BlockT::Hash)? (I do like the h256 better, asking for consistency)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is also a BLAKE2b-256 and not a block hash. |
||
|
|
||
| /// Get full block by hash. | ||
| fn block(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<SignedBlock<Block>>>; | ||
|
|
||
|
|
@@ -151,14 +157,14 @@ pub trait BlockBackend<Block: BlockT> { | |
| /// Get block hash by number. | ||
| fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>; | ||
|
|
||
| /// Get single indexed transaction by content hash. | ||
| /// Get single indexed transaction by content hash (BLAKE2b-256). | ||
| /// | ||
| /// Note that this will only fetch transactions | ||
| /// that are indexed by the runtime with `storage_index_transaction`. | ||
| fn indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>>; | ||
| fn indexed_transaction(&self, hash: H256) -> sp_blockchain::Result<Option<Vec<u8>>>; | ||
|
|
||
| /// Check if transaction index exists. | ||
| fn has_indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result<bool> { | ||
| /// Check if transaction index exists given its BLAKE2b-256 hash. | ||
| fn has_indexed_transaction(&self, hash: H256) -> sp_blockchain::Result<bool> { | ||
| Ok(self.indexed_transaction(hash)?.is_some()) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -665,6 +665,29 @@ impl<Block: BlockT> BlockchainDb<Block> { | |
| } | ||
| Ok(None) | ||
| } | ||
|
|
||
| fn block_indexed_hashes_iter( | ||
| &self, | ||
| hash: Block::Hash, | ||
| ) -> ClientResult<Option<impl Iterator<Item = DbHash>>> { | ||
| let body = match read_db( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: |
||
| &*self.db, | ||
| columns::KEY_LOOKUP, | ||
| columns::BODY_INDEX, | ||
| BlockId::<Block>::Hash(hash), | ||
| )? { | ||
| Some(body) => body, | ||
| None => return Ok(None), | ||
| }; | ||
| match Vec::<DbExtrinsic<Block>>::decode(&mut &body[..]) { | ||
| Ok(index) => Ok(Some(index.into_iter().flat_map(|ex| match ex { | ||
| DbExtrinsic::Indexed { hash, .. } => Some(hash), | ||
| _ => None, | ||
| }))), | ||
| Err(err) => | ||
| Err(sp_blockchain::Error::Backend(format!("Error decoding body list: {err}"))), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl<Block: BlockT> sc_client_api::blockchain::HeaderBackend<Block> for BlockchainDb<Block> { | ||
|
|
@@ -750,42 +773,32 @@ impl<Block: BlockT> sc_client_api::blockchain::Backend<Block> for BlockchainDb<B | |
| children::read_children(&*self.db, columns::META, meta_keys::CHILDREN_PREFIX, parent_hash) | ||
| } | ||
|
|
||
| fn indexed_transaction(&self, hash: Block::Hash) -> ClientResult<Option<Vec<u8>>> { | ||
| fn indexed_transaction(&self, hash: DbHash) -> ClientResult<Option<Vec<u8>>> { | ||
| Ok(self.db.get(columns::TRANSACTION, hash.as_ref())) | ||
| } | ||
|
|
||
| fn has_indexed_transaction(&self, hash: Block::Hash) -> ClientResult<bool> { | ||
| fn has_indexed_transaction(&self, hash: DbHash) -> ClientResult<bool> { | ||
| Ok(self.db.contains(columns::TRANSACTION, hash.as_ref())) | ||
| } | ||
|
|
||
| fn block_indexed_hashes(&self, hash: Block::Hash) -> ClientResult<Option<Vec<DbHash>>> { | ||
| self.block_indexed_hashes_iter(hash).map(|hashes| hashes.map(Iterator::collect)) | ||
| } | ||
|
|
||
| fn block_indexed_body(&self, hash: Block::Hash) -> ClientResult<Option<Vec<Vec<u8>>>> { | ||
| let body = match read_db( | ||
| &*self.db, | ||
| columns::KEY_LOOKUP, | ||
| columns::BODY_INDEX, | ||
| BlockId::<Block>::Hash(hash), | ||
| )? { | ||
| Some(body) => body, | ||
| None => return Ok(None), | ||
| }; | ||
| match Vec::<DbExtrinsic<Block>>::decode(&mut &body[..]) { | ||
| Ok(index) => { | ||
| let mut transactions = Vec::new(); | ||
| for ex in index.into_iter() { | ||
| if let DbExtrinsic::Indexed { hash, .. } = ex { | ||
| match self.db.get(columns::TRANSACTION, hash.as_ref()) { | ||
| Some(t) => transactions.push(t), | ||
| None => | ||
| return Err(sp_blockchain::Error::Backend(format!( | ||
| "Missing indexed transaction {hash:?}", | ||
| ))), | ||
| } | ||
| } | ||
| } | ||
| Ok(Some(transactions)) | ||
| }, | ||
| Err(err) => | ||
| Err(sp_blockchain::Error::Backend(format!("Error decoding body list: {err}"))), | ||
| match self.block_indexed_hashes_iter(hash) { | ||
| Ok(Some(hashes)) => Ok(Some( | ||
| hashes | ||
| .map(|hash| match self.db.get(columns::TRANSACTION, hash.as_ref()) { | ||
| Some(t) => Ok(t), | ||
| None => Err(sp_blockchain::Error::Backend(format!( | ||
| "Missing indexed transaction {hash:?}", | ||
| ))), | ||
| }) | ||
| .collect::<Result<_, _>>()?, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: The
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| )), | ||
| Ok(None) => Ok(None), | ||
| Err(err) => Err(err), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -676,9 +676,12 @@ pub struct NetworkConfiguration { | |
| /// `kademlia_replication_factor` peers to consider record successfully put. | ||
| pub kademlia_replication_factor: NonZeroUsize, | ||
|
|
||
| /// Enable serving block data over IPFS bitswap. | ||
| /// Enable publishing of indexed transactions to IPFS. | ||
| pub ipfs_server: bool, | ||
|
|
||
| /// List of IPFS bootstrap nodes. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: We could mention that only direct requests will be handled here if no bootnods are provided |
||
| pub ipfs_bootnodes: Vec<MultiaddrWithPeerId>, | ||
|
|
||
| /// Networking backend used for P2P communication. | ||
| pub network_backend: NetworkBackendType, | ||
| } | ||
|
|
@@ -714,6 +717,7 @@ impl NetworkConfiguration { | |
| kademlia_replication_factor: NonZeroUsize::new(DEFAULT_KADEMLIA_REPLICATION_FACTOR) | ||
| .expect("value is a constant; constant is non-zero; qed."), | ||
| ipfs_server: false, | ||
| ipfs_bootnodes: Vec::new(), | ||
| network_backend: NetworkBackendType::Litep2p, | ||
| } | ||
| } | ||
|
|
@@ -749,6 +753,16 @@ impl NetworkConfiguration { | |
| } | ||
| } | ||
|
|
||
| /// IPFS server configuration. | ||
| pub struct IpfsConfig<Block: BlockT, H: ExHashT, N: NetworkBackend<Block, H>> { | ||
| /// Network-backend-specific Bitswap configuration. | ||
| pub bitswap_config: N::BitswapConfig, | ||
| /// Indexed transactions provider. | ||
| pub block_provider: Box<dyn crate::IpfsBlockProvider>, | ||
| /// IPFS bootstrap nodes. | ||
| pub bootnodes: Vec<MultiaddrWithPeerId>, | ||
| } | ||
|
|
||
| /// Network initialization parameters. | ||
| pub struct Params<Block: BlockT, H: ExHashT, N: NetworkBackend<Block, H>> { | ||
| /// Assigned role for our node (full, light, ...). | ||
|
|
@@ -777,7 +791,7 @@ pub struct Params<Block: BlockT, H: ExHashT, N: NetworkBackend<Block, H>> { | |
| pub block_announce_config: N::NotificationProtocolConfig, | ||
|
|
||
| /// Bitswap configuration, if the server has been enabled. | ||
| pub bitswap_config: Option<N::BitswapConfig>, | ||
| pub ipfs_config: Option<IpfsConfig<Block, H, N>>, | ||
|
|
||
| /// Notification metrics. | ||
| pub notification_metrics: NotificationMetrics, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dq: Does the
Block::Hashresolve to something different here? Or we should update the other methods of the trait?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Block::Hashcan be any hash internally, including hashes of different size.H256is a fixed-length 32-byte hash, in this case BLAKE2b-256.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am glad that you touched on these topics. Please check my thoughts from the previous issue, “IPFS/Bitswap CID filtering” #10538 — one of them is exactly about this hash/block_hash/content_hash question.