-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
38 changed files
with
581 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package decoding | ||
|
||
import ( | ||
"sort" | ||
|
||
"cosmossdk.io/schema" | ||
) | ||
|
||
// DecoderResolver is an interface that allows indexers to discover and use module decoders. | ||
type DecoderResolver interface { | ||
// IterateAll iterates over all available module decoders. | ||
IterateAll(func(moduleName string, cdc schema.ModuleCodec) error) error | ||
|
||
// LookupDecoder looks up a specific module decoder. | ||
LookupDecoder(moduleName string) (decoder schema.ModuleCodec, found bool, err error) | ||
} | ||
|
||
// ModuleSetDecoderResolver returns DecoderResolver that will discover modules implementing | ||
// DecodeableModule in the provided module set. | ||
func ModuleSetDecoderResolver(moduleSet map[string]interface{}) DecoderResolver { | ||
return &moduleSetDecoderResolver{ | ||
moduleSet: moduleSet, | ||
} | ||
} | ||
|
||
type moduleSetDecoderResolver struct { | ||
moduleSet map[string]interface{} | ||
} | ||
|
||
func (a moduleSetDecoderResolver) IterateAll(f func(string, schema.ModuleCodec) error) error { | ||
keys := make([]string, 0, len(a.moduleSet)) | ||
for k := range a.moduleSet { | ||
keys = append(keys, k) | ||
} | ||
sort.Strings(keys) | ||
for _, k := range keys { | ||
module := a.moduleSet[k] | ||
dm, ok := module.(schema.HasModuleCodec) | ||
if ok { | ||
decoder, err := dm.ModuleCodec() | ||
if err != nil { | ||
return err | ||
} | ||
err = f(k, decoder) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (a moduleSetDecoderResolver) LookupDecoder(moduleName string) (schema.ModuleCodec, bool, error) { | ||
mod, ok := a.moduleSet[moduleName] | ||
if !ok { | ||
return schema.ModuleCodec{}, false, nil | ||
} | ||
|
||
dm, ok := mod.(schema.HasModuleCodec) | ||
if !ok { | ||
return schema.ModuleCodec{}, false, nil | ||
} | ||
|
||
decoder, err := dm.ModuleCodec() | ||
return decoder, true, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package decoding | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"cosmossdk.io/schema" | ||
) | ||
|
||
type modA struct{} | ||
|
||
func (m modA) ModuleCodec() (schema.ModuleCodec, error) { | ||
return schema.ModuleCodec{ | ||
Schema: schema.ModuleSchema{ObjectTypes: []schema.ObjectType{{Name: "A"}}}, | ||
}, nil | ||
} | ||
|
||
type modB struct{} | ||
|
||
func (m modB) ModuleCodec() (schema.ModuleCodec, error) { | ||
return schema.ModuleCodec{ | ||
Schema: schema.ModuleSchema{ObjectTypes: []schema.ObjectType{{Name: "B"}}}, | ||
}, nil | ||
} | ||
|
||
type modC struct{} | ||
|
||
var moduleSet = map[string]interface{}{ | ||
"modA": modA{}, | ||
"modB": modB{}, | ||
"modC": modC{}, | ||
} | ||
|
||
var resolver = ModuleSetDecoderResolver(moduleSet) | ||
|
||
func TestModuleSetDecoderResolver_IterateAll(t *testing.T) { | ||
objectTypes := map[string]bool{} | ||
err := resolver.IterateAll(func(moduleName string, cdc schema.ModuleCodec) error { | ||
objectTypes[cdc.Schema.ObjectTypes[0].Name] = true | ||
return nil | ||
}) | ||
if err != nil { | ||
t.Fatalf("unexpected error: %v", err) | ||
} | ||
|
||
if len(objectTypes) != 2 { | ||
t.Fatalf("expected 2 object types, got %d", len(objectTypes)) | ||
} | ||
|
||
if !objectTypes["A"] { | ||
t.Fatalf("expected object type A") | ||
} | ||
|
||
if !objectTypes["B"] { | ||
t.Fatalf("expected object type B") | ||
} | ||
} | ||
|
||
func TestModuleSetDecoderResolver_LookupDecoder(t *testing.T) { | ||
decoder, found, err := resolver.LookupDecoder("modA") | ||
if err != nil { | ||
t.Fatalf("unexpected error: %v", err) | ||
} | ||
|
||
if !found { | ||
t.Fatalf("expected to find decoder for modA") | ||
} | ||
|
||
if decoder.Schema.ObjectTypes[0].Name != "A" { | ||
t.Fatalf("expected object type A, got %s", decoder.Schema.ObjectTypes[0].Name) | ||
} | ||
|
||
decoder, found, err = resolver.LookupDecoder("modB") | ||
if err != nil { | ||
t.Fatalf("unexpected error: %v", err) | ||
} | ||
|
||
if !found { | ||
t.Fatalf("expected to find decoder for modB") | ||
} | ||
|
||
if decoder.Schema.ObjectTypes[0].Name != "B" { | ||
t.Fatalf("expected object type B, got %s", decoder.Schema.ObjectTypes[0].Name) | ||
} | ||
|
||
decoder, found, err = resolver.LookupDecoder("modC") | ||
if err != nil { | ||
t.Fatalf("unexpected error: %v", err) | ||
} | ||
|
||
if found { | ||
t.Fatalf("expected not to find decoder") | ||
} | ||
|
||
decoder, found, err = resolver.LookupDecoder("modD") | ||
if err != nil { | ||
t.Fatalf("unexpected error: %v", err) | ||
} | ||
|
||
if found { | ||
t.Fatalf("expected not to find decoder") | ||
} | ||
} | ||
|
||
type modD struct{} | ||
|
||
func (m modD) ModuleCodec() (schema.ModuleCodec, error) { | ||
return schema.ModuleCodec{}, fmt.Errorf("an error") | ||
} | ||
|
||
func TestModuleSetDecoderResolver_IterateAll_Error(t *testing.T) { | ||
resolver := ModuleSetDecoderResolver(map[string]interface{}{ | ||
"modD": modD{}, | ||
}) | ||
err := resolver.IterateAll(func(moduleName string, cdc schema.ModuleCodec) error { | ||
if moduleName == "modD" { | ||
t.Fatalf("expected error") | ||
} | ||
return nil | ||
}) | ||
if err == nil { | ||
t.Fatalf("expected error") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package decoding | ||
|
||
// SyncSource is an interface that allows indexers to start indexing modules with pre-existing state. | ||
// It should generally be a wrapper around the key-value store. | ||
type SyncSource interface { | ||
// IterateAllKVPairs iterates over all key-value pairs for a given module. | ||
IterateAllKVPairs(moduleName string, fn func(key, value []byte) error) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Indexer Framework | ||
|
||
# Defining an Indexer | ||
|
||
Indexer implementations should be registered with the `indexer.Register` function with a unique type name. Indexers take the configuration options defined by `indexer.Config` which defines a common set of configuration options as well as indexer-specific options under the `config` sub-key. Indexers do not need to manage the common filtering options specified in `Config` - the indexer manager will manage these for the indexer. Indexer implementations just need to return a correct `InitResult` response. | ||
|
||
# Integrating the Indexer Manager | ||
|
||
The indexer manager should be used for managing all indexers and should be integrated directly with applications wishing to support indexing. The `StartManager` function is used to start the manager. The configuration options for the manager and all indexer targets should be passed as the ManagerOptions.Config field and should match the json structure of ManagerConfig. An example configuration section in `app.toml` might look like this: | ||
|
||
```toml | ||
[indexer.target.postgres] | ||
type = "postgres" | ||
config.database_url = "postgres://user:password@localhost:5432/dbname" | ||
``` |
Oops, something went wrong.