-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Create new index for tracking Asset metadata #2445
base: master
Are you sure you want to change the base?
Changes from 10 commits
610fd37
54375c3
1dc6932
246eae3
684361d
d750c73
ab09b8d
07fa5e5
b2abf4d
3b56332
0cb04fd
6ae2051
098b031
630da0d
ef2e9ce
5ae7e63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use crate::client::schema::{ | ||
schema, | ||
AssetId, | ||
HexString, | ||
U64, | ||
}; | ||
|
||
#[derive(cynic::QueryVariables, Debug)] | ||
pub struct AssetInfoArg { | ||
pub id: AssetId, | ||
} | ||
|
||
#[derive(cynic::QueryFragment, Clone, Debug)] | ||
#[cynic( | ||
schema_path = "./assets/schema.sdl", | ||
graphql_type = "Query", | ||
variables = "AssetInfoArg" | ||
)] | ||
pub struct AssetInfoQuery { | ||
#[arguments(id: $id)] | ||
pub asset_details: Option<AssetInfoDetails>, | ||
} | ||
|
||
#[derive(cynic::QueryFragment, Clone, Debug)] | ||
#[cynic(schema_path = "./assets/schema.sdl")] | ||
pub struct AssetInfoDetails { | ||
pub sub_id: HexString, | ||
pub contract_id: HexString, | ||
pub total_supply: U64, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,6 +64,8 @@ use fuel_core_types::{ | |
}; | ||
use std::sync::Arc; | ||
|
||
use super::storage::assets::AssetDetails; | ||
|
||
pub trait OffChainDatabase: Send + Sync { | ||
fn block_height(&self, block_id: &BlockId) -> StorageResult<BlockHeight>; | ||
|
||
|
@@ -112,6 +114,10 @@ pub trait OffChainDatabase: Send + Sync { | |
) -> StorageResult<Option<RelayedTransactionStatus>>; | ||
|
||
fn message_is_spent(&self, nonce: &Nonce) -> StorageResult<bool>; | ||
|
||
fn asset_info(&self, asset_id: &AssetId) -> StorageResult<Option<AssetDetails>>; | ||
|
||
fn asset_exists(&self, asset_id: &AssetId) -> StorageResult<bool>; | ||
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. Seems like |
||
} | ||
|
||
/// The on chain database port expected by GraphQL API service. | ||
|
@@ -273,6 +279,7 @@ pub mod worker { | |
}, | ||
}, | ||
graphql_api::storage::{ | ||
assets::AssetsInfo, | ||
da_compression::*, | ||
old::{ | ||
OldFuelBlockConsensus, | ||
|
@@ -336,6 +343,7 @@ pub mod worker { | |
+ StorageMutate<DaCompressionTemporalRegistryIndex, Error = StorageError> | ||
+ StorageMutate<DaCompressionTemporalRegistryTimestamps, Error = StorageError> | ||
+ StorageMutate<DaCompressionTemporalRegistryEvictorCache, Error = StorageError> | ||
+ StorageMutate<AssetsInfo, Error = StorageError> | ||
{ | ||
fn record_tx_id_owner( | ||
&mut self, | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,48 @@ | ||||||
use fuel_core_storage::{ | ||||||
blueprint::plain::Plain, | ||||||
codec::{ | ||||||
postcard::Postcard, | ||||||
raw::Raw, | ||||||
}, | ||||||
structured_storage::TableWithBlueprint, | ||||||
Mappable, | ||||||
}; | ||||||
use fuel_core_types::{ | ||||||
fuel_merkle::common::Bytes32, | ||||||
fuel_tx::{ | ||||||
AssetId, | ||||||
ContractId, | ||||||
}, | ||||||
}; | ||||||
|
||||||
/// Contract info | ||||||
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.
Suggested change
|
||||||
pub struct AssetsInfo; | ||||||
|
||||||
pub type AssetDetails = (ContractId, Bytes32, u64); // (contract_id, sub_id, total_amount) | ||||||
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. Can we use struct with named fields? Something similar to what we have here. |
||||||
|
||||||
impl Mappable for AssetsInfo { | ||||||
type Key = AssetId; | ||||||
type OwnedKey = Self::Key; | ||||||
type Value = Self::OwnedValue; | ||||||
type OwnedValue = AssetDetails; | ||||||
} | ||||||
|
||||||
impl TableWithBlueprint for AssetsInfo { | ||||||
type Blueprint = Plain<Raw, Postcard>; | ||||||
type Column = super::Column; | ||||||
|
||||||
fn column() -> Self::Column { | ||||||
Self::Column::AssetsInfo | ||||||
} | ||||||
} | ||||||
|
||||||
#[cfg(test)] | ||||||
mod test { | ||||||
use super::*; | ||||||
|
||||||
fuel_core_storage::basic_storage_tests!( | ||||||
AssetsInfo, | ||||||
<AssetsInfo as Mappable>::Key::default(), | ||||||
<AssetsInfo as Mappable>::Value::default() | ||||||
); | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,12 @@ | ||
use super::{ | ||
da_compression::da_compress_block, | ||
storage::old::{ | ||
OldFuelBlockConsensus, | ||
OldFuelBlocks, | ||
OldTransactions, | ||
storage::{ | ||
assets::AssetsInfo, | ||
old::{ | ||
OldFuelBlockConsensus, | ||
OldFuelBlocks, | ||
OldTransactions, | ||
}, | ||
}, | ||
}; | ||
use crate::{ | ||
|
@@ -63,9 +66,11 @@ use fuel_core_types::{ | |
CoinPredicate, | ||
CoinSigned, | ||
}, | ||
AssetId, | ||
Contract, | ||
Input, | ||
Output, | ||
Receipt, | ||
Transaction, | ||
TxId, | ||
UniqueIdentifier, | ||
|
@@ -356,6 +361,54 @@ where | |
) | ||
.into()); | ||
} | ||
|
||
for receipt in result.receipts() { | ||
match receipt { | ||
Receipt::Mint { | ||
sub_id, | ||
contract_id, | ||
val, | ||
.. | ||
} => { | ||
let asset_id = AssetId::from(**contract_id); | ||
let current_count = db | ||
.storage::<AssetsInfo>() | ||
.get(&asset_id)? | ||
.map(|info| { | ||
info.2 | ||
.checked_add(*val) | ||
.ok_or(anyhow::anyhow!("Asset count overflow")) | ||
}) | ||
.transpose()? | ||
.unwrap_or(*val); | ||
|
||
db.storage::<AssetsInfo>() | ||
.insert(&asset_id, &(*contract_id, **sub_id, current_count))?; | ||
} | ||
Receipt::Burn { | ||
sub_id, | ||
contract_id, | ||
val, | ||
.. | ||
} => { | ||
let asset_id = AssetId::from(**contract_id); | ||
let current_count = db | ||
maschad marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.storage::<AssetsInfo>() | ||
.get(&asset_id)? | ||
.map(|info| { | ||
info.2 | ||
.checked_sub(*val) | ||
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. If we go down to Anyway, currently the index may grow indefinitely. Which also makes me think that I should consider this for the balances indexation I added recently :-) cc: @xgreenx, wdyt? |
||
.ok_or(anyhow::anyhow!("Asset count overflow")) | ||
maschad marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}) | ||
.transpose()? | ||
.unwrap_or(*val); | ||
|
||
db.storage::<AssetsInfo>() | ||
.insert(&asset_id, &(*contract_id, **sub_id, current_count))?; | ||
} | ||
_ => {} | ||
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. Please enumerate all variants explicitly to avoid surprises when new variant is added in the future. |
||
} | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod assets; | ||
mod balance; | ||
mod blob; | ||
mod block; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use crate::{ | ||
fuel_core_graphql_api::database::ReadView, | ||
graphql_api::storage::assets::AssetDetails, | ||
}; | ||
use fuel_core_storage::{ | ||
not_found, | ||
Result as StorageResult, | ||
}; | ||
use fuel_core_types::fuel_tx::AssetId; | ||
|
||
impl ReadView { | ||
pub fn get_asset_details(&self, id: AssetId) -> StorageResult<AssetDetails> { | ||
let asset = self | ||
.off_chain | ||
.asset_info(&id)? | ||
.ok_or(not_found!(AssetDetails))?; | ||
Ok(asset) | ||
} | ||
} |
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.
Not sure here, but maybe we want to use
ContractId!
here, as in other places.