Skip to content

Commit 9c5bb5e

Browse files
authored
feat(docs): add documentation index and restructure README for clarity (#112)
1 parent ae61643 commit 9c5bb5e

File tree

9 files changed

+642
-566
lines changed

9 files changed

+642
-566
lines changed

.dockerignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.git
2+
.github
3+
.idea
4+
.vscode
5+
.gradle
6+
.gradle-home
7+
.gradle-user
8+
.kotlin
9+
.claude
10+
.DS_Store
11+
.swift-module-cache/
12+
13+
build/
14+
out/
15+
16+
docs/confluence/
17+
docs/temp.md

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,7 @@ bin/
3737
.vscode/
3838

3939
### Mac OS ###
40-
.DS_Store
40+
.DS_Store
41+
42+
### Local Tooling ###
43+
.swift-module-cache/

README.md

Lines changed: 63 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,94 @@
11
# Indexer Core
22

3-
This library provides the core functionality for building an indexer for VechainThor. It supports running multiple indexers concurrently with automatic dependency management and parallel processing.
3+
`indexer-core` provides the core building blocks for VeChainThor indexers. It supports fast log-based catch-up, full block processing when required, ABI and business-event decoding, dependency-aware execution, and rollback-safe reprocessing after reorgs.
44

5-
## Features
5+
## Requirements
66

7-
- **Parallel Processing**: Multiple indexers process blocks concurrently for maximum performance
8-
- **Dependency Management**: Automatically orders indexers based on their dependencies using topological sorting
9-
- **Retry Logic**: Built-in retry mechanisms for initialization, sync, and block processing
10-
- **Block Buffering**: Configurable buffering to optimize throughput
11-
- **Group Coordination**: Indexers with dependencies are organized into processing groups that maintain proper ordering
7+
- Java 21
8+
- Access to a Thor API endpoint
9+
- A persistence layer that can store the last synced block and roll back on reorgs
1210

13-
## Example usage
11+
## Installation
12+
13+
Gradle Kotlin DSL:
1414

1515
```kotlin
16-
@Configuration
17-
open class IndexerConfig() {
18-
19-
@Bean
20-
open fun myPruner(): Pruner = PrunerService()
21-
22-
@Bean
23-
open fun blockIndexer(myPruner: Pruner): Indexer =
24-
IndexerFactory()
25-
.name("BlockIndexer")
26-
.thorClient("https://mainnet.vechain.org", Pair("X-Project-Id", "my-indexer"))
27-
.processor(blockProcessor)
28-
.pruner(myPruner)
29-
.startBlock(0)
30-
.syncLoggerInterval(1000)
31-
.abis("/abis")
32-
.businessEvents("/business-events", "/abis")
33-
.includeVetTransfers()
34-
.build()
35-
36-
@Bean
37-
open fun transactionIndexer(blockIndexer: Indexer): Indexer =
38-
IndexerFactory()
39-
.name("TransactionIndexer")
40-
.thorClient("https://mainnet.vechain.org")
41-
.processor(txProcessor)
42-
.dependsOn(blockIndexer) // Ensures BlockIndexer processes blocks first
43-
.startBlock(0)
44-
.build()
45-
46-
@Bean
47-
open fun indexerRunner(
48-
scope: CoroutineScope,
49-
thorClient: ThorClient,
50-
blockIndexer: Indexer,
51-
transactionIndexer: Indexer
52-
): Job {
53-
return IndexerRunner.launch(
54-
scope = scope,
55-
thorClient = thorClient,
56-
indexers = listOf(blockIndexer, transactionIndexer),
57-
blockBatchSize = 10 // Buffer up to 10 blocks per group
58-
)
59-
}
16+
dependencies {
17+
implementation("org.vechain:indexer-core:8.0.3")
6018
}
6119
```
6220

63-
The `IndexerFactory` can be used to configure your indexer. The only required parameters are the `name`, `thorClient` and the `processor`.
64-
For details of the available configuration options, see the comments in the `IndexerFactory` class.
65-
21+
Gradle Groovy DSL:
6622

67-
## IndexerProcessor Implementation
23+
```groovy
24+
dependencies {
25+
implementation 'org.vechain:indexer-core:8.0.3'
26+
}
27+
```
6828

69-
An example of an `IndexerProcessor` implementation:
29+
## Quick Start
7030

7131
```kotlin
72-
@Component
73-
open class MyProcessor(
74-
private val myService: Service,
32+
class MyProcessor(
33+
private val repository: MyRepository,
7534
) : IndexerProcessor {
76-
override fun process(entry: IndexingResult) {
77-
if (entry.events().isEmpty()) {
78-
return
79-
}
80-
myService.processEvents(entry.events())
81-
}
35+
override fun getLastSyncedBlock(): BlockIdentifier? = repository.getLastSyncedBlock()
8236

8337
override fun rollback(blockNumber: Long) {
84-
myService.rollback(blockNumber)
38+
repository.rollbackFrom(blockNumber)
8539
}
8640

87-
override fun getLastSyncedBlock(): BlockIdentifier? {
88-
myService.getLatestRecord()?.let {
89-
return BlockIdentifier(number = it.blockNumber, id = it.blockId)
90-
}
91-
logger.info("No records found in repository, returning null")
92-
return null
41+
override suspend fun process(entry: IndexingResult) {
42+
when (entry) {
43+
is IndexingResult.LogResult -> repository.storeEvents(entry.endBlock, entry.events)
44+
is IndexingResult.BlockResult ->
45+
repository.storeBlock(entry.block, entry.events, entry.callResults)
46+
}
9347
}
9448
}
95-
```
9649

97-
## Architecture
50+
val thorClient = DefaultThorClient("https://mainnet.vechain.org")
51+
52+
val indexer =
53+
IndexerFactory()
54+
.name("example-indexer")
55+
.thorClient(thorClient)
56+
.processor(MyProcessor(repository))
57+
.startBlock(19_000_000)
58+
.build()
59+
60+
val job =
61+
IndexerRunner.launch(
62+
scope = scope,
63+
thorClient = thorClient,
64+
indexers = listOf(indexer),
65+
)
66+
```
9867

99-
### IndexerRunner
68+
## Choosing a Mode
10069

101-
The `IndexerRunner` coordinates multiple indexers:
70+
- Default `LogsIndexer`: best when you want the fastest catch-up path and only need decoded events or transfers.
71+
- `includeFullBlock()`: use when you need full block contents, reverted transactions, gas metadata, or clause inspection results.
72+
- `dependsOn(...)`: use when one indexer must finish a block before another processes that same block.
10273

103-
1. **Initialization Phase**: All indexers are initialized and fast-synced concurrently
104-
2. **Execution Phase**: Indexers are organized into dependency groups and process blocks in parallel
105-
- Groups are determined by topological sorting based on `dependsOn` relationships
106-
- Within each group, indexers process the same block **sequentially** in list order
107-
- Different groups can work on different blocks simultaneously (e.g., Group 2 on block N+1 while Group 1 on block N+2)
74+
Processors should handle both `IndexingResult.LogResult` and `IndexingResult.BlockResult`.
10875

109-
### Dependency Management
76+
## Documentation
11077

111-
The `IndexerOrderUtils` provides topological sorting to determine the correct processing order:
78+
The detailed documentation lives in [`docs/README.md`](docs/README.md) and is the canonical source of truth for library behavior.
11279

113-
```kotlin
114-
val indexer1 = createIndexer("Base")
115-
val indexer2 = createIndexer("DependentA", dependsOn = indexer1)
116-
val indexer3 = createIndexer("DependentB", dependsOn = indexer1)
117-
val indexer4 = createIndexer("FinalIndexer", dependsOn = indexer2)
80+
- [`docs/README.md`](docs/README.md): documentation index and navigation
81+
- [`docs/IndexerOverview.md`](docs/IndexerOverview.md): runtime model, lifecycle, runner behavior
82+
- [`docs/LogsIndexerOverview.md`](docs/LogsIndexerOverview.md): log-based indexing and fast sync
83+
- [`docs/EventsAndABIHandling.md`](docs/EventsAndABIHandling.md): ABI loading and event decoding
84+
- [`docs/BusinessEvents.md`](docs/BusinessEvents.md): business event definitions and matching
85+
- [`docs/MIGRATION-8.0.0.md`](docs/MIGRATION-8.0.0.md): 7.x to 8.x migration guide
11886

119-
// Results in groups: [[Base], [DependentA, DependentB], [FinalIndexer]]
120-
// DependentA and DependentB can process blocks in parallel
121-
```
87+
## Documentation Model
12288

123-
## Java compatibility
89+
To reduce drift:
12490

125-
When using the indexer-core package in a Java project, prefer using `startInCoroutine()` to start your indexer implementation,
126-
as the regular `start()` is a suspend function for which the caller has to supply a coroutine scope.
127-
Otherwise, the package is Java compatible as is.
91+
- keep `README.md` short and focused on overview plus quick start
92+
- keep detailed technical docs in `docs/`
93+
- treat the repo docs as the canonical source
94+
- use Confluence as a landing page that links to the repo docs instead of duplicating them manually

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jacoco {
2020

2121
group = "org.vechain"
2222

23-
val projectVersion = System.getenv("PROJECT_VERSION") ?: "8.0.2"
23+
val projectVersion = System.getenv("PROJECT_VERSION") ?: "8.0.3"
2424
version = projectVersion
2525

2626
val isSnapshot = version.toString().endsWith("SNAPSHOT")

0 commit comments

Comments
 (0)