Skip to content

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
  • Loading branch information
ra0x3 committed Nov 20, 2023
1 parent 6b0c530 commit 575a699
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 124 deletions.
62 changes: 58 additions & 4 deletions docs/src/indexing-fuel-types/predicates.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,72 @@ pub struct Predicate {
In order to get started indexing Predicates, users will need to:

1. Create a new Predicate project using [`forc`]
2. Build this predicate project in order to get the JSON ABI.
3. Add this predicate template hash to your indexer manifest.
2. Build this predicate project using `forc build` in order to get the project JSON ABI and predicate template ID.
3. Add this predicate info to your indexer manifest.
4. Include the appropriate witness data in transactions you wish to flag to your indexer

### Sway Predicate

```sway,ignore
predicate;
enum PairAsset {
BTC : (),
ETH : (),
}
impl Eq for PairAsset {
fn eq(self, other: Self) -> bool {
match (self, other) {
(PairAsset::BTC(_), PairAsset::BTC(_)) => true,
(PairAsset::ETH(_), PairAsset::ETH(_)) => true,
_ => false,
}
}
}
struct OrderPair {
bid: PairAsset,
ask: PairAsset,
}
impl Eq for OrderPair {
fn eq(self, other: Self) -> bool {
self.bid == other.bid && self.ask == other.ask
}
}
configurable {
AMOUNT: u64 = 1u64,
PAIR: OrderPair = OrderPair { bid: PairAsset::BTC, ask: PairAsset::ETH },
}
fn main(
amount: u64,
pair: OrderPair,
) -> bool {
amount == AMOUNT && pair == PAIR
}
```

### Predicate Indexer

```rust,ignore
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_spent_predicates(predicate: Predicate, configurables: MyPredicateConfigurables) {
unimplemented!()
fn handle_spent_predicates(predicates: Predicates, configurables: MyPredicateInputs) {
let template_id = "0xb16545fd38b82ab5178d79c71ad0ce54712cbdcee22f722b08db278e77d1bcbc";
if let Some(predicate) = predicates.get(template_id) {
match configurables.pair.bid {
OrderPair::BTC => info!("Someone wants to give BTC"),
OrderPair::ETH => info!("Someone wants to get ETH"),
}
}
info!("No predicates for this indexer found in the transaction");
}
}
```
17 changes: 12 additions & 5 deletions packages/fuel-indexer-macros/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ pub fn is_tuple_type(typ: &TypeDeclaration) -> bool {
&& type_field_chars.next().is_some_and(|c| c != ')')
}

/// Whether a `TypeDeclaration` is a copy-able type.
pub fn is_copy_type(typ: &TypeDeclaration) -> bool {
let name = typ.type_field.split_whitespace().next().unwrap();
name == "struct" || name == "enum"
}

/// Whether a `TypeDeclaration` is a unit type
pub fn is_unit_type(typ: &TypeDeclaration) -> bool {
let mut type_field_chars = typ.type_field.chars();
Expand Down Expand Up @@ -200,6 +206,7 @@ pub fn decode_snippet(
if ty_id == Predicates::type_id() {
quote! {
#ty_id => {
// FIXME: Inject template ID here!!!
let obj: Predicate = bincode::deserialize(&data).expect("Bad bincode.");
self.#name.add("123".to_string(), obj);
}
Expand Down Expand Up @@ -1257,7 +1264,7 @@ pub fn configurable_fn_type_name(configurable: &Configurable) -> Option<String>
}

/// Derive a mapping of input type IDs to their corresponding names for a given set of predicates.
pub fn derive_configurables_names_map(manifest: &Manifest) -> HashMap<usize, String> {
pub fn predicate_inputs_names_map(manifest: &Manifest) -> HashMap<usize, String> {
let mut output = HashMap::new();
if let Some(predicate) = manifest.predicates() {
if predicate.is_empty() {
Expand All @@ -1283,12 +1290,12 @@ pub fn derive_configurables_names_map(manifest: &Manifest) -> HashMap<usize, Str
output
}

/// Given a template name, derive the name of the corresponding `fuel-indexer` `Configurables` type.
pub fn indexer_configurables_name(template_name: &str) -> String {
format!("{}IndexerConfigurables", to_pascal_case(template_name))
/// Derive the name of the set of inputs for this predicate template.
pub fn predicate_inputs_name(template_name: &str) -> String {
format!("{}Inputs", to_pascal_case(template_name))
}

/// Given a template name, derive the name of the corresponding `fuels-rs` `Configurables` type.
/// Derive the name of the set of configurables for this predicate template.
pub fn sdk_configurables_name(template_name: &str) -> String {
format!("{}Configurables", to_pascal_case(template_name))
}
Expand Down
6 changes: 3 additions & 3 deletions packages/fuel-indexer-macros/src/indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fn process_fn_items(
t.iter()
.map(|t| {
let ty_id = type_id(FUEL_TYPES_NAMESPACE, &t.name()) as usize;
let name = indexer_configurables_name(&t.name());
let name = predicate_inputs_name(&t.name());
TypeDeclaration {
type_id: ty_id,
type_field: name,
Expand Down Expand Up @@ -853,7 +853,7 @@ pub fn process_indexer_module(attrs: TokenStream, item: TokenStream) -> TokenStr

let predicate_impl_tokens = predicate_entity_impl_tokens();

let indexer_configurables_tokens = indexer_configurables_tokens(&manifest);
let predicate_inputs_tokens = predicate_inputs_tokens(&manifest);

let (block, fn_items) = process_fn_items(&manifest, indexer_module);
let block = handler_block(block, fn_items);
Expand All @@ -863,7 +863,7 @@ pub fn process_indexer_module(attrs: TokenStream, item: TokenStream) -> TokenStr

#graphql_tokens

#indexer_configurables_tokens
#predicate_inputs_tokens

#predicate_impl_tokens

Expand Down
96 changes: 40 additions & 56 deletions packages/fuel-indexer-macros/src/tokens.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// Various functions that generate TokenStreams used to augment the indexer ASTs.
use crate::helpers::*;
use fuel_abi_types::abi::program::{Configurable, TypeDeclaration};
use fuel_abi_types::abi::program::TypeDeclaration;
use fuel_indexer_lib::manifest::Manifest;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
Expand Down Expand Up @@ -432,7 +432,7 @@ pub fn configurables_match_tokens(manifest: &Manifest) -> Vec<TokenStream> {
t.iter()
.map(|t| {
let template_id = t.id().to_string();
let name = indexer_configurables_name(&t.name());
let name = predicate_inputs_name(&t.name());
let ident = format_ident! { "{}", name };

// NOTE: This decoding is used to derive the indexer configurable so that we can further use it
Expand Down Expand Up @@ -460,12 +460,12 @@ pub fn predicate_verification_tokens(manifest: &Manifest) -> Vec<TokenStream> {
return output;
}

let configurables_namings = derive_configurables_names_map(manifest);
let input_names = predicate_inputs_names_map(manifest);

if let Some(templates) = predicates.templates() {
for template in templates {
let indexer_variant_name =
format_ident! { "{}", indexer_configurables_name(&template.name()) };
format_ident! { "{}", predicate_inputs_name(&template.name()) };
let sdk_variant_name =
format_ident! { "{}", sdk_configurables_name(&template.name()) };

Expand All @@ -474,6 +474,12 @@ pub fn predicate_verification_tokens(manifest: &Manifest) -> Vec<TokenStream> {
let abi = get_json_abi(Some(template.abi()))
.expect("Could not derive predicate JSON ABI.");

let abi_types = abi
.types
.iter()
.map(|typ| (typ.type_id, typ.clone()))
.collect::<HashMap<usize, TypeDeclaration>>();

let main = abi
.functions
.iter()
Expand All @@ -485,25 +491,37 @@ pub fn predicate_verification_tokens(manifest: &Manifest) -> Vec<TokenStream> {
.iter()
.map(|i| {
let ty_id = i.type_id;
let name = configurables_namings
let name = input_names
.get(&ty_id)
.expect("Could not find configurable naming.");
let name = format_ident! {"{}", name };

format_ident! {"{}", name }
})
.collect::<Vec<_>>();

let chained_functions =
abi.configurables.iter().flat_map(|configurables| {
configurables.iter().map(|c| {
let typ = abi_types.get(&c.application.type_id).expect(
"Predicate configurable type not found in the ABI.",
);

let clone = if is_copy_type(typ) {
quote! { .clone() }
} else {
quote! {}
};

let ty_name = configurable_fn_type_name(c)
.expect("Cannot use unit types '()' in configurables.");
let arg = configurables_namings
let arg = input_names
.get(&c.application.type_id)
.expect("Could not find configurable naming.");
let arg = format_ident! {"{}", arg };
let fn_name = format_ident! { "with_{}", ty_name };
quote! {
.#fn_name(#arg)
.#fn_name(#arg #clone)
}
})
});
Expand Down Expand Up @@ -532,17 +550,13 @@ pub fn predicate_verification_tokens(manifest: &Manifest) -> Vec<TokenStream> {
output
}

/// `TokenStream` used to generate a set of indexer-specific configurables (not to be confused
/// with `fuels-rs` configurables).
///
/// While `fuels-rs` configurables are used in the predicate verification process, `fuel-indexer`
/// configurables are passed to indexer handlers and made available to users.
pub fn indexer_configurables_tokens(manifest: &Manifest) -> TokenStream {
/// `TokenStream` used to generate a set of indexer-specific predicate inputs.
pub fn predicate_inputs_tokens(manifest: &Manifest) -> TokenStream {
let predicates = manifest.predicates();

let mut output = quote! {
trait ConfigurableDecoder {
fn decode_type(&self, ty_id: usize, data: Vec<u8>);
trait InputDecoder {
fn decode_type(&self, ty_id: usize, data: Vec<u8>) -> anyhow::Result<()>;
}
};

Expand All @@ -551,9 +565,9 @@ pub fn indexer_configurables_tokens(manifest: &Manifest) -> TokenStream {
return output;
}

let configurable_namings = derive_configurables_names_map(manifest);
let configurable_namings = predicate_inputs_names_map(manifest);

let mut configurable_variants = Vec::new();
let mut input_variants = Vec::new();

let names = p
.templates()
Expand All @@ -573,23 +587,13 @@ pub fn indexer_configurables_tokens(manifest: &Manifest) -> TokenStream {
.find(|f| f.name == "main")
.expect("Could not find main function in predicate ABI.");

let configurable_types = abi
.configurables
.iter()
.flat_map(|configurables| {
configurables
.iter()
.map(|c| (c.application.type_id, c.clone()))
})
.collect::<HashMap<usize, Configurable>>();

let predicate_types = abi
.types
.iter()
.map(|typ| (typ.type_id, typ.clone()))
.collect::<HashMap<usize, TypeDeclaration>>();

let predicate_input_fields = main
let input_fields = main
.inputs
.iter()
.map(|i| {
Expand All @@ -608,53 +612,33 @@ pub fn indexer_configurables_tokens(manifest: &Manifest) -> TokenStream {
})
.collect::<Vec<_>>();

let config_set_decoders = configurable_types
.keys()
.map(|ty_id| {
let typ = predicate_types.get(ty_id).expect(
"Could not get configurable type reference from ABI types.",
);
let type_tokens = typ.rust_tokens();
decode_snippet(&type_tokens, typ)
})
.collect::<Vec<TokenStream>>();

let name = indexer_configurables_name(&name);
let name = predicate_inputs_name(&name);
let ident = format_ident! { "{}", name };
configurable_variants.push(ident.clone());
input_variants.push(ident.clone());

output = quote! {
#output

#[derive(Debug, Clone)]
pub struct #ident {
pub id: String,
#(#predicate_input_fields),*
#(#input_fields),*
}

impl #ident {

// TODO: Should document the standardization of predicate witness data

pub fn new(data: Vec<u8>) -> Self {

// FIXME: This will have to be a part of the codegen

// We need to:
// 1. chunk each piece (ty_id, len, and data)
// 2. Use SDK to decode data into T
// 3. When finished create Self { } using all T's
todo!("Finish!")
}
}

impl ConfigurableDecoder for #ident {
fn decode_type(&self, ty_id: usize, data: Vec<u8>) {
match ty_id {
#(#config_set_decoders)*
_ => {
panic!("Could not find type with ID: {}", ty_id);
}
}
}
}

impl TypeId for #ident {
fn type_id() -> usize {
type_id(FUEL_TYPES_NAMESPACE, #name) as usize
Expand All @@ -667,7 +651,7 @@ pub fn indexer_configurables_tokens(manifest: &Manifest) -> TokenStream {
#output

enum ConfigurablesContainer {
#(#configurable_variants(#configurable_variants)),*
#(#input_variants(#input_variants)),*
}
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ predicates:
abi: packages/fuel-indexer-tests/sway/test-predicate1/out/debug/test-predicate1-abi.json
id: 0xcfd60aa414972babde16215e0cb5a2739628831405a7ae81a9fc1d2ebce87145
- name: TestPredicate2
id: 0x1c83e1f094b47f14943066f6b6ca41ce5c3ae4e387c973e924564dac0227a896
id: 0xb16545fd38b82ab5178d79c71ad0ce54712cbdcee22f722b08db278e77d1bcbc
abi: packages/fuel-indexer-tests/sway/test-predicate2/out/debug/test-predicate2-abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ mod fuel_indexer_test {

fn fuel_indexer_test_predicates(
_predicates: Predicates,
_configurables: TestPredicate1IndexerConfigurables,
_inputs: TestPredicate1Inputs,
) {
info!("fuel_indexer_test_predicates handling trigger_predicates event");
}
Expand Down
Loading

0 comments on commit 575a699

Please sign in to comment.