diff --git a/config.yaml b/config.yaml index 794465086..85bf4dc3b 100644 --- a/config.yaml +++ b/config.yaml @@ -35,7 +35,7 @@ indexer_net_config: false # The number of WASM opcodes after which the indexer will stop execution. metering_points: 30000000000 -# Allow the web API to accept raw SQL queries. +# Allow the web server to accept raw SQL queries. accept_sql_queries: false # Amount of blocks to return in a request to a Fuel node. @@ -64,7 +64,7 @@ web_api: # Web API port. port: 29987 - # Max body size for web API requests. + # Max body size for web server requests. max_body_size: "5242880" # ****************************** diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 16ce436fc..970c27264 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -6,9 +6,9 @@ # Getting Started - [Dependencies](./getting-started/dependencies.md) +- [Service Infrastructure](./getting-started/indexer-service-infrastructure.md) +- [How it Compares](./getting-started/how-it-compares.md) - [Quickstart](./getting-started/quickstart.md) -- [Hello World](./getting-started/hello-world.md) -- [Starting the Fuel Indexer](./getting-started/starting-the-fuel-indexer.md) # Reference Guide @@ -16,50 +16,39 @@ - [Manifest](./project-components/manifest.md) - [Schema](./project-components/schema.md) - [Module](./project-components/module.md) -- [Indexing](./indexing/index.md) - - [Blocks and Transactions](./indexing/blocks-and-transactions.md) - - [Receipts](./indexing/receipts.md) - - [Burn](./indexing/burn.md) - - [Call](./indexing/call.md) - - [Log](./indexing/log.md) - - [LogData](./indexing/logdata.md) - - [MessageOut](./indexing/messageout.md) - - [Mint](./indexing/mint.md) - - [Panic](./indexing/panic.md) - - [Return](./indexing/return.md) - - [ReturnData](./indexing/returndata.md) - - [Revert](./indexing/revert.md) - - [ScriptResult](./indexing/scriptresult.md) - - [Transfer](./indexing/transfer.md) - - [TransferOut](./indexing/transferout.md) -- [Data Types](./data-types/types.md) -- [GraphQL](./graphql/index.md) - - [Directives](./graphql/directives.md) - - [API Server](./graphql/api-server.md) - - [Playground](./graphql/playground.md) -- [Queries](./queries/index.md) - - [Search and Filtering](./queries/search-filtering.md) - - [Pagination](./queries/pagination.md) - - [A Full Example](./queries/full-example.md) -- [Database](./database/index.md) - - [Foreign Keys](./database/foreign-keys.md) - - [ID Types](./database/ids.md) +- [Designing a Schema](./designing-a-schema/index.md) + - [Types](./designing-a-schema/types.md) + - [Scalars](./designing-a-schema/scalars.md) + - [Directives](./designing-a-schema/directives.md) + - [Relationships](./designing-a-schema/relationships.md) +- [Indexing Fuel Types](./indexing-fuel-types/index.md) + - [Blocks](./indexing-fuel-types/blocks.md) + - [Transactions](./indexing-fuel-types/transactions.md) + - [Receipts](./indexing-fuel-types/receipts.md) +- [Indexing Custom Types](./indexing-custom-types/index.md) +- [Storing Records](./storing-records/index.md) +- [Querying](./querying/index.md) + - [Basic Queries](./querying/basic-queries.md) + - [Playground](./querying/playground.md) + - [Search and Filtering](./querying/search-and-filtering.md) + - [Pagination](./querying/pagination.md) + - [A Full Example](./querying/full-example.md) +- [Authentication](./authentication/index.md) - [forc index](./forc-index/index.md) - - [new](./forc-index/new.md) - - [check](./forc-index/check.md) + - [auth](./forc-index/auth.md) - [build](./forc-index/build.md) - - [start](./forc-index/start.md) + - [check](./forc-index/check.md) - [deploy](./forc-index/deploy.md) - - [remove](./forc-index/remove.md) - [kill](./forc-index/kill.md) - - [auth](./forc-index/auth.md) + - [new](./forc-index/new.md) + - [remove](./forc-index/remove.md) + - [start](./forc-index/start.md) - [status](./forc-index/status.md) -- [forc index postgres](./forc-postgres/index.md) +- [forc postgres](./forc-postgres/index.md) - [create](./forc-postgres/create.md) + - [drop](./forc-postgres/drop.md) - [start](./forc-postgres/start.md) - [stop](./forc-postgres/stop.md) - - [drop](./forc-postgres/drop.md) -- [Authentication](./authentication/index.md) --> # For Contributors diff --git a/docs/src/authentication/index.md b/docs/src/authentication/index.md index cee929fa3..c779e1d7e 100644 --- a/docs/src/authentication/index.md +++ b/docs/src/authentication/index.md @@ -10,10 +10,10 @@ The new authentication functionality offers a flexible and secure way for users ## Usage -Below is a demonstration of basic JWT authentication using an indexer operator at "https://beta-3-indexer.fuel.network" +Below is a demonstration of basic JWT authentication using an indexer operator at "https://beta-4-indexer.fuel.network" ```bash -forc index auth --url https://beta-3-indexer.fuel.network:29987 +forc index auth --url https://beta-4-indexer.fuel.network:29987 ``` You will first be prompted for the password for your wallet: @@ -25,7 +25,7 @@ Please enter your wallet password: After successfully entering your wallet password you should be presented with your new JWT token. ```text -✅ Successfully authenticated at https://beta-3-indexer.fuel.network:29987/api/auth/signature. +✅ Successfully authenticated at https://beta-4-indexer.fuel.network:29987/api/auth/signature. Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiODNlNjhiOTFmNDhjYWM4M.... ``` diff --git a/docs/src/data-types/types.md b/docs/src/data-types/types.md deleted file mode 100644 index 2dca9a3d3..000000000 --- a/docs/src/data-types/types.md +++ /dev/null @@ -1,60 +0,0 @@ -# Types - -Below is a mapping of GraphQL schema types to their Sway and database equivalents. - -| Sway Type | GraphQL Schema Type | Postgres Type | -|------|----------|----------| -| b256 | Address | varchar(64) | -| b256 | ContractId | varchar(64) | -| bool | Boolean | bool | -| i64 | Timestamp | timestamp | -| str[] | Blob | bytes | -| str[4] | Bytes4 | varchar(16) | -| str[8] | Bytes8 | varchar(64) | -| str[32] | Bytes32 | varchar(64) | -| str[32] | AssetId | varchar(64) | -| str[32] | MessageId | varchar(64) | -| str[32] | Salt | varchar(64) | -| u32 | UInt4 | integer | -| u64 | ID | bigint primary key | -| u64 | UInt8 | bigint | -| | Json | json | -| | Charfield | varchar(255) | -| | Blob | varchar(10485760) | - -## Example - -Let's define an `Event` struct in a Sway contract: - -```sway -struct Event { - id: u64, - address: Address, - block_height: u64, -} -``` - -The corresponding GraphQL schema to mirror this `Event` struct would resemble: - -```graphql -type Event @entity { - id: ID! - account: Address! - block_height: UInt8! -} -``` - -And finally, this GraphQL schema will generate the following Postgres schema: - -```text - Table "schema.event" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description ---------------+-------------+-----------+----------+---------+----------+-------------+--------------+------------- - id | bigint | | not null | | plain | | | - block_height | bigint | | not null | | plain | | | - address | varchar(64) | | not null | | plain | | | - object | bytea | | not null | | extended | | | -Indexes: - "event_pkey" PRIMARY KEY, btree (id) -Access method: heap -``` diff --git a/docs/src/database/ids.md b/docs/src/database/ids.md deleted file mode 100644 index 7a2b3cfce..000000000 --- a/docs/src/database/ids.md +++ /dev/null @@ -1,18 +0,0 @@ -# ID Types - -There are a few important things related to the use of IDs. - -> **Every GraphQL type defined in your schema file is required to have an id field.** -> -> - This field must be called `id` -> - The type of this `id` field must be a `u64` -> - You typically want to use the `ID` type for these `id` fields -> -> **Why must every field have an ID?** -> -> Since the Fuel Indexer uses WASM runtimes to index events, a foreign function interface (FFI) is needed to call in and out of the runtime. When these calls out of the runtime are made, a pointer is passed back to the indexer service to indicate the memory location for the `id` of the type/object/entity being saved. -> -> **Is this liable to change in the future?** -> -> Yes, ideally we'd like ID's to be of _any_ type, and we plan to work towards this in the future. 👍 -> \ No newline at end of file diff --git a/docs/src/database/index.md b/docs/src/database/index.md deleted file mode 100644 index be01ba0e4..000000000 --- a/docs/src/database/index.md +++ /dev/null @@ -1,10 +0,0 @@ -# Database - -The Fuel indexer uses [PostgreSQL](https://github.com/docker-library/postgres/blob/2f6878ca854713264ebb27c1ba8530c884bcbca5/14/bullseye/Dockerfile) as the primary database. We're open to supporting other storage solutions in the future. - -In this chapter, you can find information regarding how your data should be structured for use in the Fuel indexer: - -- [Foreign Keys](./foreign-keys.md) - - How foreign keys are handled in the Fuel indexer. -- [⚠️ IDs](./ids.md) - - Explains some conventions surrounding the usage of `ID` types diff --git a/docs/src/graphql/directives.md b/docs/src/designing-a-schema/directives.md similarity index 74% rename from docs/src/graphql/directives.md rename to docs/src/designing-a-schema/directives.md index 97fd353f4..b429006aa 100644 --- a/docs/src/graphql/directives.md +++ b/docs/src/designing-a-schema/directives.md @@ -4,10 +4,9 @@ As of this writing, the list of supported Fuel GraphQL schema directives includes: -- `@indexed` -- `@unique` -- `@join` -- `@virtual` +- `@indexed`: Denotes that a field should include a B-tree index in the database. +- `@unique`: Denotes that field should include a unique index in the database. +- `@join`: Denotes that a field has a "relationship" to another object type. ## `@indexed` @@ -65,23 +64,4 @@ type Library @entity { } ``` -A foreign key constraint will be created on `library.book` that references `book.name`, which relates the `Book`s in a `Library` to the underlying `Book` table. - -## `@virtual` - -The `@virtual` directive instructs the indexer's SQL schema builder to _not_ build SQL tables from types that include this directive on any field. - -```graphql -type Title @entity { - name: CharField! @virtual -} - -type Book @entity { - id: ID! - title: Title! -} -``` - -When SQL tables are generated for the entities above, a table will be created for `Book`, but no table will be created for `Title`. Rather, the `title` field on the `Book` object will exist on the `book` table as a `JSON` field. - -> Important: When using the `@virtual` directive with GraphQL `union` types, each member of the `union` type must either include _only_ types that are not virtual, or _only_ types that are virtual. We do not support mixing and matching virtual types with non-virtual types in unions. +A foreign key constraint will be created on `library.book` that references `book.name`, which relates the `Book`s in a `Library` to the underlying `Book` table. For more info on what exactly is happening here, please see the [Relationships](./relationships.md) section. diff --git a/docs/src/designing-a-schema/index.md b/docs/src/designing-a-schema/index.md new file mode 100644 index 000000000..9921ec675 --- /dev/null +++ b/docs/src/designing-a-schema/index.md @@ -0,0 +1,39 @@ +# Designing a Schema + +The Fuel indexer uses GraphQL in order to allow users to query for indexed data. In this chapter, you can find information on how to leverage our supported features to efficiently get the data you want. + +> ⚠️ Please note that the Fuel indexer does not support the full GraphQL specification; however, we do our best to reasonably support as much as we can. + +- [Types](./types.md) +- [Scalars](./scalars.md) +- [Directives](./directives.md) +- [Relationships](./relationships.md) + +## Supported Functionality + +While we do our best to maintain compliance with the GraphQL specification and parity with other implementations, there are a few things that are under development or will not be implemented. Here's a table describing our GraphQL functionality: + +Legend: + +- 🟩 : Functionally complete +- 🟨 : Partially complete +- 🟥 : Planned but incomplete +- ⛔ : Not planned + +| Functionality | Status | Notes | +|------|----------|-------| +| Arguments | 🟩 | [read the Search and Filtering section](../querying/search-and-filtering.md) | +| Aliases | 🟩 | | +| Fragments | 🟨 | inline fragments are currently not supported | +| Introspection | 🟩 | | +| GraphQL Playground | 🟩 | [read the Playground section](../querying/playground.md) | +| Pagination | 🟨 | [read the Pagination section](../querying/pagination.md) | +| Directives |🟨 | [read the Directives section](./directives.md) | +| List Types |🟨 | | +| Union Types |🟨 | | +| Federation |⛔ | | +| Variables | ⛔ | | +| Mutations | ⛔ | | +| Enums | 🟨 | | +| Interfaces | ⛔ | | +| Input Types| ⛔ | | diff --git a/docs/src/database/foreign-keys.md b/docs/src/designing-a-schema/relationships.md similarity index 63% rename from docs/src/database/foreign-keys.md rename to docs/src/designing-a-schema/relationships.md index c92c69982..590defc69 100644 --- a/docs/src/database/foreign-keys.md +++ b/docs/src/designing-a-schema/relationships.md @@ -1,7 +1,6 @@ -# Foreign Keys +# Relationships -- The Fuel indexer service supports foreign key constraints and relationships using a combination of GraphQL schema and a database. -- There are two types of uses for foreign keys - _implicit_ and _explicit_. +The Fuel indexer service supports foreign key relationships and constraints. There are two types of relationship specifications: _implicit_ and _explicit_. > IMPORTANT: > @@ -18,35 +17,31 @@ Let's learn how to use each foreign key type by looking at some GraphQL schema e ### Implicit foreign keys ```graphql -type Book @entity { +type Library @entity { id: ID! - name: Bytes8! + name: Charfield! } -type Library @entity { +type Book @entity { id: ID! - book: Book! + library: Library! } ``` -#### Implicit foreign key breakdown - -Given the above schema, two entities will be created: a `Book` entity, and a `Library` entity. As you can see, we add the `Book` entity as an attribute on the `Library` entity, thus conveying that we want a one-to-many or one-to-one relationship between `Library` and `Book`. This means that for a given `Library`, we may also fetch one or many `Book` entities. It also means that the column `library.book` will be an integer type that references `book.id`. +Given the above schema, two entities will be created: a `Book` entity, and a `Library` entity. As you can see, we add the `Book` entity as an attribute on the `Library` entity, thus conveying that we want a one-to-many or one-to-one relationship between `Library` and `Book`. This means that for a given `Book`, we may also fetch the associated `Library` entity. It also means that the field `Book.library` will be an `ID` scalar type that references `Library.id`. ### Explicit foreign keys ```graphql -type Book @entity { +type Library @entity { id: ID! - name: Bytes8! @unique + name: Charfield! @unique } -type Library @entity { +type Book @entity { id: ID! - book: Book! @join(on:name) + library: Library! join(on:name) } ``` -#### Explicit foreign key breakdown - -For the most part, this works the same way as implicit foreign key usage. However, as you can see, instead of implicitly using `book.id` as the reference column for our `Book` object, we're instead explicitly specifying that we want `book.name` to serve as our foreign key. Also, please note that since we're using `book.name` in our foreign key constraint, that column is required to be unique (via the `@unique` directive). +For the most part, this works the same way as implicit foreign key usage. However, as you can see, instead of implicitly using `Library.id` as the reference column for our `Library` field type on the `Book` object, we're _explicitly_ specifying that we want `Library.name` to serve as our foreign key for the `Book.library` field. Also, please note that since we're using `Library.name` in our foreign key constraint, that column is required to be unique (via the `@unique` directive). diff --git a/docs/src/designing-a-schema/scalars.md b/docs/src/designing-a-schema/scalars.md new file mode 100644 index 000000000..d026af518 --- /dev/null +++ b/docs/src/designing-a-schema/scalars.md @@ -0,0 +1,36 @@ +# Scalars + +The Fuel indexer has a collection of GraphQL scalars that cover virtually any value type in use on the Fuel network. The following list contains each GraphQL scalar type along with its equivalent Rust type. + +| GraphQL Scalar | Rust Type | Notes | +--- | --- | --- +| Address | `u8[32]` | +| AssetId | `u8[32]` | +| Blob | `Vec` | Byte blob of arbitary size | +| BlockId | `u8[32]` | 32-byte block ID | +| Boolean | `bool` | +| Bytes4 | `u8[4]` | +| Bytes8 | `u8[8]` | +| Bytes32 | `u8[32]` | +| Bytes64 | `u8[64]` | +| Charfield | `String` | String of arbitrary size | +| ContractId | `u8[32]` | +| HexString | `Vec` | Byte blob of arbitrary size | +| ID | `SizedAsciiString<64>` | Alias of `UID` +| Int1 | `i8` | +| Int4 | `i32` | +| Int8 | `i64` | +| Int16 | `i128` | +| Json | `String` | JSON string of arbitary size | +| MessageId | `u8[32]` | +| Nonce | `u8[32]` | +| Salt | `u8[32]` | +| Signature | `u8[64]` | 64-byte signature | +| Tai64Timestamp | `Tai64` | `Tai64` timestamp | +| Timestamp | `u64` | +| UID | `SizedAsciiString<64>` | 32-byte unique ID | +| UInt1 | `u8` | +| UInt4 | `u32` | +| UInt8 | `u64` | +| UInt16 | `u128` | +| Virtual | `String` | Used to store types tagged with `@virtual` directive | diff --git a/docs/src/designing-a-schema/types.md b/docs/src/designing-a-schema/types.md new file mode 100644 index 000000000..98326a7a9 --- /dev/null +++ b/docs/src/designing-a-schema/types.md @@ -0,0 +1,123 @@ +# Types + +## Objects + +Object types are the most commonly used type in indexer GraphQL schema. Each object type marked with an `@entity` directive will be converted into a SQL table. + +```graphql +type Account @entity { + id: ID! + address: Address! + balance: UInt8! +} +``` + +This `Account` object type from the GraphQL schema, might be used in an indexer module like so: + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_event(event: Event) { + let address = Address::default(); + let balance = 0; + let account = Account::new(address, balance); + account.save(); + } +} +``` + +## Enums + +Enum types are simply implemented as String types. + +```graphql +enum SignatureLabel { + Multi + Single +} +``` + +> Enum types in relation to Fuel indexer's implementation are just `String` types used primarily to label object types. There is no other way that `enum` types should be used at this time. +This `SignatureLabel` object type from the GraphQL schema, might be used in an indexer module like so: + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_event(event: Event) { + let label = SignatureLabel::Multi; + assert_eq!(label.to_string(), "SignatureLabel::Multi".to_string()); + } +} +``` + +## Unions + +Union types are unique in that any type marked as a `union` will be converted into an Object type, who's fields are the unique set of fields over all members of the union. + +```graphql +enum TransactionLabel { + Create + Script + Mint +} + +type CreateTransaction @entity { + id: ID! + bytecode_length: UInt8! + contract_id: ContractId! + label: TransactionLabel! +} + +type ScriptTransaction @entity { + id: ID! + maturity: UInt8! + label: TransactionLabel! +} + +type MintTransaction @entity { + id: ID! + metadata: Json + label: TransactionLabel! +} + +union Transaction = CreateTransaction | ScriptTransaction | MintTransaction +``` + +The `Transaction` union type above, will internally produce the following object type: + +```graphql +type Transaction @entity { + id: ID! + bytecode_length: UInt8! + contract_id: ContractId! + label: TransactionLabel! + maturity: UInt8! + metadata: Json +} +``` + +> IMPORTANT: Note the order of the fields in the derived `Transaction` object type: the fields are ordered according to the unique set of fields from each of the union's members. +> +> The `id`, `bytecode_length`, `contract_id`, and `label` fields come first, from the `CreateTransaction` object type. Next comes the `maturity` field from the `ScriptTransaction` object - because the `ScriptTransaction`'s `id` and `label` fiels are already a part of the derived `Transaction` object, courtesy of the `CreateTransaction` object type. Finally, comes the `metadata` field, as part of the `MintTransaction` object type. +This `Transaction` union type from the GraphQL schema, might be used in an indexer module like so: + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_event(event: Event) { + let bytecode_length = 1024; + let contract_id = ContractId::default(); + let label = TransactionLabel::Create; + let maturity = 10000000; + let metadata = None; + let transaction = Transaction::new(bytecode_length, contract_id, label, maturity, metadata); + transaction.save(); + } +} +``` diff --git a/docs/src/forc-index/deploy.md b/docs/src/forc-index/deploy.md index 896369976..319a5696e 100644 --- a/docs/src/forc-index/deploy.md +++ b/docs/src/forc-index/deploy.md @@ -3,7 +3,7 @@ Deploy an indexer to an indexer service. ```bash -forc index deploy --url https://beta-3-indexer.fuel.network +forc index deploy --url https://beta-4-indexer.fuel.network ``` ```text diff --git a/docs/src/forc-index/index.md b/docs/src/forc-index/index.md index c582b7aa9..45bc1cf14 100644 --- a/docs/src/forc-index/index.md +++ b/docs/src/forc-index/index.md @@ -15,12 +15,16 @@ OPTIONS: -V, --version Print version information SUBCOMMANDS: - build Build an indexer - check Get status checks on all indexer components - deploy Deploy an indexer asset bundle to a remote or locally running indexer server - help Print this message or the help of the given subcommand(s) - init Create a new indexer project in the current directory - new Create a new indexer project in a new directory - remove Stop and remove a running indexer - start Start a local indexer service + auth Authenticate against an indexer service + build Build an indexer + check Check for Fuel indexer components + deploy Deploy an indexer to an indexer service + help Print this message or the help of the given subcommand(s) + kill Kill the indexer process. Note that this command will kill any process listening + on the default indexer port or the port specified by the `--port` flag + new Create a new indexer project in a new directory + postgres Fuel Postgres Orchestrator + remove Stop and remove a running indexer + start Standalone binary for the Fuel indexer service + status Check the status of a registered indexer ``` diff --git a/docs/src/forc-index/remove.md b/docs/src/forc-index/remove.md index 7f01e9c75..5ceaf27df 100644 --- a/docs/src/forc-index/remove.md +++ b/docs/src/forc-index/remove.md @@ -3,7 +3,7 @@ Stop and remove a running indexer. ```bash -forc index remove --url https://beta-3-indexer.fuel.network +forc index remove --url https://beta-4-indexer.fuel.network ``` ```text diff --git a/docs/src/forc-index/start.md b/docs/src/forc-index/start.md index bd208bf35..826f1e60e 100644 --- a/docs/src/forc-index/start.md +++ b/docs/src/forc-index/start.md @@ -14,7 +14,7 @@ USAGE: OPTIONS: --accept-sql-queries - Allow the web API to accept raw SQL queries. + Allow the web server to accept raw SQL queries. --auth-enabled Require users to authenticate for some operations. @@ -66,7 +66,7 @@ OPTIONS: Indexer config file. --max-body-size - Max body size for web API requests. [default: 5242880] + Max body size for web server requests. [default: 5242880] --metering-points The number of WASM opcodes after which the indexer's event handler will stop execution. diff --git a/docs/src/forc-index/status.md b/docs/src/forc-index/status.md index 11e56685e..675568ca8 100644 --- a/docs/src/forc-index/status.md +++ b/docs/src/forc-index/status.md @@ -3,7 +3,7 @@ Check the status of a registered indexer. ```bash -forc index status --url https://beta-3-indexer.fuel.network +forc index status --url https://beta-4-indexer.fuel.network ``` ```text diff --git a/docs/src/getting-started/dependencies.md b/docs/src/getting-started/dependencies.md index 748d6e54a..442de775f 100644 --- a/docs/src/getting-started/dependencies.md +++ b/docs/src/getting-started/dependencies.md @@ -1,32 +1,34 @@ # Dependencies -To run the Fuel indexer, you'll need to install a few dependencies on your system: +> This guide covers some of the basics with regard to installing dependencies for the Fuel indexer service. However, note that this guide is meant to be a general overview for most platforms and by no means covers all platforms. +> +> If you're having trouble with dependencies on your system, we recommend that you use `docker`. -- [`fuelup`](#fuelup), the Fuel toolchain manager -- A supported [database](#postgresql) - - As of now we only support Postgres -- The [`wasm32-unknown-unknown`](#wasm) `rustup` target -- [`wasm-snip`](#wasm), a utility for stripping symbols from WebAssemly binaries. +To run the Fuel indexer, you'll need to install a few dependencies on your system: -If you don't want to install a database directly onto your system, you can use Docker to run it as an isolated container. You can install it by following the [install instructions](https://docs.docker.com/get-docker/). For reference purposes, we provide a [`docker compose` file](https://github.com/FuelLabs/fuel-indexer/blob/develop/scripts/docker-compose.yaml) that runs a Postgres database and the Fuel indexer service. +1. The [Rust programming language, with its package manager](https://www.rust-lang.org/tools/install) +2. [`fuelup`](#fuelup), the Fuel toolchain manager +3. A [PostgresQL](#postgresql) server backend +4. The [`wasm32-unknown-unknown`](#web-assembly-wasm) `rustup` target +5. [`wasm-snip`](#web-assembly-wasm), a utility for stripping symbols from WebAssemly binaries. -> IMPORTANT: Note for Apple Silicon macOS users: -> -> Using the Fuel indexer through Docker on Apple Silicon systems is currently not supported. +> If you don't want to install a database directly onto your system, you can use Docker to run a database in an isolated container. You can install Docker by following its [installation instructions](https://docs.docker.com/get-docker/). > -> We're working to bring support to these systems. - -Also, it's assumed that you have the Rust programming language installed on your system. If that is not the case, please refer to the [Rust installation instructions](https://www.rust-lang.org/tools/install) for more information. +> For reference purposes, we provide a [`docker compose` file](https://github.com/FuelLabs/fuel-indexer/blob/develop/scripts/docker-compose.yaml) that comes with a PostgresSQL server and a Fuel indexer service. ## `fuelup` -We strongly recommend that you use the Fuel indexer through [`forc`, the Fuel orchestrator](https://fuellabs.github.io/sway/master/book/forc/index.html). You can get `forc` (and other Fuel components) by way of [`fuelup`, the Fuel toolchain manager](https://fuellabs.github.io/fuelup/latest). Install `fuelup` by running the following command, which downloads and runs the installation script. +We strongly recommend that you use the Fuel indexer that's made available via [`forc`, the Fuel orchestrator](https://fuellabs.github.io/sway/master/book/forc/index.html). You can get `forc` (and other Fuel components) by way of [`fuelup`, the Fuel toolchain manager](https://fuellabs.github.io/fuelup/latest). + +Install `fuelup` by running the following command, which downloads and runs the installation script. ```bash curl --proto '=https' --tlsv1.2 -sSf https://install.fuel.network/fuelup-init.sh | sh ``` -After `fuelup` has been installed, the `forc index` command and `fuel-indexer` binaries will be available on your system. +After `fuelup` has been installed, the `forc index` command and `fuel-indexer` binaries should be available on your system. + +> A simple `forc index check` can be used to show which indexer components you have installed via `fuelup`. ## PostgreSQL @@ -34,7 +36,7 @@ The Fuel indexer requires the use of a database. We currently support [PostgresS > IMPORTANT: Fuel Indexer users on most platforms don't need to explicitly install PostgresQL software via a package manager. When starting the indexer service via `forc index start` simply pass the `--embedded-database` flag in order to have the indexer service download and start an embedded PostgresQL instance via [`forc index postgres`](../forc-postgres/index.md). > -> However if users or devs would like to install PostgresQL via some package manager, feel free to checkout the more detailed installation steps below. +> However note that this `--embedded-database` functionality can be a bit brittle or flaky on some platforms, so alternative methods of installing or using PostgresQL are briefly mentioned below. ### macOS @@ -42,11 +44,13 @@ On macOS systems, you can install PostgreSQL through Homebrew. If it isn't prese Once installed, you can add PostgreSQL to your system by running `brew install postgresql`. -## WASM +## Web Assembly (WASM) -Two additonal cargo components will be required to build your indexers: `wasm-snip` and the `wasm32-unknown-unknown` target. +Two additional cargo components will be required to build your indexers: `wasm-snip` and the `wasm32-unknown-unknown` target. -> As of this writing, there is a small bug in newly built Fuel indexer WASM modules that produces a WASM runtime error due an errant upstream dependency. For now, you can use `wasm-snip` to remove the errant symbols from the WASM module. An example can be found in the related script [here](https://github.com/FuelLabs/fuel-indexer/blob/develop/scripts/stripper.bash). +> As of this writing, there is a small bug in newly built Fuel indexer WASM modules that produces a WASM runtime error due an errant upstream dependency. For now, you can use `wasm-snip` to remove the errant symbols from the WASM module, and prevent this issue from happening. An example can be found in the related script [here](https://github.com/FuelLabs/fuel-indexer/blob/develop/scripts/stripper.bash). +> +> Note that since `wasm-snip` strips Web Assembly related symbols, users will temporarily not be allowed to include other WASM-friendly crates (e.g., [`chrono`](https://docs.rs/chrono/latest/chrono/)) in their indexers. ### `wasm-snip` diff --git a/docs/src/getting-started/hello-world.md b/docs/src/getting-started/hello-world.md deleted file mode 100644 index 51ba30a85..000000000 --- a/docs/src/getting-started/hello-world.md +++ /dev/null @@ -1,19 +0,0 @@ -# Hello World - -Below is a simple "Hello World" Sway contract that we want to index. This contract has a function called `new_greeting` that logs a `Greeting` and a `Person`. - -```rust, ignore -{{#include ../../../examples/hello-world/contracts/greeting/src/main.sw}} -``` - -We can define our schema like this in the schema file: - -```graphql -{{#include ../../../examples/hello-world/hello-indexer/schema/hello_indexer.schema.graphql}} -``` - -Now that our schema is defined, here is how we can implement the WASM module in our `lib.rs` file: - -```rust,ignore -{{#include ../../../examples/hello-world/hello-indexer/src/lib.rs}} -``` diff --git a/docs/src/getting-started/how-it-compares.md b/docs/src/getting-started/how-it-compares.md new file mode 100644 index 000000000..fb392f6ca --- /dev/null +++ b/docs/src/getting-started/how-it-compares.md @@ -0,0 +1,42 @@ +# How it Compares + +Since many users may be familiar with indexing by using a solution like The Graph, it may be helpful to provide a comparison between it and the Fuel indexer. Generally, the biggest conceptual differences between the two are as follows: + +- The Fuel indexer does not support publishing indexers to decentralized networks. That being said, the Fuel indexer is developed with the intention of allowing anyone to run an instance and host whatever indexers they want. +- Contracts on the Fuel network can be indexed without the need to add additional events. Whether a user wanted to index information from the very start of a contract or a recent block, the process is the same: define the schema and manifest, write custom handler logic, and deploy to an indexer service. + +Legend: + +- 🟩 : Functionally complete +- 🟨 : Partially complete +- 🟥 : Planned but incomplete +- ⛔ : Not planned + + + +| Feature | The Graph | Fuel Indexer | Notes | +|:-:|:-:|:-:|:-:| +| Hosted Indexers | 🟩 | 🟩 | | +| WASM Execution | 🟩 | 🟩 | | +| Native Execution | 🟥 | 🟩 | | +| Handlers | 🟩 | 🟩 | see [Indexing Fuel Types](../indexing-fuel-types/index.md) and [Indexing Custom Types](../indexing-custom-types/index.md)| +| Updateable Schemas | 🟩 | 🟩 | | +| API Authentication | 🟩 | 🟩 | | +| Starting Block Configuration | 🟩 | 🟩 | | +| Grafted Indexes | 🟩 | 🟥 | | +| Index Ownership Transfer | 🟩 | 🟥 | | +| Unit Testing Framework | 🟩 | 🟥 | Users are able to use `cargo test` | +| Querying: Sorting | 🟩 | 🟩 | | +| Querying: Pagination | 🟩 | 🟩 | | +| Querying: Filtering | 🟩 | 🟩 | | +| Querying: Time Travel | 🟩 | 🟥 | | +| Querying: Fulltext Search | 🟩 | 🟥 | | +| Querying: GraphQL Validation Spec | 🟩 | 🟨 | | +| Schema: Enums | 🟩 | 🟩 | | +| Schema: One-to-one relationships | 🟩 | 🟩 | | +| Schema: One-to-many relationships| 🟩 | 🟩 | | +| Schema: Many-to-many relationships | 🟩 | 🟩 | | +| Schema: Reverse Lookup | 🟩 | 🟥 | | +| AssemblyScript Support | 🟩 | ⛔ | | +| Admin Portal UI | 🟩 | ⛔ | | +| Decentralized Hosting | 🟩 | ⛔ | | diff --git a/docs/src/getting-started/indexer-service-infrastructure.md b/docs/src/getting-started/indexer-service-infrastructure.md new file mode 100644 index 000000000..13a5eda7d --- /dev/null +++ b/docs/src/getting-started/indexer-service-infrastructure.md @@ -0,0 +1,280 @@ +# Indexer Service Infrastructure + +- [Service Components](#components) +- [Fuel Indexer Service](#fuel-indexer-service) + - [Starting the service via CLI options](#using-cli-options-indexer-service) + - [Starting the service via a config file](#using-a-configuration-file-indexer-service) +- [Fuel Indexer Web Server](#web-api-server) + - [Starting the service via CLI options](#using-cli-options-web-server) + - [Starting the service via a config file](#using-a-configuration-file-web-server) + +A Fuel indexer service instance requires just three components: + +- a **Fuel Node**: Custom indexers monitor incoming blocks via a Fuel GraphQL server and extract information about the state of the Fuel blockchain. + +- a **PostgresQL database server**: Extracted information is saved into a database. + +- a **Web Server**: dApps can query indexers for up-to-date information and operators can deploy/remove indexers as needed. + +--- + +## Components + +| Component | Default Host | Default Port | CLI Argument | Environment Variable | +|---|---|---|---|---| +| Fuel Node | localhost | 4000 | `--fuel-node-{host,port}` | $FUEL_NODE_{HOST,PORT} | +| Database Server | localhost | 5432 | `--postgres-{username,database,password,host,port}` | $POSTGRES_{USERNAME,DATABASE,PASSWORD,HOST,PORT} | +| Indexer Service Web API | localhost | 29987 | `--web-api-{host,port}` | $WEB_API_{HOST,PORT} | + +--- + +## Fuel Indexer Service + +The Fuel indexer service will connect to any Fuel GraphQL server, which means you can run your own node or use a node provided by Fuel. The indexer service web server is included with the Fuel indexer; it's available as soon as the indexer is started through `fuel-indexer run`. The only component that isn't provided for you is a Postgres database server. You should set up a server according to your own needs and specifications. + +> You can start the indexer service with an array of CLI options. Note that most (if not all) of these options include sensible defaults. + +### Using CLI options (Indexer Service) + +```bash +fuel-indexer run --help +``` + +```text +Standalone binary for the fuel indexer service. + +USAGE: + fuel-indexer run [OPTIONS] + +OPTIONS: + --accept-sql-queries + Allow the web server to accept raw SQL queries. + + --auth-enabled + Require users to authenticate for some operations. + + --auth-strategy + Authentication scheme used. + + --block-page-size + Amount of blocks to return in a request to a Fuel node. [default: 10] + + -c, --config + Indexer service config file. + + --database + Database type. [default: postgres] [possible values: postgres] + + --embedded-database + Automatically create and start database using provided options or defaults. + + --fuel-node-host + Host of the running Fuel node. [default: localhost] + + --fuel-node-port + Listening port of the running Fuel node. [default: 4000] + + -h, --help + Print help information + + --indexer-net-config + Allow network configuration via indexer manifests. + + --jwt-expiry + Amount of time (seconds) before expiring token (if JWT scheme is specified). + + --jwt-issuer + Issuer of JWT claims (if JWT scheme is specified). + + --jwt-secret + Secret used for JWT scheme (if JWT scheme is specified). + + --local-fuel-node + Start a local Fuel node. + + --log-level + Log level passed to the Fuel Indexer service. [default: info] [possible values: info, + debug, error, warn] + + -m, --manifest + Indexer config file. + + --max-body-size + Max body size for web server requests. [default: 5242880] + + --metering-points + The number of WASM opcodes after which the indexer's event handler will stop execution. + [default: 30000000000] + + --metrics + Use Prometheus metrics reporting. + + --postgres-database + Postgres database. + + --postgres-host + Postgres host. + + --postgres-password + Postgres password. + + --postgres-port + Postgres port. + + --postgres-user + Postgres username. + + --rate-limit + Enable rate limiting. + + --rate-limit-request-count + Maximum number of requests to allow over --rate-limit-window.. + + --rate-limit-window-size + Number of seconds over which to allow --rate-limit-rps. + + --replace-indexer + Whether to allow replacing an existing indexer. If not specified, an attempt to deploy + over an existing indexer results in an error. + + --run-migrations + Run database migrations before starting service. + + --stop-idle-indexers + Prevent indexers from running without handling any blocks. + + -v, --verbose + Enable verbose logging. + + -V, --version + Print version information + + --web-api-host + Web API host. [default: localhost] + + --web-api-port + Web API port. [default: 29987] + +``` + +### Using a configuration file (Indexer Service) + +```yaml +{{#include ../../../config.yaml}} +``` + +--- + +## Web API Server + +The `fuel-indexer-api-server` crate of the Fuel indexer contains a standalone web server that acts as a queryable endpoint on top of the database. Note that the main `fuel-indexer` binary of the indexer project also contains the same web server endpoint. + +> The `fuel-indexer-api-server` crate offers a _standalone_ web server endpoint, whereas the API endpoint offered in `fuel-indexer` is bundled with other Fuel indexer functionality (e.g., execution, handling, data-layer construction, etc). Offering the API server as a separate piece allows users to separate components and run them on different systems, if desired. + +### Using CLI Options (Web Server) + +> You can start the indexer service with an array of CLI options. Note that most (if not all) of these options include sensible defaults. + +```bash +fuel-indexer-api-server run --help +``` + +```text +Fuel indexer web server + +USAGE: + fuel-indexer-api-server run [OPTIONS] + +OPTIONS: + --accept-sql-queries + Allow the web server to accept raw SQL queries. + + --auth-enabled + Require users to authenticate for some operations. + + --auth-strategy + Authentication scheme used. [possible values: jwt] + + -c, --config + API server config file. + + --database + Database type. [default: postgres] [possible values: postgres] + + --fuel-node-host + Host of the running Fuel node. [default: localhost] + + --fuel-node-port + Listening port of the running Fuel node. [default: 4000] + + -h, --help + Print help information + + --jwt-expiry + Amount of time (seconds) before expiring token (if JWT scheme is specified). + + --jwt-issuer + Issuer of JWT claims (if JWT scheme is specified). + + --jwt-secret + Secret used for JWT scheme (if JWT scheme is specified). + + --log-level + Log level passed to the Fuel Indexer service. [default: info] [possible values: info, + debug, error, warn] + + --max-body-size + Max body size for web requests. [default: 5242880] + + --metrics + Use Prometheus metrics reporting. + + --postgres-database + Postgres database. + + --postgres-host + Postgres host. + + --postgres-password + Postgres password. + + --postgres-port + Postgres port. + + --postgres-user + Postgres username. + + --rate-limit + Enable rate limiting. + + --rate-limit-request-count + Maximum number of requests to allow over --rate-limit-window.. + + --rate-limit-window-size + Number of seconds over which to allow --rate-limit-rps. + + --run-migrations + Run database migrations before starting service. + + -v, --verbose + Enable verbose logging. + + -V, --version + Print version information + + --web-api-host + Web API host. [default: localhost] + + --web-api-port + Web API port. [default: 29987] +``` + +### Using A Configuration File (Web Server) + +To run the standalone Fuel indexer web server server using a configuration file: + +```bash +fuel-indexer-api-server run --config config.yaml +``` + +In the above example, `config.yaml` is based on [the default service configuration file](https://github.com/FuelLabs/fuel-indexer/blob/develop/config.yaml). diff --git a/docs/src/getting-started/quickstart.md b/docs/src/getting-started/quickstart.md index 323a4eae5..6d8d2367b 100644 --- a/docs/src/getting-started/quickstart.md +++ b/docs/src/getting-started/quickstart.md @@ -3,8 +3,10 @@ In this tutorial you will: 1. Bootstrap your development environment. -2. Create, build, and deploy an indexer to an indexer service hooked up to Fuel's `beta-3` testnet. -3. Query your newly created index for data using GraphQL. +2. Create, build, and deploy an indexer to an indexer service hooked up to Fuel's `beta-4` testnet. +3. Query your indexer's newly created index for data using GraphQL. + +--- ## 1. Setting up your environment @@ -34,6 +36,8 @@ Additionally, you'll need the `wasm-snip` utility in order to remove errant symb cargo install wasm-snip ``` +--- + ## 2. Using the `forc-index` plugin The primary means of interfacing with the Fuel indexer for indexer development is the [`forc-index` CLI tool](https://crates.io/crates/forc-index). `forc-index` is a [`forc`](https://github.com/FuelLabs/sway/tree/master/forc) plugin specifically created to interface with the Fuel indexer service. Since we already installed `fuelup` in a previous step [1.1](#11-install-fuelup), we should be able to check that our `forc-index` binary was successfully installed and added to our `PATH`. @@ -98,7 +102,9 @@ To quickly setup and bootstrap the PostgreSQL database that we'll need, we'll us We can quickly create a bootstrapped database and start the Fuel indexer service by running the following command: -> IMPORTANT: Below we're specifying our Postgres hostname as `--postgres-host postgresql`, but you will need to be specific to your own Postgres instance details (see `forc index start --help` for more details). You can try using the `--embedded-database` flag in order to quickly use an embedded instance of Postgres, but this is flaky and often depends on what platform you're using. +> IMPORTANT: Below we're specifying our Postgres hostname as `--postgres-host postgresql`, but you might need to change this based on your own Postgres instance details (see `forc index start --help` for more details). +> +> Additionally, you can try using the `--embedded-database` flag in order to quickly use an embedded instance of Postgres, but this flag can be flaky, and its ease of use often depends on what platform you're using. ```bash forc index start --fuel-node-host beta-4.fuel.network --fuel-node-port 80 --run-migrations --postgres-host postgresql @@ -124,14 +130,17 @@ You should see output indicating the successful creation of a database and start Now that we have our development environment set up, the next step is to create an indexer. ```bash -forc index new hello-indexer --namespace fuelLabs && cd hello-indexer +forc index new hello-indexer --namespace fuellabs && cd hello-indexer ``` -> The `namespace` of your project is a required option. You can think of a `namespace` as your organization name or company name. Your project might contain one or many indexers all under the same `namespace`. For a complete list of options passed to `forc index new`, see [here](../forc-index/new.md) +> The `namespace` of your project is a required option. You can think of a `namespace` as your organization name or company name. Your project might contain one or many indexers all under the same `namespace`. For a complete list of options passed to `forc index new`, see [here](../forc-index/new.md). ```text forc index new hello-indexer --namespace FuelLabs +✅ Successfully created indexer + + ███████╗██╗ ██╗███████╗██╗ ██╗███╗ ██╗██████╗ ███████╗██╗ ██╗███████╗██████╗ ██╔════╝██║ ██║██╔════╝██║ ██║████╗ ██║██╔══██╗██╔════╝╚██╗██╔╝██╔════╝██╔══██╗ █████╗ ██║ ██║█████╗ ██║ ██║██╔██╗ ██║██║ ██║█████╗ ╚███╔╝ █████╗ ██████╔╝ @@ -139,51 +148,57 @@ forc index new hello-indexer --namespace FuelLabs ██║ ╚██████╔╝███████╗███████╗ ██║██║ ╚████║██████╔╝███████╗██╔╝ ██╗███████╗██║ ██║ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ + An easy-to-use, flexible indexing service built to go fast. 🚗💨 + ---- Read the Docs: - Fuel Indexer: https://github.com/FuelLabs/fuel-indexer - Fuel Indexer Book: https://fuellabs.github.io/fuel-indexer/latest - Sway Book: https://fuellabs.github.io/sway/latest -- Rust SDK Book: https://fuellabs.github.io/fuels-rs/latest +- Rust SDK Book: https://rust.fuel.network + Join the Community: -- Follow us @SwayLang: https://twitter.com/fuellabs_ +- Follow us @Fuel: https://twitter.com/fuel_network - Ask questions in dev-chat on Discord: https://discord.com/invite/xfpK4Pe Report Bugs: - Fuel Indexer Issues: https://github.com/FuelLabs/fuel-indexer/issues/new Take a quick tour. + +`forc index auth` + Authenticate against an indexer service. +`forc index build` + Build an indexer. `forc index check` List indexer components. +`forc index deploy` + Deploy an indexer. +`forc index kill` + Kill a running Fuel indexer process on a given port. `forc index new` Create a new indexer. -`forc index start` - Start a local indexer service. -`forc index build` - Build your indexer. -`forc index deploy` - Deploy your indexer. `forc index remove` Stop a running indexer. -`forc index auth` - Authenticate against an indexer service. +`forc index start` + Start a local indexer service. `forc index status` Check the status of an indexer. ``` ### 2.4 Deploying our indexer -At this point, we have a brand new indexer that will index some blocks and transactions. And with both our database and Fuel indexer services up and running, all that's left is to build and deploy the indexer in order to see it in action. Let's build and deploy our indexer: +At this point, we have a brand new indexer that will index some blocks and transactions. And with both our database and Fuel indexer services up and running, all that's left to do is to build and deploy the indexer in order to see it in action. Let's build and deploy our indexer: ```bash forc index deploy ``` -> IMPORTANT: `forc index deploy` by defaults runs `forc index build` prior to deploying the indexer. The same result can be produced by running `forc index build` then subsequently running `forc index deploy`. +> IMPORTANT: `forc index deploy` by defaults runs `forc index build` prior to deploying the indexer. The same result can be produced by running `forc index build` then subsequently running `forc index deploy`. For more info, checkout the [`forc index deploy`](./../forc-index/deploy.md) command. If all goes well, you should see the following: @@ -197,7 +212,7 @@ If all goes well, you should see the following: With our indexer deployed, we should be able to query for newly indexed data after a few seconds. -Below, we write a simple GraphQL query that simply returns a few fields from all transactions that we've indexed. +Below, we write a simple GraphQL query that returns a few fields from all transactions that we've indexed. You can open your GraphQL query playground at `http://127.0.0.1:29987/api/playground/fuellabs/hello_indexer` and submit the following GraphQL query. @@ -244,3 +259,5 @@ The response you get should resemble: ### Finished! 🥳 Congrats, you just created, built, and deployed your first indexer on the world's fastest execution layer. + +For more info on how indexers work, please checkout the [reference guide](./../project-components/index.md). diff --git a/docs/src/getting-started/starting-the-fuel-indexer.md b/docs/src/getting-started/starting-the-fuel-indexer.md deleted file mode 100644 index 50b16b985..000000000 --- a/docs/src/getting-started/starting-the-fuel-indexer.md +++ /dev/null @@ -1,126 +0,0 @@ -# Starting the Fuel Indexer - -## Using CLI options - -```text -Standalone binary for the fuel indexer service. - -USAGE: - fuel-indexer run [OPTIONS] - -OPTIONS: - --accept-sql-queries - Allow the web API to accept raw SQL queries. - - --auth-enabled - Require users to authenticate for some operations. - - --auth-strategy - Authentication scheme used. - - --block-page-size - Amount of blocks to return in a request to a Fuel node. [default: 10] - - -c, --config - Indexer service config file. - - --database - Database type. [default: postgres] [possible values: postgres] - - --embedded-database - Automatically create and start database using provided options or defaults. - - --fuel-node-host - Host of the running Fuel node. [default: localhost] - - --fuel-node-port - Listening port of the running Fuel node. [default: 4000] - - -h, --help - Print help information - - --indexer-net-config - Allow network configuration via indexer manifests. - - --jwt-expiry - Amount of time (seconds) before expiring token (if JWT scheme is specified). - - --jwt-issuer - Issuer of JWT claims (if JWT scheme is specified). - - --jwt-secret - Secret used for JWT scheme (if JWT scheme is specified). - - --local-fuel-node - Start a local Fuel node. - - --log-level - Log level passed to the Fuel Indexer service. [default: info] [possible values: info, - debug, error, warn] - - -m, --manifest - Indexer config file. - - --max-body-size - Max body size for web API requests. [default: 5242880] - - --metering-points - The number of WASM opcodes after which the indexer's event handler will stop execution. - [default: 30000000000] - - --metrics - Use Prometheus metrics reporting. - - --postgres-database - Postgres database. - - --postgres-host - Postgres host. - - --postgres-password - Postgres password. - - --postgres-port - Postgres port. - - --postgres-user - Postgres username. - - --rate-limit - Enable rate limiting. - - --rate-limit-request-count - Maximum number of requests to allow over --rate-limit-window.. - - --rate-limit-window-size - Number of seconds over which to allow --rate-limit-rps. - - --replace-indexer - Whether to allow replacing an existing indexer. If not specified, an attempt to deploy - over an existing indexer results in an error. - - --run-migrations - Run database migrations before starting service. - - --stop-idle-indexers - Prevent indexers from running without handling any blocks. - - -v, --verbose - Enable verbose logging. - - -V, --version - Print version information - - --web-api-host - Web API host. [default: localhost] - - --web-api-port - Web API port. [default: 29987] - -``` - -## Using a configuration file - -```yaml -{{#include ../../../config.yaml}} -``` diff --git a/docs/src/graphql/api-server.md b/docs/src/graphql/api-server.md deleted file mode 100644 index 5fe77b42d..000000000 --- a/docs/src/graphql/api-server.md +++ /dev/null @@ -1,108 +0,0 @@ -# GraphQL API Server - -- The `fuel-indexer-api-server` crate of the Fuel indexer contains a standalone GraphQL API server that acts as a queryable endpoint on top of the database. -- Note that the main `fuel-indexer` binary of the indexer project also contains a queryable GraphQL API endpoint. - -> The `fuel-indexer-api-server` crate offers a _standalone_ GraphQL API endpoint, whereas the GraphQL endpoint offered in `fuel-indexer` is bundled with other Fuel indexer functionality (e.g., execution, handling, data-layer contruction, etc). - -## Usage - -To run the standalone Fuel indexer GraphQL API server using a configuration file: - -```bash -fuel-indexer-api-server run --config config.yaml -``` - -In the above example, `config.yaml` is based on [the default service configuration file](https://github.com/FuelLabs/fuel-indexer/blob/develop/config.yaml). - -## Options - -```text -Fuel indexer web API - -USAGE: - fuel-indexer-api-server run [OPTIONS] - -OPTIONS: - --accept-sql-queries - Allow the web API to accept raw SQL queries. - - --auth-enabled - Require users to authenticate for some operations. - - --auth-strategy - Authentication scheme used. [possible values: jwt] - - -c, --config - API server config file. - - --database - Database type. [default: postgres] [possible values: postgres] - - --fuel-node-host - Host of the running Fuel node. [default: localhost] - - --fuel-node-port - Listening port of the running Fuel node. [default: 4000] - - -h, --help - Print help information - - --jwt-expiry - Amount of time (seconds) before expiring token (if JWT scheme is specified). - - --jwt-issuer - Issuer of JWT claims (if JWT scheme is specified). - - --jwt-secret - Secret used for JWT scheme (if JWT scheme is specified). - - --log-level - Log level passed to the Fuel Indexer service. [default: info] [possible values: info, - debug, error, warn] - - --max-body-size - Max body size for web requests. [default: 5242880] - - --metrics - Use Prometheus metrics reporting. - - --postgres-database - Postgres database. - - --postgres-host - Postgres host. - - --postgres-password - Postgres password. - - --postgres-port - Postgres port. - - --postgres-user - Postgres username. - - --rate-limit - Enable rate limiting. - - --rate-limit-request-count - Maximum number of requests to allow over --rate-limit-window.. - - --rate-limit-window-size - Number of seconds over which to allow --rate-limit-rps. - - --run-migrations - Run database migrations before starting service. - - -v, --verbose - Enable verbose logging. - - -V, --version - Print version information - - --web-api-host - Web API host. [default: localhost] - - --web-api-port - Web API port. [default: 29987] -``` diff --git a/docs/src/graphql/index.md b/docs/src/graphql/index.md deleted file mode 100644 index 640d43933..000000000 --- a/docs/src/graphql/index.md +++ /dev/null @@ -1,36 +0,0 @@ -# GraphQL - -The Fuel indexer uses GraphQL to in order to allow users to query for indexed data. Please note that the Fuel indexer does not support the full GraphQL specification; however, we do our best to reasonably support as much as we can. In this chapter, you can find information on how to leverage our supported features to efficiently get the data you want. - -- [Directives](./directives.md) -- [GraphQL API Server](./api-server.md) -- [Playground](./playground.md) -- [Queries](../queries/index.md) - -## Supported Functionality - -While we do our best to maintain compliance with the GraphQL specification and parity with other implementations, there are a few things that are under development or will not be implemented. Here's a table describing our GraphQL functionality: - -```text -✅ -- implemented -🚧 -- planned or in development -⛔ -- will not implement -``` - -| Functionality | Status | Notes | -|------|----------|-------| -| Arguments | ✅ | [read the Search and Filtering section](../queries/search-filtering.md) | -| Aliases | ✅ | | -| Fragments | ✅ | inline fragments are currently not supported | -| Introspection | ✅ | | -| GraphQL Playground | ✅ | [read the Playground section](./playground.md) | -| Pagination | ✅ | [read the Pagination section](../queries/pagination.md) | -| Directives | 🚧 | [read the Directives section](./directives.md) | -| List Types | 🚧 | | -| Union Types | 🚧 | | -| Federation | 🚧 | | -| Variables | ⛔ | | -| Mutations | ⛔ | | -| Enums | ⛔ | | -| Interfaces | ⛔ | | -| Input Types| ⛔ | | diff --git a/docs/src/indexing-custom-types/index.md b/docs/src/indexing-custom-types/index.md new file mode 100644 index 000000000..a93456d85 --- /dev/null +++ b/docs/src/indexing-custom-types/index.md @@ -0,0 +1,247 @@ +# Custom Types + +1. [Contract](#1-contract) +2. [Schema](#2-schema) +3. [Manifest](#3-manifest) +4. [Writing a handler](#4-handler-logic) + +> In addition to Fuel-specific types, you can also index custom types triggered in your Sway smart contract. + +To index custom types from a Sway smart contract, you'll need that specific contract's ABI in JSON format; the JSON ABI is generated as a result of running `forc build` to build your contract. After that, the process is similar to [indexing Fuel types](../indexing-fuel-types/index.md). + +## Example + +Let's cover some of these concepts in an example below. + +### 1. Contract + +First, let's create a Sway contract with some simple types. + +```sway +contract; + +use std::logging::log; + +struct Addition { + added_value: u64, + updated_total: u64, +} + +struct Subtraction { + subtracted_value: u64, + updated_total: u64, +} + +abi ValueStore { + #[storage(read, write)] + fn add(value: u64); + + #[storage(read, write)] + fn subtract(value: u64) -> Subtraction; +} + +storage { + total: u64 = 1000, +} + +impl ValueStore for Contract { + #[storage(read, write)] + fn add(value: u64) { + let updated_total = storage.total.read() + value; + storage.total.write(updated_total); + log( + Addition { + added_value: value, + updated_total + } + ) + } + + #[storage(read, write)] + fn subtract(value: u64) -> Subtraction { + let updated_total = storage.total.read() - value; + storage.total.write(updated_total); + + Subtraction { + subtracted_value: value, + updated_total + } + } +} +``` + +- In this contract, we have two types: `Addition` and `Subtraction`. As we'll soon see, indexers can process custom types that are logged or returned as part of a function. +- To begin creating an indexer for this contract, let's build the contract and generate a JSON ABI file. + - Running `forc build` generates a JSON ABI similar to the lightly-edited one below: + +```json +{ + "types": [ + { + "typeId": 0, + "type": "()", + "components": [], + "typeParameters": null + }, + { + "typeId": 1, + "type": "struct Addition", + "components": [ + { + "name": "added_value", + "type": 3, + "typeArguments": null + }, + { + "name": "updated_total", + "type": 3, + "typeArguments": null + } + ], + "typeParameters": null + }, + { + "typeId": 2, + "type": "struct Subtraction", + "components": [ + { + "name": "subtracted_value", + "type": 3, + "typeArguments": null + }, + { + "name": "updated_total", + "type": 3, + "typeArguments": null + } + ], + "typeParameters": null + }, + { + "typeId": 3, + "type": "u64", + "components": null, + "typeParameters": null + } + ], + "functions": [...], + "loggedTypes": [ + { + "logId": 0, + "loggedType": { + "name": "", + "type": 1, + "typeArguments": [] + } + } + ], + "messagesTypes": [...], + "configurables": [...] +} + +``` + +## 2. Schema + +Now that we've discussed how to generate the JSON ABI for our Sway smart contract, let's now cover how to create an associated GraphQL schema. + +To index the contracts and store information about our Sway types in the database, we should create a schema. Let's design a schema that has an entity for each Sway type: + +```graphql +type AddEntity @entity { + id: ID! + value: UInt8! + updated_total: UInt8! +} + +type SubtractEntity @entity { + id: ID! + value: UInt8! + updated_total: UInt8! +} +``` + +> Note how the types used here, match the types used in our Sway smart contract. For a detailed mapping of these types, please see the [Storing Records](./../storing-records/index.md) section. + +## 3. Manifest + +So far we've covered how to (1) write your Sway smart contract and generate its JSON ABI, and (2) create types in your GraphQL schema that align with your Sway types. + +Next, we'll cover how to write the manifest file for your indexer. + +Before writing any of the handler code for your indexer, we need to make sure that our indexer manifest contains the necessary information to allow for the compiler to parse our contract types. + +Specifically, we should ensure that the `contract_abi` and `graphql_schema` fields point to the correct locations, respectively. + +```yaml +# A namespace is a logical grouping of declared names. Think of the namespace +# as an organization identifier +namespace: fuellabs + +# The identifier field is used to identify the given index. +identifier: custom_types_example + +# The abi option is used to provide a link to the Sway JSON ABI that is generated when you +# build your project. +abi: path/to/custom/type/example/contract-abi.json + +# The particular start block after which you'd like your indexer to start indexing events. +start_block: ~ + +# The particular end block after which you'd like your indexer to stop indexing events. +end_block: ~ + +# The `fuel_client` denotes the address (host, port combination) of the running Fuel client +# that you would like your indexer to index events from. In order to use this per-indexer +# `fuel_client` option, the indexer service at which your indexer is deployed will have to run +# with the `--indexer_net_config` option. +fuel_client: ~ + +# The contract_id specifies which particular contract you would like your index to subscribe to. +contract_id: ~ + +# The graphql_schema field contains the file path that points to the GraphQL schema for the +# given index. +graphql_schema: path/to/custom/type/example/indexer.schema.graphql + +# The module field contains a file path that points to code that will be run as an executor inside +# of the indexer. +# Important: At this time, wasm is the preferred method of execution. +module: + wasm: ~ + +# The resumable field contains a boolean that specifies whether or not the indexer should, synchronise +# with the latest block if it has fallen out of sync. +resumable: true +``` + +## 4. Handler Logic + +Finally, we can create handlers to index these particular types and store them in the database. Let's look at the following example: + +```rust, ignore +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn index_addition(addition_event: Addition) { + let addition = AddEntity { + id: 123, + value: addition_event.added_value, + updated_total: addition_event.updated_total + }; + addition.save(); + } + + fn index_subtraction(subtraction_event: Subtraction) { + let subtraction = SubtractEntity { + id: 123, + value: subtraction_event.subtracted_value, + updated_total: subtraction_event.updated_total + }; + subtraction.save(); + } +} +``` + +Regardless of whether a custom type was logged (e.g. `Addition`) or returned (e.g. `Subtraction`), the type will be available for you to use in your functions. Just include the type(s) you want your function to use in the parameters, and the function will be executed whenever each of the parameters have been satisfied by an instance of the type(s). diff --git a/docs/src/indexing-fuel-types/blocks.md b/docs/src/indexing-fuel-types/blocks.md new file mode 100644 index 000000000..df89e8f23 --- /dev/null +++ b/docs/src/indexing-fuel-types/blocks.md @@ -0,0 +1,32 @@ +# `BlockData` + +> The `BlockData` struct is how blocks are represented in the Fuel indexer. It contains metadata such as the ID, height, and time, as well as a list of the transactions it contains (represented by `TransactionData`). It also contains the public key hash of the block producer, if present. + +## Definition + +```rust,ignore +pub struct BlockData { + pub height: u32, + pub id: Bytes32, + pub header: Header, + pub producer: Option, + pub time: i64, + pub consensus: Consensus, + pub transactions: Vec, +} +``` + +## Usage + +```rust,ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_block(block_data: BlockData) { + let height = block_data.header.height; + info!("This block #{height}"); + } +} +``` diff --git a/docs/src/indexing-fuel-types/index.md b/docs/src/indexing-fuel-types/index.md new file mode 100644 index 000000000..c3646b0a2 --- /dev/null +++ b/docs/src/indexing-fuel-types/index.md @@ -0,0 +1,7 @@ +# Indexing Fuel Types + +This document provides information about Fuel-specific types and provides examples on how to index each type. + +- [Blocks](./blocks.md) +- [Transactions](./transactions.md) +- [Receipts](./receipts.md) diff --git a/docs/src/indexing-fuel-types/receipts.md b/docs/src/indexing-fuel-types/receipts.md new file mode 100644 index 000000000..39836aa9c --- /dev/null +++ b/docs/src/indexing-fuel-types/receipts.md @@ -0,0 +1,469 @@ +# Receipts + +Every transaction in the Fuel network contains a list of receipts with information about that transaction, including what contract function was called, logged data, data returned from a function, etc. + +There are several types of receipts that can be attached to a transaction and indexed. You can learn more about each of these in the sections below. + +- [**Burn**](#burn) +- [**Call**](#call) +- [**Log**](#log) +- [**LogData**](#logdata) +- [**MessageOut**](#messageout) +- [**Mint**](#mint) +- [**Panic**](#panic) +- [**Return**](#return) +- [**ReturnData**](#returndata) +- [**Revert**](#revert) +- [**ScriptResult**](#scriptresult) +- [**Transfer**](#transfer) +- [**TransferOut**](#transferout) + +## Burn + +A `Burn` receipt is generated whenever an asset is burned in a Sway contract. [Read more about `Burn` in the Fuel protocol ABI spec](https://docs.fuel.network/docs/specs/abi/receipts/#burn-receipt). + +```rust, ignore +use fuel_types::{AssetId, ContractId}; +pub struct Burn { + pub sub_id: AssetId, + pub contract_id: ContractId, + pub val: u64, + pub pc: u64, + pub is: u64, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_burn_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::Burn { contract_id, .. } => { + info!("Found burn receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` + +## Call + +A `Call` receipt is generated whenever a function is called in a Sway contract. The `fn_name` field contains the name of the called function from the aforementioned contract. [Read more about `Call` in the Fuel protocol ABI spec](https://docs.fuel.network/docs/specs/abi/receipts/#call-receipt). + +```rust, ignore +use fuel_types::{AssetId, ContractId}; +pub struct Call { + pub contract_id: ContractId, + pub to: ContractId, + pub amount: u64, + pub asset_id: AssetId, + pub gas: u64, + pub fn_name: String, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_call_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::Call { contract_id, .. } => { + info!("Found call receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` + +## Log + +A `Log` receipt is generated when calling `log()` on a non-reference types in a Sway contracts - specifically `bool`, `u8`, `u16`, `u32`, and `u64`. The `ra` field includes the value being logged while `rb` may include a non-zero value representing a unique ID for the `log` instance. [Read more about `Log` in the Fuel protocol ABI spec](https://docs.fuel.network/docs/specs/abi/receipts/#log-receipt). + +```rust, ignore +use fuel_types::ContractId; +pub struct Log { + pub contract_id: ContractId, + pub ra: u64, + pub rb: u64, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_log_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::Log { contract_id, .. } => { + info!("Found log receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` + +## LogData + +A `LogData` receipt is generated when calling `log()` in a Sway contract on a reference type; this includes all types _except_ non-reference types. The `data` field will include the logged value as a hexadecimal. The `rb` field will contain a unique ID that can be used to look up the logged data type. [Read more about `LogData` in the Fuel protocol ABI spec](https://docs.fuel.network/docs/specs/abi/receipts/#logdata-receipt). +> + +```rust,ignore +use fuel_types::ContractId; +pub struct LogData { + pub contract_id: ContractId, + pub data: Vec, + pub rb: u64, + pub len: u64, + pub ptr: u64, +} +``` + +> Note: the example below will run both when the type `MyEvent` is logged as well as when `MyEvent` is returned from a function. + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_log_data(event: MyEvent) { + info!("Event {event:?} was logged in the contract"); + } +} +``` + +## MessageOut + +A `MessageOut` receipt is generated as a result of the `send_typed_message()` Sway method in which a message is sent to a recipient address along with a certain amount of coins. The `data` field supports data of an arbitrary type `T` and will be decoded by the indexer upon receipt. [Read more about `MessageOut` in the Fuel protocol ABI spec](https://docs.fuel.network/docs/specs/abi/receipts/#messageout-receipt). + +```rust,ignore +use fuel_types::{MessageId, Bytes32, Address}; +pub struct MessageOut { + pub message_id: MessageId, + pub sender: Address, + pub recipient: Address, + pub amount: u64, + pub nonce: Bytes32, + pub len: u64, + pub digest: Bytes32, + pub data: Vec, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_message_out(event: MyEvent) { + info!("Event {event:?} was logged in the contract"); + } +} +``` + +## Mint + +A `Mint` receipt is generated whenever an asset is burned in a Sway contract. [Read more about `Mint` in the Fuel protocol ABI spec](https://docs.fuel.network/docs/specs/abi/receipts/#mint-receipt). + +```rust, ignore +use fuel_types::{AssetId, ContractId}; +pub struct Mint { + pub sub_id: AssetId, + pub contract_id: ContractId, + pub val: u64, + pub pc: u64, + pub is: u64, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_mint_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::Mint { contract_id, .. } => { + info!("Found mint receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` + +## Panic + +A `Panic` receipt is produced when a Sway smart contract call fails for a reason that doesn't produce a revert. The reason field records the reason for the panic, which is represented by a number between 0 and 255. You can find the mapping between the values and their meanings here in the FuelVM [source code](https://github.com/FuelLabs/fuel-vm/blob/master/fuel-asm/src/panic_reason.rs). [Read more about `Panic` in the Fuel protocol spec](https://docs.fuel.network/docs/specs/abi/receipts/#mint-receipt). + +```rust, ignore +use fuel_types::ContractId; +pub struct Panic { + pub contract_id: ContractId, + pub reason: u32, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_panic_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::Panic { contract_id, .. } => { + info!("Found panic receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` + +## Return + +A `Return` receipt is generated when returning a non-reference type in a Sway contract, specifically `bool`, `u8`, `u16`, `u32`, and `u64`. The `val` field includes the value being returned. [Read more about `Return` in the Fuel protocol spec](https://docs.fuel.network/docs/specs/abi/receipts/#return-receipt). + +```rust, ignore +use fuel_types::ContractId; +pub struct Return { + pub contract_id: ContractId, + pub val: u64, + pub pc: u64, + pub is: u64, +} +``` + +You can handle functions that produce a `Return` receipt type by adding a parameter with the type `Return`. + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_return_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::Return { contract_id, .. } => { + info!("Found return receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` + +## ReturnData + +A `ReturnData` receipt is generated when returning a reference type in a Sway contract; this includes all types _except_ non-reference types. The `data` field will include the returned value as a hexadecimal. [Read more about `ReturnData` in the Fuel protocol ABI spec](https://docs.fuel.network/docs/specs/abi/receipts/#returndata-receipt). + +```rust, ignore +use fuel_types::ContractId; +pub struct ReturnData { + id: ContractId, + data: Vec, +} +``` + +> Note: the example below will run both when the type `MyStruct` is logged as well as when `MyStruct` is returned from a function. + +```rust, ignore +fn handle_return_data(data: MyStruct) { + // handle the emitted ReturnData receipt +} +``` + +## Revert + +A `Revert` receipt is produced when a Sway smart contract function call fails. The table below lists possible reasons for the failure and their values. The `error_val` field records these values, enabling your indexer to identify the specific cause of the reversion. [Read more about `Revert` in the Fuel protocol spec](https://docs.fuel.network/docs/specs/abi/receipts/#revert-receipt). + +```rust, ignore +use fuel_types::ContractId; +pub struct Revert { + pub contract_id: ContractId, + pub error_val: u64, + } +``` + +| Reason | Value | +|-----------------------|-------| +| FailedRequire | 0 | +| FailedTransferToAddress | 1 | +| FailedSendMessage | 2 | +| FailedAssertEq | 3 | +| FailedAssert | 4 | + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_revert_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::Revert { contract_id, .. } => { + info!("Found return receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` + +## ScriptResult + +A `ScriptResult` receipt is generated when a contract call resolves; that is, it's generated as a result of the `RET`, `RETD`, and `RVRT` instructions. The `result` field will contain a `0` for success, and a non-zero value otherwise. [Read more about `ScriptResult` in the Fuel protocol spec](https://docs.fuel.network/docs/specs/abi/receipts/#scriptresult-receipt). + +```rust,ignore +pub struct ScriptResult { + pub result: u64, + pub gas_used: u64, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_script_result_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::ScriptResult { result, .. } => { + info!("Result from script: {result:?}"); + } + } + } + } + } +} +``` + +## Transfer + +A `Transfer` receipt is generated when coins are transferred to a contract as part of a Sway contract. The `asset_id` field contains the asset ID of the transferred coins, as the FuelVM has built-in support for working with multiple assets. The `pc` and `is` fields aren't currently used for anything, but are included for completeness. [Read more about `Transfer` in the Fuel protocol spec](https://docs.fuel.network/docs/specs/abi/receipts/#transfer-receipt). + +```rust,ignore +use fuel_types::{ContractId, AssetId}; +pub struct Transfer { + pub contract_id: ContractId, + pub to: ContractId, + pub amount: u64, + pub asset_id: AssetId, + pub pc: u64, + pub is: u64, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_transfer_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::Transfer { contract_id, .. } => { + info!("Found transfer receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` + +## TransferOut + +A `TransferOut` receipt is generated when coins are transferred to an address rather than a contract. Every other field of the receipt works the same way as it does in the `Transfer` receipt. [Read more about `TransferOut` in the Fuel protocol spec](https://docs.fuel.network/docs/specs/abi/receipts/#transferout-receipt). + +```rust,ignore +use fuel_types::{ContractId, AssetId, Address}; +pub struct TransferOut { + pub contract_id: ContractId, + pub to: Address, + pub amount: u64, + pub asset_id: AssetId, + pub pc: u64, + pub is: u64, +} +``` + +```rust, ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_transfer_out_receipt(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + for receipt in transaction.receipts { + match receipt { + fuel::Receipt::TransferOut { contract_id, .. } => { + info!("Found transfer_out receipt from contract {contract_id:?}"); + } + } + } + } + } +} +``` diff --git a/docs/src/indexing-fuel-types/transactions.md b/docs/src/indexing-fuel-types/transactions.md new file mode 100644 index 000000000..e3a1e787d --- /dev/null +++ b/docs/src/indexing-fuel-types/transactions.md @@ -0,0 +1,97 @@ + +# Transactions + +## `TransactionData` + +The `TransactionData` struct contains important information about a transaction in the Fuel network. The `id` field is the transaction hash, which is a 32-byte string. The `receipts` field contains a list of `Receipts`, which are generated by a Fuel node during the execution of a Sway smart contract; you can find more information in the [Receipts](./receipts.md) section. + +### Definition + +```rust,ignore +pub struct TransactionData { + pub transaction: Transaction, + pub status: TransactionStatus, + pub receipts: Vec, + pub id: TxId, +} +``` + +### Usage + +```rust,ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_transaction(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + info!( + "Transaction {} in block at height {} has {} receipts", + transaction.id, + block_data.header.height, + transaction.receipts.len() + ); + } + } +} + +``` + +## `TransactionStatus` + +`TransactionStatus` refers to the status of a `Transaction` in the Fuel network. + +### Definition + +```rust,ignore +pub enum TransactionStatus { + Failure { + block_id: String, + time: DateTime, + reason: String, + }, + SqueezedOut { + reason: String, + }, + Submitted { + submitted_at: DateTime, + }, + Success { + block_id: String, + time: DateTime, + }, +} +``` + +### Usage + +```rust,ignore +extern crate alloc; +use fuel_indexer_utils::prelude::*; + +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { + fn handle_transaction(block_data: BlockData) { + let height = block_data.header.height; + if !block_data.transactions.is_empty() { + let transaction = block_data.transactions[0]; + match transaction.transaction { + fuel::Transaction::Script(tx) => match tx.status { + fuel::TransactionStatus::Success { block_id, time } => { + info!( + "Transaction {} in block {} was successful at {}", + tx.id, block_id, time + ); + } + }, + _ => { + info!("We don't care about this transaction type"); + } + } + } + } +} +``` diff --git a/docs/src/indexing/blocks-and-transactions.md b/docs/src/indexing/blocks-and-transactions.md deleted file mode 100644 index ad440d527..000000000 --- a/docs/src/indexing/blocks-and-transactions.md +++ /dev/null @@ -1,66 +0,0 @@ -# Blocks and Transactions - -You can use the `BlockData` and `TransactionData` data structures to index important information about the Fuel network for your dApp. - -## `BlockData` - -```rust,ignore -pub struct BlockData { - pub height: u64, - pub id: Bytes32, - pub producer: Option, - pub time: i64, - pub transactions: Vec, -} -``` - -The `BlockData` struct is how blocks are represented in the Fuel indexer. It contains metadata such as the ID, height, and time, as well as a list of the transactions it contains (represented by `TransactionData`). It also contains the public key hash of the block producer, if present. - -## `TransactionData` - -```rust,ignore -pub struct TransactionData { - pub transaction: Transaction, - pub status: ClientTransactionStatus, - pub receipts: Vec, - pub id: ClientTxId, -} -``` - -The `TransactionData` struct contains important information about a transaction in the Fuel network. The `id` field is the transaction hash, which is a 32-byte string. The `receipts` field contains a list of `Receipts`, which are generated by a Fuel node during the execution of a Sway smart contract; you can find more information in the [Receipts](./receipts.md) section. - -### `Transaction` - -```rust,ignore -pub enum Transaction { - Script(Script), - Create(Create), - Mint(Mint), -} -``` - -`Transaction` refers to the Fuel transaction entity and can be one of three distinct types: `Script`, `Create`, or `Mint`. Explaining the differences between each of the types is out of scope for the Fuel indexer; however, you can find information about the `Transaction` type in the [Fuel specifications](https://specs.fuel.network/master/tx-format/transaction.html). - -### `TransactionStatus` - -```rust,ignore -pub enum TransactionStatus { - Failure { - block_id: String, - time: DateTime, - reason: String, - }, - SqueezedOut { - reason: String, - }, - Submitted { - submitted_at: DateTime, - }, - Success { - block_id: String, - time: DateTime, - }, -} -``` - -`TransactionStatus` refers to the status of a `Transaction` in the Fuel network. diff --git a/docs/src/indexing/burn.md b/docs/src/indexing/burn.md deleted file mode 100644 index 8f11889c9..000000000 --- a/docs/src/indexing/burn.md +++ /dev/null @@ -1,23 +0,0 @@ -# Burn - -```rust, ignore -use fuel_types::{AssetId, ContractId}; -pub struct Burn { - pub sub_id: AssetId, - pub contract_id: ContractId, - pub val: u64, - pub pc: u64, - pub is: u64, -} -``` - -- A `Burn` receipt is generated whenever an asset is burned in a Sway contract. -- [Read more about `Burn` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#burn-receipt) - -You can handle functions that produce a `Burn` receipt type by adding a parameter with the type `Burn`. - -```rust, ignore -fn handle_burn(burn: Burn) { - // handle the emitted Burn receipt -} -``` diff --git a/docs/src/indexing/call.md b/docs/src/indexing/call.md deleted file mode 100644 index 480bab4e3..000000000 --- a/docs/src/indexing/call.md +++ /dev/null @@ -1,25 +0,0 @@ -# Call - -```rust, ignore -use fuel_types::{AssetId, ContractId}; -pub struct Call { - pub contract_id: ContractId, - pub to: ContractId, - pub amount: u64, - pub asset_id: AssetId, - pub gas: u64, - pub fn_name: String, -} -``` - -- A `Call` receipt is generated whenever a function is called in a Sway contract. -- The `fn_name` field contains the name of the called function from the aforementioned contract. -- [Read more about `Call` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#call-receipt) - -You can handle functions that produce a `Call` receipt type by adding a parameter with the type `Call`. - -```rust, ignore -fn handle_call(call: Call) { - // handle the emitted Call receipt -} -``` diff --git a/docs/src/indexing/index.md b/docs/src/indexing/index.md deleted file mode 100644 index 7049d42ff..000000000 --- a/docs/src/indexing/index.md +++ /dev/null @@ -1,11 +0,0 @@ -# Indexing - -You can index three main types of data from the Fuel network: blocks, transactions, and transaction receipts. You can read more about these data types below: - -- [**Blocks and Transactions**](./blocks-and-transactions.md) - -- [**Transaction Receipts**](./receipts.md) - -If you've previously built an indexer for the EVM, you may be used to only being able to index data that is emitted as an event. - -However, with Fuel you can index the entire transaction, which means you can use much more than logged data, allowing you to reduce the number of logs you need in your contract. diff --git a/docs/src/indexing/log.md b/docs/src/indexing/log.md deleted file mode 100644 index 88a60f8c1..000000000 --- a/docs/src/indexing/log.md +++ /dev/null @@ -1,23 +0,0 @@ -# Log - -```rust, ignore -use fuel_types::ContractId; -pub struct Log { - pub contract_id: ContractId, - pub ra: u64, - pub rb: u64, -} -``` - -- A `Log` receipt is generated when calling `log()` on a non-reference types in a Sway contracts. - - Specifically `bool`, `u8`, `u16`, `u32`, and `u64`. -- The `ra` field includes the value being logged while `rb` may include a non-zero value representing a unique ID for the `log` instance. -- [Read more about `Log` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#log-receipt) - -You can handle functions that produce a `Log` receipt type by adding a parameter with the type `Log`. - -```rust, ignore -fn handle_log(log: Log) { - // handle the emitted Log receipt -} -``` diff --git a/docs/src/indexing/logdata.md b/docs/src/indexing/logdata.md deleted file mode 100644 index 8da6540a9..000000000 --- a/docs/src/indexing/logdata.md +++ /dev/null @@ -1,28 +0,0 @@ - -# LogData - -```rust,ignore -use fuel_types::ContractId; -pub struct LogData { - pub contract_id: ContractId, - pub data: Vec, - pub rb: u64, - pub len: u64, - pub ptr: u64, -} -``` - -- A `LogData` receipt is generated when calling `log()` in a Sway contract on a reference type; this includes all types _except_ non-reference types. -- The `data` field will include the logged value as a hexadecimal. - - The `rb` field will contain a unique ID that can be used to look up the logged data type. -- [Read more about `LogData` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#logdata-receipt) - -You can handle functions that produce a `LogData` receipt type by using the logged type as a function parameter. - -> Note: the example below will run both when the type `MyStruct` is logged as well as when `MyStruct` is returned from a function. - -```rust, ignore -fn handle_log_data(data: MyStruct) { - // handle the emitted LogData receipt -} -``` diff --git a/docs/src/indexing/messageout.md b/docs/src/indexing/messageout.md deleted file mode 100644 index f996db3ca..000000000 --- a/docs/src/indexing/messageout.md +++ /dev/null @@ -1,27 +0,0 @@ -# MessageOut - -```rust,ignore -use fuel_types::{MessageId, Bytes32, Address}; -pub struct MessageOut { - pub message_id: MessageId, - pub sender: Address, - pub recipient: Address, - pub amount: u64, - pub nonce: Bytes32, - pub len: u64, - pub digest: Bytes32, - pub data: Vec, -} -``` - -- A `MessageOut` receipt is generated as a result of the `send_typed_message()` Sway method in which a message is sent to a recipient address along with a certain amount of coins. -- The `data` field supports data of an arbitrary type `T` and will be decoded by the indexer upon receipt. -- [Read more about `MessageOut` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#messageout-receipt) - -You can handle functions that produce a `MessageOut` receipt type by adding a parameter with the type `MessageOut`. - -```rust, ignore -fn handle_message_out(message_out: MessageOut) { - // handle the emitted MessageOut receipt -} -``` diff --git a/docs/src/indexing/mint.md b/docs/src/indexing/mint.md deleted file mode 100644 index 2017478b2..000000000 --- a/docs/src/indexing/mint.md +++ /dev/null @@ -1,23 +0,0 @@ -# Mint - -```rust, ignore -use fuel_types::{AssetId, ContractId}; -pub struct Mint { - pub sub_id: AssetId, - pub contract_id: ContractId, - pub val: u64, - pub pc: u64, - pub is: u64, -} -``` - -- A `Mint` receipt is generated whenever an asset is burned in a Sway contract. -- [Read more about `Mint` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#mint-receipt) - -You can handle functions that produce a `Mint` receipt type by adding a parameter with the type `Mint`. - -```rust, ignore -fn handle_mint(mint: Mint) { - // handle the emitted Mint receipt -} -``` diff --git a/docs/src/indexing/panic.md b/docs/src/indexing/panic.md deleted file mode 100644 index 0cc0e558b..000000000 --- a/docs/src/indexing/panic.md +++ /dev/null @@ -1,20 +0,0 @@ -# Panic - -```rust, ignore -use fuel_types::ContractId; -pub struct Panic { - pub contract_id: ContractId, - pub reason: u32, -} -``` - -- A `Panic` receipt is produced when a Sway smart contract call fails for a reason that doesn't produce a revert. -- The reason field records the reason for the panic, which is represented by a number between 0 and 255. You can find the mapping between the values and their meanings here in the FuelVM [source code](https://github.com/FuelLabs/fuel-vm/blob/master/fuel-asm/src/panic_reason.rs). -- [Read more about `Panic` in the Fuel Protocol spec](https://specs.fuel.network/master/abi/receipts.html#panic-receipt) -- You can handle functions that could produce a `Panic` receipt by adding a parameter with the type `Panic`. - -```rust, ignore -fn handle_panic(panic: Panic) { - // handle the emitted Panic receipt -} -``` diff --git a/docs/src/indexing/receipts.md b/docs/src/indexing/receipts.md deleted file mode 100644 index b72a79a09..000000000 --- a/docs/src/indexing/receipts.md +++ /dev/null @@ -1,19 +0,0 @@ -# Receipts - -Every transaction in the Fuel network contains a list of receipts with information about that transaction, including what contract function was called, logged data, data returned from a function, etc. - -There are several types of receipts that can be attached to a transaction and indexed. You can learn more about each of these in the sections below. - -- [**Burn**](./burn.md) -- [**Call**](./call.md) -- [**Log**](./log.md) -- [**LogData**](./logdata.md) -- [**MessageOut**](./messageout.md) -- [**Mint**](./mint.md) -- [**Panic**](./panic.md) -- [**Return**](./return.md) -- [**ReturnData**](./returndata.md) -- [**Revert**](./revert.md) -- [**ScriptResult**](./scriptresult.md) -- [**Transfer**](./transfer.md) -- [**TransferOut**](./transferout.md) diff --git a/docs/src/indexing/return.md b/docs/src/indexing/return.md deleted file mode 100644 index c3b5efd26..000000000 --- a/docs/src/indexing/return.md +++ /dev/null @@ -1,24 +0,0 @@ -# Return - -```rust, ignore -use fuel_types::ContractId; -pub struct Return { - pub contract_id: ContractId, - pub val: u64, - pub pc: u64, - pub is: u64, -} -``` - -- A `Return` receipt is generated when returning a non-reference type in a Sway contract. - - Specifically `bool`, `u8`, `u16`, `u32`, and `u64`. -- The `val` field includes the value being returned. -- [Read more about `Log` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#return-receipt) - -You can handle functions that produce a `Return` receipt type by adding a parameter with the type `Return`. - -```rust, ignore -fn handle_return(data: Return) { - // handle the emitted Return receipt -} -``` diff --git a/docs/src/indexing/returndata.md b/docs/src/indexing/returndata.md deleted file mode 100644 index f4eabe64a..000000000 --- a/docs/src/indexing/returndata.md +++ /dev/null @@ -1,23 +0,0 @@ -# ReturnData - -```rust, ignore -use fuel_types::ContractId; -pub struct ReturnData { - id: ContractId, - data: Vec, -} -``` - -- A `ReturnData` receipt is generated when returning a reference type in a Sway contract; this includes all types _except_ non-reference types. -- The `data` field will include the returned value as a hexadecimal. -- [Read more about `ReturnData` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#returndata-receipt) - -You can handle functions that produce a `ReturnData` receipt type by using the returned type as a function parameter. - -> Note: the example below will run both when the type `MyStruct` is logged as well as when `MyStruct` is returned from a function. - -```rust, ignore -fn handle_return_data(data: MyStruct) { - // handle the emitted ReturnData receipt -} -``` diff --git a/docs/src/indexing/revert.md b/docs/src/indexing/revert.md deleted file mode 100644 index a7f45869e..000000000 --- a/docs/src/indexing/revert.md +++ /dev/null @@ -1,31 +0,0 @@ -# Revert - -```rust, ignore -use fuel_types::ContractId; -pub struct Revert { - pub contract_id: ContractId, - pub error_val: u64, - } -``` - -- A `Revert` receipt is produced when a Sway smart contract function call fails. -- The table below lists possible reasons for the failure and their values. -- The `error_val` field records these values, enabling your indexer to identify the specific cause of the reversion. - -| Reason | Value | -|-----------------------|-------| -| FailedRequire | 0 | -| FailedTransferToAddress | 1 | -| FailedSendMessage | 2 | -| FailedAssertEq | 3 | -| FailedAssert | 4 | - -- [Read more about `Revert` in the Fuel Protocol spec](https://specs.fuel.network/master/abi/receipts.html#revert-receipt) - -You can handle functions that could produce a `Revert` receipt by adding a parameter with the type `Revert`. - -```rust, ignore -fn handle_revert(revert: Revert) { - // handle the emitted Revert receipt -} -``` diff --git a/docs/src/indexing/scriptresult.md b/docs/src/indexing/scriptresult.md deleted file mode 100644 index a99f20754..000000000 --- a/docs/src/indexing/scriptresult.md +++ /dev/null @@ -1,20 +0,0 @@ -# ScriptResult - -```rust,ignore -pub struct ScriptResult { - pub result: u64, - pub gas_used: u64, -} -``` - -- A `ScriptResult` receipt is generated when a contract call resolves; that is, it's generated as a result of the `RET`, `RETD`, and `RVRT` instructions. -- The `result` field will contain a `0` for success, and a non-zero value otherwise. -- [Read more about `ScriptResult` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#scriptresult-receipt) - -You can handle functions that produce a `ScriptResult` receipt type by adding a parameter with the type `ScriptResult`. - -```rust, ignore -fn handle_script_result(script_result: ScriptResult) { - // handle the emitted ScriptResult receipt -} -``` diff --git a/docs/src/indexing/transfer.md b/docs/src/indexing/transfer.md deleted file mode 100644 index 534b2085c..000000000 --- a/docs/src/indexing/transfer.md +++ /dev/null @@ -1,26 +0,0 @@ -# Transfer - -```rust,ignore -use fuel_types::{ContractId, AssetId}; -pub struct Transfer { - pub contract_id: ContractId, - pub to: ContractId, - pub amount: u64, - pub asset_id: AssetId, - pub pc: u64, - pub is: u64, -} -``` - -- A `Transfer` receipt is generated when coins are transferred to a contract as part of a Sway contract. -- The `asset_id` field contains the asset ID of the transferred coins, as the FuelVM has built-in support for working with multiple assets. - - The `pc` and `is` fields aren't currently used for anything, but are included for completeness. -- [Read more about `Transfer` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#transfer-receipt) - -You can handle functions that produce a `Transfer` receipt type by adding a parameter with the type `Transfer`. - -```rust, ignore -fn handle_transfer(transfer: Transfer) { - // handle the emitted Transfer receipt -} -``` diff --git a/docs/src/indexing/transferout.md b/docs/src/indexing/transferout.md deleted file mode 100644 index 70a2c58e4..000000000 --- a/docs/src/indexing/transferout.md +++ /dev/null @@ -1,25 +0,0 @@ -# TransferOut - -```rust,ignore -use fuel_types::{ContractId, AssetId, Address}; -pub struct TransferOut { - pub contract_id: ContractId, - pub to: Address, - pub amount: u64, - pub asset_id: AssetId, - pub pc: u64, - pub is: u64, -} -``` - -- A `TransferOut` receipt is generated when coins are transferred to an address rather than a contract. -- Every other field of the receipt works the same way as it does in the `Transfer` receipt. -- [Read more about `TransferOut` in the Fuel protocol ABI spec](https://specs.fuel.network/master/abi/receipts.html#transferout-receipt) - -You can handle functions that produce a `TransferOut` receipt type by adding a parameter with the type `TransferOut`. - -```rust, ignore -fn handle_transferout(transfer_out: TransferOut) { - // handle the emitted TransferOut receipt -} -``` diff --git a/docs/src/project-components/index.md b/docs/src/project-components/index.md index ce5e0a2c2..2f3f8c057 100644 --- a/docs/src/project-components/index.md +++ b/docs/src/project-components/index.md @@ -1,22 +1,46 @@ + # A Fuel Indexer Project ## Use Cases The Fuel indexer project can currently be used in a number of different ways: -- as tooling to compile arbitrary indicies +- as tooling to interact with indexers - as a standalone service -- as a part of a Fuel project, alongside other components of the Fuel ecosystem (e.g. [Sway](https://fuellabs.github.io/sway)) +- as a part of a larger Fuel project, alongside other components of the Fuel ecosystem (e.g. [Sway smart contracts](https://fuellabs.github.io/sway)) -We'll describe these three different implementations below. +We'll describe these three different use cases below. -### As tooling for compiling indexers +### As tooling to interact with indexers -The Fuel indexer provides functionality to make it easy to build and compile abitrary indexers by using [`forc index`](../forc-index/index.md). For info on how to use indexer tooling to compile arbitrary indexers, check out our [Quickstart](../getting-started/quickstart.md) and [Hello World](../getting-started/hello-world.md) examples for a more in-depth exploration of how to compile indexers. +The Fuel indexer provides functionality to make it easy to build and compile abitrary indexers by using the [`forc index`](../forc-index/index.md) CLI tool. Using `forc index`, users can create, build, deploy, and remove indexers, as well as authenticate against a running indexer service, and check the status of running indexers. + +#### Example + +Create, deploy, and check the status of a new indexer. + +```bash +forc index new fuel && \ + cd fuel && forc index deploy --url http://indexer.fuel.network && \ + forc index status --url http://indexer.fuel.network --auth $MY_TOKEN +``` ### As a standalone service -You can also start the Fuel indexer as a standalone binary that connects to a Fuel node to monitor the Fuel blockchain for new blocks and transactions. To do so, run the requisite database migrations, adjust the configuration to connect to a Fuel node, and start the service. +You can also start the Fuel indexer as a standalone service that connects to a Fuel node in order to monitor the Fuel blockchain for new blocks and transactions. To do so, run the requisite database migrations, adjust the configuration to connect to a Fuel node, and start the service. + +#### Example + +Create, deploy, and check the status of a new indexer. + +```bash +fuel-indexer run \ + --fuel-node-host beta-4.fuel.network \ + --fuel-node-port 80 \ + --run-migrations \ + --accept-sql-queries \ + --replace-indexer +``` ### As part of a Fuel project @@ -41,10 +65,12 @@ Finally, you can run the Fuel indexer as part of a project that uses other compo └── lib.rs ``` +--- + ## An Indexer Project at a Glance Every Fuel indexer project requires three components: -- a [Manifest](./manifest.md) describing indexer metadata -- a [Schema](./schema.md) containing models for the data you want to index -- a [Module](./module.md) which houses the logic for creating and saving the aforementioned data models +- a [Manifest](./manifest.md) describing how the indexer should work +- a [Schema](./schema.md) containing data models for the data that is to be indexed +- a [Module](./module.md) which contains the logic for how data coming from the FuelVM should be saved into an index diff --git a/docs/src/project-components/manifest.md b/docs/src/project-components/manifest.md index 2de84086b..fe8475b65 100644 --- a/docs/src/project-components/manifest.md +++ b/docs/src/project-components/manifest.md @@ -1,13 +1,15 @@ # Manifest -A manifest serves as the YAML configuration file for a given indexer. A proper manifest has the following structure: +A manifest is a YAML configuration file that specifies various aspects of how an indexer should function: Where should the indexer start? Where should the indexer end? What contract should the indexer subscribe to? + +Below is a sample indexer manifest file ```yaml -namespace: fuel -identifier: index1 +namespace: fuellabs +identifier: order_book_v1 fuel_client: beta-4.fuel.network:80 abi: path/to/my/contract-abi.json -contract_id: "0x39150017c9e38e5e280432d546fae345d6ce6d8fe4710162c2e3a95a6faff051" +contract_id: "fuels0x39150017c9e38e5e280432d546fae345d6ce6d8fe4710162c2e3a95a6faff051" graphql_schema: path/to/my/schema.graphql start_block: 1564 end_block: 310000 diff --git a/docs/src/project-components/module.md b/docs/src/project-components/module.md index d8e718286..8c94a5b56 100644 --- a/docs/src/project-components/module.md +++ b/docs/src/project-components/module.md @@ -1,32 +1,38 @@ -# WASM Modules +# Indexer modules -WebAssembly (WASM) modules are compiled binaries that are registered into a Fuel indexer at runtime. The WASM bytes are read in by the indexer and _executors_ are created which will implement blocking calls to the WASM runtime. +Indexer modules are compiled binaries that process data from the Fuel blockchain into entity types defined in your schema so that the data can be stored in a database. The Fuel indexer supports both WebAssembly (WASM) and native binaries; however, we **strongly** recommend using WASM binaries. -The WASM module is generated based on your manifest, schema, and your `lib.rs` file. +This document describes the process of creating an indexer module. -## `lib.rs` +## Creating Handlers -You can implement the logic for handling events and saving data to the database in your `lib.rs` file in the `src` folder. +Prior to creating a module for an indexer, both the manifest and schema should be created. At compile time, information will be extracted from both of those assets and combined it with your defined logic to create handlers that save data to storage. Let's look at the following example of a module that will be compiled to WASM: -Here, you can define which functions handle different events based on the function parameters. If you add a function parameter of a certain type, the function will handle all blocks, transactions, or transaction receipts that contain a matching type. +```rust, ignore +use fuel_indexer_utils::prelude::*; -We can look at the function below as an example: +#[indexer(manifest = "indexer.manifest.yaml")] +mod indexer_mod { -```rust, ignore -fn index_logged_greeting(greeter: Greeting) { - // function logic goes here + // This `log_the_greeting` function will be called, when we find + // a `Greeting` in a block. + fn log_the_greeting(greeting: Greeting) { + info!("The greeting is: {greeting:?}"); + } } ``` -All transactions that have a receipt that contains data with a type of `Greeting` will be handled by the function. +## What's going on here? -You can learn more about what data can be indexed in the [Indexing](../indexing/index.md) section. +- The first line imports the [prelude](https://docs.rs/fuel-indexer-utils/latest/fuel_indexer_utils/prelude/index.html) from `fuel_indexer_utils`; this allows you to quickly bootstrap an indexer by using common types and traits. Then, we have a module decorated with the `#[indexer]` macro. + - This macro processes a manifest at the supplied file path, parses your schema and Sway contract ABI (if supplied), and generates code that is combined with handler functions in order to create a complete indexer module. -To save an instance of a schema type in your database, you can call the `save` method on the instance. +- Finally, we have an example handler function. You can define which functions handle different events by using the function parameters. If you add a function parameter of a certain type `T`, the function will be triggered whenever that type is found as part of a block, transaction, or receipt. + - In this example, let's say that you have a Sway contract with a function that logs a `Greeting` struct. When that function executes as part of a transaction, the logged struct will be included in the data that is processed from the Fuel blockchain. Your indexer module will see the struct and execute `log_the_greeting`. -```rust, ignore -instance.save(); -``` +> You can learn more about what data can be indexed and find example handlers in the [Indexing Fuel Types](../indexing-fuel-types/index.md) and [Indexing Custom Types](../indexing-custom-types/index.md) sections. + +--- ## Usage @@ -36,23 +42,19 @@ To compile your indexer code to WASM, you'll first need to install the `wasm32-u rustup add target wasm32-unknown-unknown ``` -After that, you would compile your indexer code by navigating to the root folder for your indexer code and build. An example of this can be found below: - -```bash -cd /my/index-lib && cargo build --release -``` - -## Notes on WASM - -There are a few points that Fuel indexer users should know when using WASM: - -1. WASM modules are only used if the execution mode specified in your manifest file is `wasm`. - -2. Developers should be aware of what things may not work off-the-shelf in a module: file I/O, thread spawning, and anything that depends on system libraries. This is due to the technological limitations of WASM as a whole; more information can be found [here](https://rustwasm.github.io/docs/book/reference/which-crates-work-with-wasm.html). - -3. As of this writing, there is a small bug in newly built Fuel indexer WASM modules that produces a WASM runtime error due to an errant upstream dependency. For now, a quick workaround requires the use of `wasm-snip` to remove the errant symbols from the WASM module. More info can be found in the related script [here](https://github.com/FuelLabs/fuel-indexer/blob/develop/scripts/stripper.bash). - -4. Users on Apple Silicon macOS systems may experience trouble when trying to build WASM modules due to its `clang` binary not supporting WASM targets. If encountered, you can install a binary with better support from Homebrew (`brew install llvm`) and instruct `rustc` to leverage it by setting the following environment variables: - -- `AR=/opt/homebrew/opt/llvm/bin/llvm-ar` -- `CC=/opt/homebrew/opt/llvm/bin/clang` +After that, you can conveniently use the [`forc index`](./../forc-index/index.md) plugin to manager your indexers. Simply use `forc index build` to build your indexer or checkout the [`forc index build`](./../forc-index/build.md) docs for more options. + +> ## Notes on Web Assembly modules +> +> There are a few points that Fuel indexer users should know when using WASM: +> +> 1. WASM modules are only used if the execution mode specified in your manifest file is `wasm`. +> +> 2. Developers should be aware of what things may not work off-the-shelf in a module: file I/O, thread spawning, and anything that depends on system libraries or makes system calls. This is due to the technological limitations of WASM as a whole; more information can be found [here](https://rustwasm.github.io/docs/book/reference/which-crates-work-with-wasm.html). +> +> 3. As of this writing, there is a small bug in newly built Fuel indexer WASM modules that produces a WASM runtime error due to an errant upstream dependency. For now, a quick workaround requires the use of `wasm-snip` to remove the errant symbols from the WASM module. More info can be found in the related script [here](https://github.com/FuelLabs/fuel-indexer/blob/develop/scripts/stripper.bash). +> +> 4. Users on Apple Silicon macOS systems may experience trouble when trying to build WASM modules due to its `clang` binary not supporting WASM targets. If encountered, you can install a binary with better support from Homebrew (`brew install llvm`) and instruct `rustc` to leverage it by setting the following environment variables: +> +> - `AR=/opt/homebrew/opt/llvm/bin/llvm-ar` +> - `CC=/opt/homebrew/opt/llvm/bin/clang` diff --git a/docs/src/project-components/schema.md b/docs/src/project-components/schema.md index ba3f1faa9..f4c93bf20 100644 --- a/docs/src/project-components/schema.md +++ b/docs/src/project-components/schema.md @@ -1,31 +1,31 @@ # GraphQL Schema -The GraphQL schema is a required component of the Fuel indexer. When data is indexed into the database, the actual values that are persisted to the database will be values created using the data structures defined in the schema. +The GraphQL schema is a required component of the Fuel indexer. When data is indexed into the database, the actual values that are persisted to the database will be values created using the data structures defined in the GraphQL schema. -In its most basic form, a Fuel indexer GraphQL schema should have a `schema` definition that contains a defined query root. The rest of the implementation is up to you. Here's an example of a well-formed schema: +Below is a sample GraphQL schema for a Fuel indexer. ```graphql -type FirstThing @entity { +type Metadata @entity(virtual: true) { + imageUrl: Charfield! + data: Blob +} + +type Account @entity { id: ID! - value: UInt8! + address: Address! + index: UInt8! + metadata: Metadata } -type SecondThing @entity { +type Wallet @entity { id: ID! - optional_value: UInt8 - timestamp: Timestamp! + name: Charfield! + accounts: [Account!]! } ``` -The types you see above (e.g., `ID`, `UInt8`, etc) are Fuel abstractions that were created to more seamlessly integrate with the Fuel VM and are not native to GraphQL. A deeper explanation on these -types can be found in [the Types section](../data-types/types.md). - -> Important: It is up to developers to manage their own unique IDs for each type, meaning that a data structure's `ID` field needs to be manually generated prior to saving it to the database. This generation can be as simple or complex as you want in order to fit your particular situation; the only requirement is that the developer implement their own custom generation. - -## Required and Optional Fields - -Required fields are denoted with a `!` following its type; for example, the `value` field of the `FirstThing` type is a `UInt8` and is required to be present for the indexer to successfully persist the entity. If a certain piece of information is essential to your use case, then you should mark that field as required. +For a complete list of all scalars that can be used in a Fuel indexer, please see the [GraphQL Scalars](../designing-a-schema/scalars.md) section. -In contrast, optional fields are not required to be present for the indexer to persist the entity in storage. You can denote an optional field by just using the type name; for example, the `optional_value` field of the `SecondThing` type is optional, and should be a `UInt8` if present. If it's possible that a value might not always exist in the data you wish to index, consider making that the corresponding field optional. In your indexer code, you will need to use the `Option` Rust type when assigning a value to an optional field; values that are present should be assigned after being wrapped in `Some(..)` while absent values should be assigned using `None`. +Further, for a complete list of how Sway data types, GraphQL scalar types, and Fuel indexer database types map to each other, please see the [Database Types](../storing-records/index.md) section. -> Important: The `ID` field is _always_ required. An indexer **will** return an error if an optional value is used for the `ID` field. +Finally, for a more in-depth explanation on the schema being used above 👆🏽, please read the [GraphQL](./../designing-a-schema/index.md) section. diff --git a/docs/src/queries/index.md b/docs/src/querying/basic-queries.md similarity index 77% rename from docs/src/queries/index.md rename to docs/src/querying/basic-queries.md index e9828c703..324d05b2b 100644 --- a/docs/src/queries/index.md +++ b/docs/src/querying/basic-queries.md @@ -1,6 +1,6 @@ # Queries -Once data has been persisted into your storage backend, you can retrieve it by querying the [GraphQL API server](../graphql/api-server.md). By default, the API server can be reached at `http://localhost:29987/api/graph/:namespace/:identifier`, where `:namespace` and `:identifier` are the values for the respective fields in your indexer's manifest. If you've changed the `WEB_API_HOST` or `WEB_API_PORT` values of your configuration, then you'll need to adjust the URL accordingly. +Once data has been persisted into your storage backend, you can retrieve it by querying the [GraphQL API server](../getting-started/indexer-service-infrastructure.md#web-api-server). By default, the API server can be reached at `http://localhost:29987/api/graph/:namespace/:identifier`, where `:namespace` and `:identifier` are the values for the respective fields in your indexer's manifest. If you've changed the `WEB_API_HOST` or `WEB_API_PORT` values of your configuration, then you'll need to adjust the URL accordingly. ## Basic Query @@ -63,7 +63,7 @@ We're requesting the ID, height, and timestamp for each block stored in the back ## Nested Query -The Fuel indexer supports [foreign keys](../database/foreign-keys.md) on entity types; thus, you can also ask for information about a referenced entity inside of your query. A nested query has the following general structure: +The Fuel indexer supports [foreign keys](../designing-a-schema/relationships.md) on entity types; thus, you can also ask for information about a referenced entity inside of your query. A nested query has the following general structure: ```graphql query { @@ -112,7 +112,7 @@ type Character @entity { } ``` -This schema uses implicit foreign keys to reference other entities; for more information on implicit and explicit foreign keys, please refer to the [Foreign Keys](../database/foreign-keys.md) section of the book. In this contrived example, we're storing information about characters that are found in books which are stored in libraries that can be found in cities. This will be the query that we use to retrieve the aforementioned data: +This schema uses implicit foreign keys to reference other entities; for more information on implicit and explicit foreign keys, please refer to the [Relationships](../designing-a-schema/relationships.md) section of the book. In this contrived example, we're storing information about characters that are found in books which are stored in libraries that can be found in cities. This will be the query that we use to retrieve the aforementioned data: ```graphql query { diff --git a/docs/src/queries/full-example.md b/docs/src/querying/full-example.md similarity index 97% rename from docs/src/queries/full-example.md rename to docs/src/querying/full-example.md index 942419c95..d5facc066 100644 --- a/docs/src/queries/full-example.md +++ b/docs/src/querying/full-example.md @@ -2,7 +2,7 @@ Finally, let's combine nested entities, filtering, and pagination into one complete example. -Sticking with the same block explorer example, let's say that we are looking for a particular transaction and its containing block, but we don't remember either of the hashes. All we know is that the total value of the transaction is greater than zero, it was sometime after the start of the `beta-3` testnet, and it was included as part of the first fifty blocks. Additionally, we don't want to parse through all the results at once, so we only want to look at two records at a time. Finally, we think that it may have been on the more recent side, so we want to check them in reverse chronological order. +Sticking with the same block explorer example, let's say that we are looking for a particular transaction and its containing block, but we don't remember either of the hashes. All we know is that the total value of the transaction is greater than zero, it was sometime after the start of the `beta-4` testnet, and it was included as part of the first fifty blocks. Additionally, we don't want to parse through all the results at once, so we only want to look at two records at a time. Finally, we think that it may have been on the more recent side, so we want to check them in reverse chronological order. Putting all of that together, we get the following query: diff --git a/docs/src/querying/index.md b/docs/src/querying/index.md new file mode 100644 index 000000000..bfcfe24dd --- /dev/null +++ b/docs/src/querying/index.md @@ -0,0 +1,7 @@ +# Queries + +- [Basic Queries](./basic-queries.md) +- [Pagination](./pagination.md) +- [Search & Filtering](./search-and-filtering.md) +- [Full Example](./full-example.md) +- [The GraphQL Playground](./playground.md) diff --git a/docs/src/queries/pagination.md b/docs/src/querying/pagination.md similarity index 100% rename from docs/src/queries/pagination.md rename to docs/src/querying/pagination.md diff --git a/docs/src/graphql/playground.md b/docs/src/querying/playground.md similarity index 63% rename from docs/src/graphql/playground.md rename to docs/src/querying/playground.md index 5e645a77b..ec2ed5f42 100644 --- a/docs/src/graphql/playground.md +++ b/docs/src/querying/playground.md @@ -6,10 +6,8 @@ Every public indexer can access the GraphQL playground of the Fuel indexer node ## Usage -To use the GraphQL playground to explor your indices, simply [start your indexer service](../getting-started/starting-the-fuel-indexer.md) - then open the following URL in your browser - where `namespace` and `identifier` correspond to the namespace and identifier of the index that you'd like to explore. +To use the GraphQL playground to explor your indices, simply [start your indexer service](../getting-started/indexer-service-infrastructure.md) - then open the following URL in your browser - where `namespace` and `identifier` correspond to the namespace and identifier of the index that you'd like to explore. ```bash http://localhost:29987/api/playground/:namespace/:identifier ``` - -> NOTE: On initial page render, the playground throws a 500. Don't worry about this, you should still be able to query. diff --git a/docs/src/queries/search-filtering.md b/docs/src/querying/search-and-filtering.md similarity index 100% rename from docs/src/queries/search-filtering.md rename to docs/src/querying/search-and-filtering.md diff --git a/docs/src/storing-records/index.md b/docs/src/storing-records/index.md new file mode 100644 index 000000000..2ac4384fe --- /dev/null +++ b/docs/src/storing-records/index.md @@ -0,0 +1,79 @@ +# Storing Info in a Database + +The Fuel indexer uses [PostgreSQL](https://github.com/docker-library/postgres/blob/2f6878ca854713264ebb27c1ba8530c884bcbca5/14/bullseye/Dockerfile) as the primary database. + +> 💡 We're open to supporting other storage solutions in the future. + +## Data Types + +Below is a mapping of GraphQL schema types to their Sway and database equivalents. Note that an empty cell denotes that there is no direct equivalent for the type in the corresponding domain. + +| GraphQL Scalar | Sway Type | Postgres Type | +--- | --- | --- +| Address | `b256` | varchar(64) | +| AssetId | `u8[32]` | varchar(64) | +| Blob | `str[]` | varchar(10485760) | +| BlockId | | varchar(64) | +| Boolean | `bool` | boolean | +| Bytes4 | `str[4]` | varchar(8) | +| Bytes8 | `str[8]` | varchar(16) | +| Bytes32 | `str[32]` | varchar(64) | +| Bytes64 | `str[64]` | varchar(128) | +| Charfield | `str[]` | varchar(255) | +| ContractId | `b256` | varchar(64) | +| HexString | `str[]` | varchar(10485760) | +| ID | | varchar(64) primary key | +| Int1 | `u8` | integer | +| Int4 | `u32` | integer | +| Int8 | `u64` | bigint | +| Int16 | | numeric(39,0) | +| Json | `str[]` | json | +| MessageId | `str[32]` | varchar(64) | +| Nonce | `str[32]` | varchar(64) | +| Salt | `str[32]` | varchar(64) | +| Signature | `str[64]` | varchar(128) | +| Tai64Timestamp | | varchar(128) | +| Timestamp | `u64` | timestamp | +| UID | | varchar(64) | +| UInt1 | `u8` | integer | +| UInt4 | `u32` | integer | +| UInt8 | `u64` | numeric(20, 0) | +| UInt16 | | numeric(39, 0) | +| Virtual | | json | + +## Example + +Let's define an `Event` struct in a Sway contract: + +```sway +struct Event { + id: u64, + address: Address, + block_height: u64, +} +``` + +The corresponding GraphQL schema to mirror this `Event` struct would resemble: + +```graphql +type Event @entity { + id: ID! + account: Address! + block_height: UInt8! +} +``` + +And finally, this GraphQL schema will generate the following Postgres schema: + +```text + Table "schema.event" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description +--------------+-------------+-----------+----------+---------+----------+-------------+--------------+------------- + id | bigint | | not null | | plain | | | + block_height | bigint | | not null | | plain | | | + address | varchar(64) | | not null | | plain | | | + object | bytea | | not null | | extended | | | +Indexes: + "event_pkey" PRIMARY KEY, btree (id) +Access method: heap +``` diff --git a/examples/fuel-explorer/README.md b/examples/fuel-explorer/README.md index cedc46ca2..20a7f8ff8 100644 --- a/examples/fuel-explorer/README.md +++ b/examples/fuel-explorer/README.md @@ -43,7 +43,7 @@ query { ``` > IMPORTANT: Since this example uses a dockerized indexer service, with the GraphQL -> web API being bound at interface `0.0.0.0` your LAN IP might differ from the +> web server being bound at interface `0.0.0.0` your LAN IP might differ from the > `192.168.1.34` mentioned above. > > On *nix platforms you can typically find your LAN IP via `ifconfig | grep inet` \ No newline at end of file diff --git a/examples/hello-world-native/README.md b/examples/hello-world-native/README.md index f51b65e7b..e5ddecd01 100644 --- a/examples/hello-world-native/README.md +++ b/examples/hello-world-native/README.md @@ -52,7 +52,7 @@ query { ``` > IMPORTANT: Since this example uses a dockerized indexer service, with the GraphQL -> web API being bound at interface `0.0.0.0` your LAN IP might differ from the +> web server being bound at interface `0.0.0.0` your LAN IP might differ from the > `192.168.1.34` mentioned above. > > On *nix platforms you can typically find your LAN IP via `ifconfig | grep inet` \ No newline at end of file diff --git a/examples/hello-world-native/hello-indexer-native/schema/hello_indexer_native.schema.graphql b/examples/hello-world-native/hello-indexer-native/schema/hello_indexer_native.schema.graphql index 8e6997378..98a900b13 100644 --- a/examples/hello-world-native/hello-indexer-native/schema/hello_indexer_native.schema.graphql +++ b/examples/hello-world-native/hello-indexer-native/schema/hello_indexer_native.schema.graphql @@ -2,17 +2,13 @@ type Greeter @entity { id: ID! name: Charfield! - first_seen: UInt4! last_seen: UInt4! - visits: Blob! } # Calling this `Salutation` so as to not clash with `Greeting` in the contract type Salutation @entity { id: ID! - message_hash: Bytes32! message: Charfield! greeter: Greeter! - first_seen: UInt4! last_seen: UInt4! } diff --git a/examples/hello-world-native/hello-indexer-native/src/main.rs b/examples/hello-world-native/hello-indexer-native/src/main.rs index 7ba4340a2..9b1d4d9d7 100644 --- a/examples/hello-world-native/hello-indexer-native/src/main.rs +++ b/examples/hello-world-native/hello-indexer-native/src/main.rs @@ -28,22 +28,17 @@ use fuel_indexer_utils::prelude::*; )] mod hello_world_native { - async fn index_logged_greeting(event: Greeting, block: BlockData) { - let greeting = event.greeting.to_right_trimmed_str().to_string(); + async fn index_logged_greeting(event: Greeting, block_data: BlockData) { + let height = std::cmp::min(0, block_data.header.height - 1); let name = event.person.name.to_right_trimmed_str().to_string(); - let height = block.height; - let data = vec![1u8, 2, 3, 4, 5, 6, 7, 8].into(); - let greeter = Greeter::new(name.clone(), height, height, data) - .get_or_create() - .await; - + let greeting = event.greeting.to_right_trimmed_str().to_string(); let message = format!("{greeting} 👋, my name is {name}"); - let message_hash = bytes32(&message); - let salutation = - Salutation::new(message_hash, message, greeter.id.clone(), height, height) - .get_or_create() - .await; + let greeter = Greeter::new(name, height).get_or_create().await; + + let salutation = Salutation::new(message, greeter.id.clone(), height) + .get_or_create() + .await; greeter.save().await; salutation.save().await; diff --git a/examples/hello-world/README.md b/examples/hello-world/README.md index 434edb236..3bc0af5f0 100644 --- a/examples/hello-world/README.md +++ b/examples/hello-world/README.md @@ -50,7 +50,7 @@ query { ``` > IMPORTANT: Since this example uses a dockerized indexer service, with the GraphQL -> web API being bound at interface `0.0.0.0` your LAN IP might differ from the +> web server being bound at interface `0.0.0.0` your LAN IP might differ from the > `192.168.1.34` mentioned above. > > On *nix platforms you can typically find your LAN IP via `ifconfig | grep inet` diff --git a/examples/hello-world/hello-indexer/schema/hello_indexer.schema.graphql b/examples/hello-world/hello-indexer/schema/hello_indexer.schema.graphql index 8e6997378..98a900b13 100644 --- a/examples/hello-world/hello-indexer/schema/hello_indexer.schema.graphql +++ b/examples/hello-world/hello-indexer/schema/hello_indexer.schema.graphql @@ -2,17 +2,13 @@ type Greeter @entity { id: ID! name: Charfield! - first_seen: UInt4! last_seen: UInt4! - visits: Blob! } # Calling this `Salutation` so as to not clash with `Greeting` in the contract type Salutation @entity { id: ID! - message_hash: Bytes32! message: Charfield! greeter: Greeter! - first_seen: UInt4! last_seen: UInt4! } diff --git a/examples/hello-world/hello-indexer/src/lib.rs b/examples/hello-world/hello-indexer/src/lib.rs index e60f37431..f6a77c2c6 100644 --- a/examples/hello-world/hello-indexer/src/lib.rs +++ b/examples/hello-world/hello-indexer/src/lib.rs @@ -32,19 +32,16 @@ use fuel_indexer_utils::prelude::*; #[indexer(manifest = "examples/hello-world/hello-indexer/hello_indexer.manifest.yaml")] mod hello_world_indexer { - fn index_logged_greeting(event: Greeting, block: BlockData) { - let greeting = event.greeting.to_right_trimmed_str().to_string(); + fn index_logged_greeting(event: Greeting, block_data: BlockData) { + let height = std::cmp::min(0, block_data.header.height - 1); let name = event.person.name.to_right_trimmed_str().to_string(); - let height = block.height; - let data = vec![1u8, 2, 3, 4, 5, 6, 7, 8].into(); - let greeter = Greeter::new(name.clone(), height, height, data).get_or_create(); - + let greeting = event.greeting.to_right_trimmed_str().to_string(); let message = format!("{greeting} 👋, my name is {name}"); - let message_hash = bytes32(&message); + + let greeter = Greeter::new(name, height).get_or_create(); let salutation = - Salutation::new(message_hash, message, greeter.id.clone(), height, height) - .get_or_create(); + Salutation::new(message, greeter.id.clone(), height).get_or_create(); greeter.save(); salutation.save(); diff --git a/packages/fuel-indexer-api-server/src/api.rs b/packages/fuel-indexer-api-server/src/api.rs index 5aba634a1..bd772bb93 100644 --- a/packages/fuel-indexer-api-server/src/api.rs +++ b/packages/fuel-indexer-api-server/src/api.rs @@ -41,7 +41,7 @@ use tower_http::{ }; use tracing::{error, Level}; -/// Result type returned by web API operations. +/// Result type returned by web server operations. pub type ApiResult = core::result::Result; /// Size of the buffer for reqeusts being passed to the `RateLimitLayer`. @@ -70,7 +70,7 @@ impl From for HttpError { } } -/// Error type returned by web API operations. +/// Error type returned by web server operations. #[derive(Debug, Error)] pub enum ApiError { #[error("Query builder error {0:?}")] diff --git a/packages/fuel-indexer-api-server/src/models.rs b/packages/fuel-indexer-api-server/src/models.rs index 1cddffacd..2b1d19210 100644 --- a/packages/fuel-indexer-api-server/src/models.rs +++ b/packages/fuel-indexer-api-server/src/models.rs @@ -12,7 +12,7 @@ pub struct VerifySignatureRequest { pub message: String, } -/// GraphQL web API response. +/// GraphQL web server response. #[derive(Serialize)] pub(crate) struct QueryResponse { /// Arbitrarily sized JSON response. @@ -74,7 +74,7 @@ impl Claims { } } -/// A SQL query posted to the web API. +/// A SQL query posted to the web server. #[derive(Serialize, Deserialize, Clone, Debug)] pub struct SqlQuery { /// The literal raw SQL query. diff --git a/packages/fuel-indexer-api-server/src/sql.rs b/packages/fuel-indexer-api-server/src/sql.rs index 3d002ead0..2545d7fdf 100644 --- a/packages/fuel-indexer-api-server/src/sql.rs +++ b/packages/fuel-indexer-api-server/src/sql.rs @@ -15,7 +15,7 @@ pub enum SqlValidatorError { /// A validator for SQL queries. /// -/// Intended to ensure that users posting raw SQL queries to web API endpoints +/// Intended to ensure that users posting raw SQL queries to web server endpoints /// are not attempting to do anything malicious. pub struct SqlQueryValidator; diff --git a/packages/fuel-indexer-lib/src/config/cli.rs b/packages/fuel-indexer-lib/src/config/cli.rs index 167608f02..798c9e570 100644 --- a/packages/fuel-indexer-lib/src/config/cli.rs +++ b/packages/fuel-indexer-lib/src/config/cli.rs @@ -63,8 +63,8 @@ pub struct IndexerArgs { #[clap(long, help = "Database type.", default_value = defaults::DATABASE, value_parser(["postgres"]))] pub database: String, - /// Max body size for web API requests. - #[clap(long, help = "Max body size for web API requests.", default_value_t = defaults::MAX_BODY_SIZE )] + /// Max body size for web server requests. + #[clap(long, help = "Max body size for web server requests.", default_value_t = defaults::MAX_BODY_SIZE )] pub max_body_size: usize, /// Postgres username. @@ -184,8 +184,8 @@ pub struct IndexerArgs { )] pub remove_data: bool, - /// Allow the web API to accept raw SQL queries. - #[clap(long, help = "Allow the web API to accept raw SQL queries.")] + /// Allow the web server to accept raw SQL queries. + #[clap(long, help = "Allow the web server to accept raw SQL queries.")] pub accept_sql_queries: bool, /// Amount of blocks to return in a request to a Fuel node. @@ -196,7 +196,7 @@ pub struct IndexerArgs { #[derive(Debug, Parser, Clone)] #[clap( name = "Fuel Indexer API Server", - about = "Fuel indexer web API", + about = "Fuel indexer web server", version )] pub struct ApiServerArgs { @@ -236,7 +236,7 @@ pub struct ApiServerArgs { #[clap(long, help = "Database type.", default_value = defaults::DATABASE, value_parser(["postgres"]))] pub database: String, - /// Max body size for web API requests. + /// Max body size for web server requests. #[clap(long, help = "Max body size for web requests.", default_value_t = defaults::MAX_BODY_SIZE )] pub max_body_size: usize, @@ -313,7 +313,7 @@ pub struct ApiServerArgs { #[clap(long, help = "Number of seconds over which to allow --rate-limit-rps.")] pub rate_limit_window_size: Option, - /// Allow the web API to accept raw SQL queries. - #[clap(long, help = "Allow the web API to accept raw SQL queries.")] + /// Allow the web server to accept raw SQL queries. + #[clap(long, help = "Allow the web server to accept raw SQL queries.")] pub accept_sql_queries: bool, } diff --git a/packages/fuel-indexer-lib/src/config/web.rs b/packages/fuel-indexer-lib/src/config/web.rs index 0506c8417..5dc92189e 100644 --- a/packages/fuel-indexer-lib/src/config/web.rs +++ b/packages/fuel-indexer-lib/src/config/web.rs @@ -19,7 +19,7 @@ pub struct WebApiConfig { #[serde(default)] pub port: String, - /// Max body size for web API requests. + /// Max body size for web server requests. #[serde(default)] pub max_body_size: usize, } diff --git a/packages/fuel-indexer-lib/src/defaults.rs b/packages/fuel-indexer-lib/src/defaults.rs index 2e88f6590..14d5c4e2d 100644 --- a/packages/fuel-indexer-lib/src/defaults.rs +++ b/packages/fuel-indexer-lib/src/defaults.rs @@ -132,5 +132,5 @@ pub const REPLACE_INDEXER: bool = false; /// Whether to remove the indexed data when replacing an indexer. pub const REMOVE_DATA: bool = false; -/// Allow the web API to accept raw SQL queries. +/// Allow the web server to accept raw SQL queries. pub const ACCEPT_SQL: bool = false; diff --git a/packages/fuel-indexer-macros/src/helpers.rs b/packages/fuel-indexer-macros/src/helpers.rs index ad3e33670..72734a404 100644 --- a/packages/fuel-indexer-macros/src/helpers.rs +++ b/packages/fuel-indexer-macros/src/helpers.rs @@ -746,6 +746,31 @@ pub fn can_derive_id(field_set: &HashSet, field_name: &str) -> bool { && field_name != IdCol::to_lowercase_str() } +/// Strip the call path from the type field of a `TypeDeclaration`. +/// +/// It is possible that the type field for a `TypeDeclaration` contains a +/// fully-qualified path (e.g. `std::address::Address` as opposed to `Address`). +/// Path separators are not allowed to be used as part of an identifier, so this +/// function removes the qualifying path while keeping the type keyword. +pub fn strip_callpath_from_type_field(mut typ: TypeDeclaration) -> TypeDeclaration { + if is_non_decodable_type(&typ) { + return typ; + } + + let mut s = typ.type_field.split_whitespace(); + typ.type_field = + if let (Some(keyword), Some(fully_qualified_type_path)) = (s.next(), s.last()) { + if let Some(slug) = fully_qualified_type_path.split("::").last() { + [keyword, slug].join(" ") + } else { + unreachable!("All types should be formed with a keyword and call path") + } + } else { + typ.type_field + }; + typ +} + /// Simply represents a value for a generic type. #[derive(Debug)] pub enum GenericType { diff --git a/packages/fuel-indexer-macros/src/indexer.rs b/packages/fuel-indexer-macros/src/indexer.rs index b9bba7316..ba476c985 100644 --- a/packages/fuel-indexer-macros/src/indexer.rs +++ b/packages/fuel-indexer-macros/src/indexer.rs @@ -45,7 +45,12 @@ fn process_fn_items( let mut abi_dispatchers = Vec::new(); let funcs = abi.clone().functions; - let abi_types = abi.clone().types; + let abi_types: Vec = abi + .clone() + .types + .iter() + .map(|t| strip_callpath_from_type_field(t.clone())) + .collect(); let abi_log_types = abi.clone().logged_types.unwrap_or_default(); let abi_msg_types = abi.clone().messages_types.unwrap_or_default(); let fuel_types = FUEL_PRIMITIVES diff --git a/packages/fuel-indexer-tests/contracts/fuel-indexer-test/out/debug/fuel-indexer-test-abi.json b/packages/fuel-indexer-tests/contracts/fuel-indexer-test/out/debug/fuel-indexer-test-abi.json index ea9eaa56a..56bfc5415 100644 --- a/packages/fuel-indexer-tests/contracts/fuel-indexer-test/out/debug/fuel-indexer-test-abi.json +++ b/packages/fuel-indexer-tests/contracts/fuel-indexer-test/out/debug/fuel-indexer-test-abi.json @@ -17,7 +17,7 @@ }, { "name": "__tuple_element", - "type": 30, + "type": 27, "typeArguments": null } ], @@ -102,17 +102,17 @@ "components": [ { "name": "Ping", - "type": 24, + "type": 22, "typeArguments": null }, { "name": "Pung", - "type": 26, + "type": 24, "typeArguments": null }, { "name": "Call", - "type": 11, + "type": 9, "typeArguments": null } ], @@ -120,16 +120,11 @@ }, { "typeId": 8, - "type": "enum Identity", + "type": "enum NestedEnum", "components": [ { - "name": "Address", - "type": 19, - "typeArguments": null - }, - { - "name": "ContractId", - "type": 21, + "name": "Inner", + "type": 7, "typeArguments": null } ], @@ -137,11 +132,21 @@ }, { "typeId": 9, - "type": "enum NestedEnum", + "type": "enum SimpleEnum", "components": [ { - "name": "Inner", - "type": 7, + "name": "One", + "type": 0, + "typeArguments": null + }, + { + "name": "Two", + "type": 0, + "typeArguments": null + }, + { + "name": "Three", + "type": 0, "typeArguments": null } ], @@ -149,40 +154,28 @@ }, { "typeId": 10, - "type": "enum Option", + "type": "enum UserError", "components": [ { - "name": "None", + "name": "Unauthorized", "type": 0, "typeArguments": null - }, - { - "name": "Some", - "type": 13, - "typeArguments": null } ], - "typeParameters": [ - 13 - ] + "typeParameters": null }, { "typeId": 11, - "type": "enum SimpleEnum", + "type": "enum std::identity::Identity", "components": [ { - "name": "One", - "type": 0, - "typeArguments": null - }, - { - "name": "Two", - "type": 0, + "name": "Address", + "type": 28, "typeArguments": null }, { - "name": "Three", - "type": 0, + "name": "ContractId", + "type": 29, "typeArguments": null } ], @@ -190,15 +183,22 @@ }, { "typeId": 12, - "type": "enum UserError", + "type": "enum std::option::Option", "components": [ { - "name": "Unauthorized", + "name": "None", "type": 0, "typeArguments": null + }, + { + "name": "Some", + "type": 13, + "typeArguments": null } ], - "typeParameters": null + "typeParameters": [ + 13 + ] }, { "typeId": 13, @@ -238,18 +238,6 @@ }, { "typeId": 19, - "type": "struct Address", - "components": [ - { - "name": "value", - "type": 5, - "typeArguments": null - } - ], - "typeParameters": null - }, - { - "typeId": 20, "type": "struct ComplexTupleStruct", "components": [ { @@ -261,19 +249,7 @@ "typeParameters": null }, { - "typeId": 21, - "type": "struct ContractId", - "components": [ - { - "name": "value", - "type": 5, - "typeArguments": null - } - ], - "typeParameters": null - }, - { - "typeId": 22, + "typeId": 20, "type": "struct ExampleMessageStruct", "components": [ { @@ -290,7 +266,7 @@ "typeParameters": null }, { - "typeId": 23, + "typeId": 21, "type": "struct ExplicitQueryStruct", "components": [ { @@ -302,7 +278,7 @@ "typeParameters": null }, { - "typeId": 24, + "typeId": 22, "type": "struct Ping", "components": [ { @@ -324,7 +300,7 @@ "typeParameters": null }, { - "typeId": 25, + "typeId": 23, "type": "struct Pong", "components": [ { @@ -341,7 +317,7 @@ "typeParameters": null }, { - "typeId": 26, + "typeId": 24, "type": "struct Pung", "components": [ { @@ -361,34 +337,39 @@ }, { "name": "pung_from", - "type": 8, + "type": 11, "typeArguments": null } ], "typeParameters": null }, { - "typeId": 27, - "type": "struct RawVec", + "typeId": 25, + "type": "struct SimpleQueryStruct", "components": [ { - "name": "ptr", - "type": 14, + "name": "id", + "type": 33, "typeArguments": null - }, + } + ], + "typeParameters": null + }, + { + "typeId": 26, + "type": "struct SimpleTupleStruct", + "components": [ { - "name": "cap", - "type": 33, + "name": "data", + "type": 4, "typeArguments": null } ], - "typeParameters": [ - 13 - ] + "typeParameters": null }, { - "typeId": 28, - "type": "struct SimpleQueryStruct", + "typeId": 27, + "type": "struct TupleStructItem", "components": [ { "name": "id", @@ -398,13 +379,25 @@ ], "typeParameters": null }, + { + "typeId": 28, + "type": "struct std::address::Address", + "components": [ + { + "name": "value", + "type": 5, + "typeArguments": null + } + ], + "typeParameters": null + }, { "typeId": 29, - "type": "struct SimpleTupleStruct", + "type": "struct std::contract_id::ContractId", "components": [ { - "name": "data", - "type": 4, + "name": "value", + "type": 5, "typeArguments": null } ], @@ -412,23 +405,30 @@ }, { "typeId": 30, - "type": "struct TupleStructItem", + "type": "struct std::vec::RawVec", "components": [ { - "name": "id", + "name": "ptr", + "type": 14, + "typeArguments": null + }, + { + "name": "cap", "type": 33, "typeArguments": null } ], - "typeParameters": null + "typeParameters": [ + 13 + ] }, { "typeId": 31, - "type": "struct Vec", + "type": "struct std::vec::Vec", "components": [ { "name": "buf", - "type": 27, + "type": 30, "typeArguments": [ { "name": "", @@ -487,7 +487,7 @@ "name": "trigger_callreturn", "output": { "name": "", - "type": 26, + "type": 24, "typeArguments": null }, "attributes": null @@ -497,7 +497,7 @@ "name": "trigger_deeply_nested", "output": { "name": "", - "type": 28, + "type": 25, "typeArguments": null }, "attributes": null @@ -533,7 +533,7 @@ "name": "trigger_explicit", "output": { "name": "", - "type": 23, + "type": 21, "typeArguments": null }, "attributes": null @@ -543,11 +543,11 @@ "name": "trigger_generics", "output": { "name": "", - "type": 10, + "type": 12, "typeArguments": [ { "name": "", - "type": 24, + "type": 22, "typeArguments": null } ] @@ -604,7 +604,7 @@ "name": "trigger_multiargs", "output": { "name": "", - "type": 24, + "type": 22, "typeArguments": null }, "attributes": null @@ -624,7 +624,7 @@ "name": "trigger_ping", "output": { "name": "", - "type": 24, + "type": 22, "typeArguments": null }, "attributes": null @@ -634,7 +634,7 @@ "name": "trigger_ping_for_optional", "output": { "name": "", - "type": 24, + "type": 22, "typeArguments": null }, "attributes": null @@ -644,7 +644,7 @@ "name": "trigger_pong", "output": { "name": "", - "type": 25, + "type": 23, "typeArguments": null }, "attributes": null @@ -714,7 +714,7 @@ "name": "trigger_tuple", "output": { "name": "", - "type": 20, + "type": 19, "typeArguments": null }, "attributes": null @@ -765,7 +765,7 @@ "logId": 1, "loggedType": { "name": "", - "type": 9, + "type": 8, "typeArguments": [] } }, @@ -773,7 +773,7 @@ "logId": 2, "loggedType": { "name": "", - "type": 12, + "type": 10, "typeArguments": [] } }, @@ -781,11 +781,11 @@ "logId": 3, "loggedType": { "name": "", - "type": 10, + "type": 12, "typeArguments": [ { "name": "", - "type": 24, + "type": 22, "typeArguments": [] } ] @@ -799,7 +799,7 @@ "typeArguments": [ { "name": "", - "type": 24, + "type": 22, "typeArguments": [] } ] @@ -817,7 +817,7 @@ "logId": 6, "loggedType": { "name": "", - "type": 26, + "type": 24, "typeArguments": [] } }, @@ -825,7 +825,7 @@ "logId": 7, "loggedType": { "name": "", - "type": 26, + "type": 24, "typeArguments": [] } }, @@ -833,7 +833,7 @@ "logId": 8, "loggedType": { "name": "", - "type": 25, + "type": 23, "typeArguments": [] } }, @@ -849,7 +849,7 @@ "logId": 10, "loggedType": { "name": "", - "type": 29, + "type": 26, "typeArguments": [] } }, @@ -869,7 +869,7 @@ "typeArguments": [ { "name": "", - "type": 25, + "type": 23, "typeArguments": [] } ] @@ -881,7 +881,7 @@ "messageId": 0, "messageType": { "name": "", - "type": 22, + "type": 20, "typeArguments": [] } } diff --git a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__forc_index_start_help_output.snap b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__forc_index_start_help_output.snap index 2cc462b08..d7fac7506 100644 --- a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__forc_index_start_help_output.snap +++ b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__forc_index_start_help_output.snap @@ -9,7 +9,7 @@ USAGE: OPTIONS: --accept-sql-queries - Allow the web API to accept raw SQL queries. + Allow the web server to accept raw SQL queries. --auth-enabled Require users to authenticate for some operations. @@ -61,7 +61,7 @@ OPTIONS: Indexer config file. --max-body-size - Max body size for web API requests. [default: 5242880] + Max body size for web server requests. [default: 5242880] --metering-points The number of WASM opcodes after which the indexer's event handler will stop execution. diff --git a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_api_server_help_output.snap b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_api_server_help_output.snap index 62f934cb6..f3bb86d04 100644 --- a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_api_server_help_output.snap +++ b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_api_server_help_output.snap @@ -13,4 +13,4 @@ OPTIONS: SUBCOMMANDS: help Print this message or the help of the given subcommand(s) - run Fuel indexer web API + run Fuel indexer web server diff --git a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_api_server_run_help_output.snap b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_api_server_run_help_output.snap index afe11352d..1564a42e7 100644 --- a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_api_server_run_help_output.snap +++ b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_api_server_run_help_output.snap @@ -2,14 +2,14 @@ source: packages/fuel-indexer-tests/tests/commands.rs expression: output --- -Fuel indexer web API +Fuel indexer web server USAGE: fuel-indexer-api-server run [OPTIONS] OPTIONS: --accept-sql-queries - Allow the web API to accept raw SQL queries. + Allow the web server to accept raw SQL queries. --auth-enabled Require users to authenticate for some operations. diff --git a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_run_help_output.snap b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_run_help_output.snap index 939df7f58..46f9952af 100644 --- a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_run_help_output.snap +++ b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__commands__fuel_indexer_run_help_output.snap @@ -9,7 +9,7 @@ USAGE: OPTIONS: --accept-sql-queries - Allow the web API to accept raw SQL queries. + Allow the web server to accept raw SQL queries. --auth-enabled Require users to authenticate for some operations. @@ -61,7 +61,7 @@ OPTIONS: Indexer config file. --max-body-size - Max body size for web API requests. [default: 5242880] + Max body size for web server requests. [default: 5242880] --metering-points The number of WASM opcodes after which the indexer's event handler will stop execution. diff --git a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__forc_index_start_help_output.snap b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__forc_index_start_help_output.snap index df6bc81e4..fb5e7a9c2 100644 --- a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__forc_index_start_help_output.snap +++ b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__forc_index_start_help_output.snap @@ -9,7 +9,7 @@ USAGE: OPTIONS: --accept-sql-queries - Allow the web API to accept raw SQL queries. + Allow the web server to accept raw SQL queries. --auth-enabled Require users to authenticate for some operations. @@ -61,7 +61,7 @@ OPTIONS: Indexer config file. --max-body-size - Max body size for web API requests. [default: 5242880] + Max body size for web server requests. [default: 5242880] --metering-points The number of WASM opcodes after which the indexer's event handler will stop execution. diff --git a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_api_server_help_output.snap b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_api_server_help_output.snap index 445bc01b9..a0b2193b3 100644 --- a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_api_server_help_output.snap +++ b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_api_server_help_output.snap @@ -13,4 +13,4 @@ OPTIONS: SUBCOMMANDS: help Print this message or the help of the given subcommand(s) - run Fuel indexer web API + run Fuel indexer web server diff --git a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_api_server_run_help_output.snap b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_api_server_run_help_output.snap index dbd54724b..e3c217c1f 100644 --- a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_api_server_run_help_output.snap +++ b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_api_server_run_help_output.snap @@ -2,14 +2,14 @@ source: packages/fuel-indexer-tests/tests/snapshots.rs expression: output --- -Fuel indexer web API +Fuel indexer web server USAGE: fuel-indexer-api-server run [OPTIONS] OPTIONS: --accept-sql-queries - Allow the web API to accept raw SQL queries. + Allow the web server to accept raw SQL queries. --auth-enabled Require users to authenticate for some operations. diff --git a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_run_help_output.snap b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_run_help_output.snap index 6d6d3ba40..48aeb1018 100644 --- a/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_run_help_output.snap +++ b/packages/fuel-indexer-tests/tests/snapshots/integration_tests__snapshots__fuel_indexer_run_help_output.snap @@ -9,7 +9,7 @@ USAGE: OPTIONS: --accept-sql-queries - Allow the web API to accept raw SQL queries. + Allow the web server to accept raw SQL queries. --auth-enabled Require users to authenticate for some operations. @@ -61,7 +61,7 @@ OPTIONS: Indexer config file. --max-body-size - Max body size for web API requests. [default: 5242880] + Max body size for web server requests. [default: 5242880] --metering-points The number of WASM opcodes after which the indexer's event handler will stop execution. diff --git a/packages/fuel-indexer-tests/trybuild/invalid_abi_type_simple_wasm.yaml b/packages/fuel-indexer-tests/trybuild/invalid_abi_type_simple_wasm.yaml new file mode 100644 index 000000000..374a79f92 --- /dev/null +++ b/packages/fuel-indexer-tests/trybuild/invalid_abi_type_simple_wasm.yaml @@ -0,0 +1,8 @@ + + namespace: test_namespace + identifier: simple_wasm_executor + abi: /Users/rashad/dev/repos/fuel-indexer/packages/fuel-indexer-tests/contracts/simple-wasm/out/debug/contracts-abi-reserved-name.json + graphql_schema: /Users/rashad/dev/repos/fuel-indexer/packages/fuel-indexer-tests/indexers/simple-wasm/schema/simple_wasm.graphql + contract_id: ~ + module: + wasm: /Users/rashad/dev/repos/fuel-indexer/target/wasm32-unknown-unknown/release/simple_wasm.wasm \ No newline at end of file diff --git a/packages/fuel-indexer-tests/trybuild/invalid_schema_simple_wasm.yaml b/packages/fuel-indexer-tests/trybuild/invalid_schema_simple_wasm.yaml new file mode 100644 index 000000000..93680770e --- /dev/null +++ b/packages/fuel-indexer-tests/trybuild/invalid_schema_simple_wasm.yaml @@ -0,0 +1,9 @@ + + namespace: test_namespace + identifier: simple_wasm_executor + abi: /Users/rashad/dev/repos/fuel-indexer/packages/fuel-indexer-tests/contracts/simple-wasm/out/debug/contracts-abi.json + # This schema file doesn't actually exist + graphql_schema: schema.graphql + contract_id: ~ + module: + wasm: /Users/rashad/dev/repos/fuel-indexer/target/wasm32-unknown-unknown/release/simple_wasm.wasm \ No newline at end of file diff --git a/packages/fuel-indexer/src/executor.rs b/packages/fuel-indexer/src/executor.rs index ee97c84a1..02df80f4b 100644 --- a/packages/fuel-indexer/src/executor.rs +++ b/packages/fuel-indexer/src/executor.rs @@ -422,7 +422,23 @@ pub async fn retrieve_blocks_from_node( salt: <[u8; 32]>::from(*tx.salt()).into(), metadata: None, }), - _ => Transaction::default(), + ClientTransaction::Script(tx) => Transaction::Script(Script { + gas_price: *tx.gas_price(), + gas_limit: *tx.gas_limit(), + maturity: *tx.maturity(), + script: (*tx.script().clone()).to_vec(), + script_data: (*tx.script_data().clone()).to_vec(), + inputs: tx.inputs().iter().map(|i| i.to_owned().into()).collect(), + outputs: tx.outputs().iter().map(|o| o.to_owned().into()).collect(), + witnesses: tx.witnesses().to_vec(), + receipts_root: <[u8; 32]>::from(*tx.receipts_root()).into(), + metadata: None, + }), + ClientTransaction::Mint(tx) => Transaction::Mint(Mint { + tx_pointer: tx.tx_pointer().to_owned().into(), + outputs: tx.outputs().iter().map(|o| o.to_owned().into()).collect(), + metadata: None, + }), }; let tx_data = TransactionData { diff --git a/packages/fuel-indexer/src/service.rs b/packages/fuel-indexer/src/service.rs index a7a01e49f..78c8646db 100644 --- a/packages/fuel-indexer/src/service.rs +++ b/packages/fuel-indexer/src/service.rs @@ -258,7 +258,7 @@ impl IndexerService { Ok(()) } - /// Kick it off! Run the indexer service loop, listening to service messages primarily coming from the web API. + /// Kick it off! Run the indexer service loop, listening to service messages primarily coming from the web server. pub async fn run(mut self) -> IndexerResult<()> { loop { tokio::select! { diff --git a/plugins/forc-index/README.md b/plugins/forc-index/README.md index b0cdc2a89..aaa9e2eb2 100644 --- a/plugins/forc-index/README.md +++ b/plugins/forc-index/README.md @@ -25,7 +25,7 @@ forc index start Deploy a given indexer project to a particular endpoint ```bash -forc index deploy --url https://beta-3-indexer.fuel.network +forc index deploy --url https://beta-4-indexer.fuel.network ``` ### `forc index remove` @@ -33,7 +33,7 @@ forc index deploy --url https://beta-3-indexer.fuel.network Kill a running indexer ```bash -forc index remove --url https://beta-3-indexer.fuel.network +forc index remove --url https://beta-4-indexer.fuel.network ``` ### `forc index check`