Repository: algorand/indexer
Pull request #1493 (2023-03-03 16:49:25)

e2e-tests: Filter processor e2e test

## Summary
Adds a couple of filter scenarios to the conduit e2e tests.  
Also adds details on creating new e2e tests to the readme.  

For now I have not added indexer queries to these. They simply verify that the pipeline runs without error.

## Test Plan

`make e2e-conduit`


codecov[bot]: # [Codecov](https://codecov.io/gh/algorand/indexer/pull/1493?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand) Report
> Merging [#1493](https://codecov.io/gh/algorand/indexer/pull/1493?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand) (94cae3b) into [develop](https://codecov.io/gh/algorand/indexer/commit/93f02f5393f48d6eed2acb0a0ebbc4f34fba6c48?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand) (93f02f5) will **increase** coverage by `0.03%`.
> The diff coverage is `n/a`.

```diff
@@             Coverage Diff             @@
##           develop    #1493      +/-   ##
===========================================
+ Coverage    70.06%   70.10%   +0.03%     
===========================================
  Files           71       71              
  Lines         9699     9699              
===========================================
+ Hits          6796     6799       +3     
+ Misses        2407     2405       -2     
+ Partials       496      495       -1     
```


| [Impacted Files](https://codecov.io/gh/algorand/indexer/pull/1493?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand) | Coverage Δ | |
|---|---|---|
| [idb/postgres/postgres.go](https://codecov.io/gh/algorand/indexer/pull/1493?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand#diff-aWRiL3Bvc3RncmVzL3Bvc3RncmVzLmdv) | `66.72% <0.00%> (+0.13%)` | :arrow_up: |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand)


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 16a341d..08a5034 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -121,12 +121,6 @@ commands:
             pip3 install -r misc/requirements.txt
             pip3 install e2e_tests/
 
-      - run:
-          name: sync submodules (go-algorand)
-          command: |
-            git submodule sync
-            git submodule update --init
-
       - run: echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/.local/bin' >> $BASH_ENV
 
   install_linter:
diff --git a/Makefile b/Makefile
index 590196a..3b51fc1 100644
--- a/Makefile
+++ b/Makefile
@@ -25,18 +25,14 @@ COVERPKG := $(shell go list ./...  | grep -v '/cmd/' | egrep -v '(testing|test|m
 export GO_IMAGE = golang:$(shell go version | cut -d ' ' -f 3 | tail -c +3 )
 
 # This is the default target, build everything:
-all: conduit cmd/algorand-indexer/algorand-indexer go-algorand idb/postgres/internal/schema/setup_postgres_sql.go idb/mocks/IndexerDb.go
+all: conduit cmd/algorand-indexer/algorand-indexer idb/postgres/internal/schema/setup_postgres_sql.go idb/mocks/IndexerDb.go
 
-conduit: go-algorand
+conduit:
 	go generate ./... && cd cmd/conduit && go build -ldflags="${GOLDFLAGS}"
 
-cmd/algorand-indexer/algorand-indexer: idb/postgres/internal/schema/setup_postgres_sql.go go-algorand
+cmd/algorand-indexer/algorand-indexer: idb/postgres/internal/schema/setup_postgres_sql.go
 	cd cmd/algorand-indexer && go build -ldflags="${GOLDFLAGS}"
 
-go-algorand:
-	git submodule update --init && cd third_party/go-algorand && \
-		make crypto/libs/`scripts/ostype.sh`/`scripts/archtype.sh`/lib/libsodium.a
-
 idb/postgres/internal/schema/setup_postgres_sql.go:	idb/postgres/internal/schema/setup_postgres.sql
 	cd idb/postgres/internal/schema && go generate
 
@@ -45,16 +41,16 @@ idb/mocks/IndexerDb.go:	idb/idb.go
 	cd idb && mockery --name=IndexerDb
 
 # check that all packages (except tests) compile
-check: go-algorand
+check:
 	go build ./...
 
-package: go-algorand
+package:
 	rm -rf $(PKG_DIR)
 	mkdir -p $(PKG_DIR)
 	misc/release.py --host-only --outdir $(PKG_DIR)
 
 # used in travis test builds; doesn't verify that tag and .version match
-fakepackage: go-algorand
+fakepackage:
 	rm -rf $(PKG_DIR)
 	mkdir -p $(PKG_DIR)
 	misc/release.py --host-only --outdir $(PKG_DIR) --fake-release
@@ -62,7 +58,7 @@ fakepackage: go-algorand
 test: idb/mocks/IndexerDb.go cmd/algorand-indexer/algorand-indexer
 	go test -coverpkg=$(COVERPKG) ./... -coverprofile=coverage.txt -covermode=atomic ${TEST_FLAG}
 
-lint: go-algorand
+lint:
 	golangci-lint run -c .golangci.yml
 	go vet ./...
 
@@ -96,24 +92,7 @@ test-package:
 test-generate:
 	test/test_generate.py
 
-nightly-setup:
-	cd third_party/go-algorand && git fetch && git reset --hard origin/master
-
-nightly-teardown:
-	git submodule update
-
-indexer-v-algod-swagger:
+indexer-v-algod:
 	pytest -sv misc/parity
 
-indexer-v-algod: nightly-setup indexer-v-algod-swagger nightly-teardown
-
-# fetch and update submodule. it's default to latest rel/nightly branch.
-# to use a different branch, update the branch in .gitmodules for CI build,
-# and for local testing, you may checkout a specific branch in the submodule.
-# after submodule is updated, CI_E2E_FILENAME in .circleci/config.yml should
-# also be updated to use a newer artifact. path copied from s3 bucket,
-# s3://algorand-testdata/indexer/e2e4/
-update-submodule:
-	git submodule update --remote
-
-.PHONY: all test e2e integration fmt lint deploy sign test-package package fakepackage cmd/algorand-indexer/algorand-indexer idb/mocks/IndexerDb.go go-algorand indexer-v-algod conduit
+.PHONY: all test e2e integration fmt lint deploy sign test-package package fakepackage cmd/algorand-indexer/algorand-indexer idb/mocks/IndexerDb.go indexer-v-algod conduit
diff --git a/accounting/accounting.go b/accounting/accounting.go
deleted file mode 100644
index 0b93634..0000000
--- a/accounting/accounting.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package accounting
-
-import (
-	sdk "github.com/algorand/go-algorand-sdk/v2/types"
-)
-
-// GetTransactionParticipants calls function `add` for every address referenced in the
-// given transaction, possibly with repetition.
-func GetTransactionParticipants(stxnad *sdk.SignedTxnWithAD, includeInner bool, add func(address sdk.Address)) {
-	txn := &stxnad.Txn
-
-	add(txn.Sender)
-
-	switch txn.Type {
-	case sdk.PaymentTx:
-		add(txn.Receiver)
-		// Close address is optional.
-		if !txn.CloseRemainderTo.IsZero() {
-			add(txn.CloseRemainderTo)
-		}
-	case sdk.AssetTransferTx:
-		// If asset sender is non-zero, it is a clawback transaction. Otherwise,
-		// the transaction sender address is used.
-		if !txn.AssetSender.IsZero() {
-			add(txn.AssetSender)
-		}
-		add(txn.AssetReceiver)
-		// Asset close address is optional.
-		if !txn.AssetCloseTo.IsZero() {
-			add(txn.AssetCloseTo)
-		}
-	case sdk.AssetFreezeTx:
-		add(txn.FreezeAccount)
-	case sdk.ApplicationCallTx:
-		for _, address := range txn.ApplicationCallTxnFields.Accounts {
-			add(address)
-		}
-	}
-
-	if includeInner {
-		for _, inner := range stxnad.ApplyData.EvalDelta.InnerTxns {
-			GetTransactionParticipants(&inner, includeInner, add)
-		}
-	}
-}
diff --git a/cmd/algorand-indexer/daemon.go b/cmd/algorand-indexer/daemon.go
index 28b9b6b..bb4faf2 100644
--- a/cmd/algorand-indexer/daemon.go
+++ b/cmd/algorand-indexer/daemon.go
@@ -22,7 +22,6 @@ import (
 	_ "github.com/algorand/indexer/conduit/plugins/exporters/postgresql"
 	_ "github.com/algorand/indexer/conduit/plugins/importers/algod"
 	"github.com/algorand/indexer/config"
-	"github.com/algorand/indexer/fetcher"
 	"github.com/algorand/indexer/idb"
 	iutil "github.com/algorand/indexer/util"
 )
@@ -305,7 +304,7 @@ func runDaemon(daemonConfig *daemonConfig) error {
 	}
 
 	if daemonConfig.algodDataDir != "" {
-		daemonConfig.algodAddr, daemonConfig.algodToken, _, err = fetcher.AlgodArgsForDataDir(daemonConfig.algodDataDir)
+		daemonConfig.algodAddr, daemonConfig.algodToken, _, err = config.AlgodArgsForDataDir(daemonConfig.algodDataDir)
 		if err != nil {
 			return fmt.Errorf("algod data dir err, %v", err)
 		}
diff --git a/cmd/algorand-indexer/main.go b/cmd/algorand-indexer/main.go
index bb09308..2313b8d 100644
--- a/cmd/algorand-indexer/main.go
+++ b/cmd/algorand-indexer/main.go
@@ -16,7 +16,6 @@ import (
 	"github.com/algorand/indexer/idb"
 	"github.com/algorand/indexer/idb/dummy"
 	_ "github.com/algorand/indexer/idb/postgres"
-	_ "github.com/algorand/indexer/util/disabledeadlock"
 	"github.com/algorand/indexer/util/metrics"
 	"github.com/algorand/indexer/version"
 )
diff --git a/cmd/conduit/conduit.test.init.default.yml b/cmd/conduit/internal/initialize/conduit.test.init.default.yml
similarity index 100%
rename from cmd/conduit/conduit.test.init.default.yml
rename to cmd/conduit/internal/initialize/conduit.test.init.default.yml
diff --git a/cmd/conduit/conduit.yml.example b/cmd/conduit/internal/initialize/conduit.yml.example
similarity index 100%
rename from cmd/conduit/conduit.yml.example
rename to cmd/conduit/internal/initialize/conduit.yml.example
diff --git a/cmd/conduit/internal/initialize/init.go b/cmd/conduit/internal/initialize/init.go
new file mode 100644
index 0000000..7ce1e57
--- /dev/null
+++ b/cmd/conduit/internal/initialize/init.go
@@ -0,0 +1,153 @@
+package initialize
+
+import (
+	_ "embed"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/spf13/cobra"
+
+	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/pipeline"
+)
+
+// InitCommand is the init subcommand.
+var InitCommand = makeInitCmd()
+
+const defaultDataDirectory = "data"
+
+//go:embed conduit.yml.example
+var sampleConfig string
+
+func formatArrayObject(obj string) string {
+
+	var ret string
+	lines := strings.Split(obj, "\n")
+	for i, line := range lines {
+		if i == 0 {
+			ret += "  - "
+		} else {
+			ret += "    "
+		}
+		ret += line + "\n"
+	}
+
+	return ret
+
+}
+
+func runConduitInit(path string, importerFlag string, processorsFlag []string, exporterFlag string) error {
+	var location string
+	if path == "" {
+		path = defaultDataDirectory
+		location = "in the current working directory"
+	} else {
+		location = fmt.Sprintf("at '%s'", path)
+	}
+
+	if err := os.MkdirAll(path, 0755); err != nil {
+		return err
+	}
+
+	configFilePath := filepath.Join(path, conduit.DefaultConfigName)
+	f, err := os.Create(configFilePath)
+	if err != nil {
+		return fmt.Errorf("runConduitInit(): failed to create %s", configFilePath)
+	}
+	defer f.Close()
+
+	var importer string
+	if importerFlag == "" {
+		importerFlag = "algod"
+	}
+	for _, metadata := range pipeline.ImporterMetadata() {
+		if metadata.Name == importerFlag {
+			importer = metadata.SampleConfig
+			break
+		}
+	}
+	if importer == "" {
+		return fmt.Errorf("runConduitInit(): unknown importer name: %v", importerFlag)
+	}
+
+	var exporter string
+	if exporterFlag == "" {
+		exporterFlag = "file_writer"
+	}
+	for _, metadata := range pipeline.ExporterMetadata() {
+		if metadata.Name == exporterFlag {
+			exporter = metadata.SampleConfig
+			break
+		}
+	}
+	if exporter == "" {
+		return fmt.Errorf("runConduitInit(): unknown exporter name: %v", exporterFlag)
+	}
+
+	var processors string
+	for _, processorName := range processorsFlag {
+		found := false
+		for _, metadata := range pipeline.ProcessorMetadata() {
+			if metadata.Name == processorName {
+				processors = processors + formatArrayObject(metadata.SampleConfig)
+				found = true
+				break
+			}
+		}
+		if !found {
+			return fmt.Errorf("runConduitInit(): unknown processor name: %v", processorName)
+		}
+	}
+
+	config := fmt.Sprintf(sampleConfig, importer, processors, exporter)
+
+	_, _ = f.WriteString(config)
+
+	if err != nil {
+		return fmt.Errorf("runConduitInit(): failed to write sample config: %w", err)
+	}
+
+	fmt.Printf("A data directory has been created %s.\n", location)
+	fmt.Printf("\nBefore it can be used, the config file needs to be updated with\n")
+	fmt.Printf("values for the selected import, export and processor modules. For example,\n")
+	fmt.Printf("if the default algod importer was used, set the address/token and the block-dir\n")
+	fmt.Printf("path where Conduit should write the block files.\n")
+	fmt.Printf("\nOnce the config file is updated, start Conduit with:\n")
+	fmt.Printf("  ./conduit -d %s\n", path)
+	return nil
+}
+
+// makeInitCmd creates a sample data directory.
+func makeInitCmd() *cobra.Command {
+	var data string
+	var importer string
+	var exporter string
+	var processors []string
+	cmd := &cobra.Command{
+		Use:   "init",
+		Short: "initializes a Conduit data directory",
+		Long: `Initializes a Conduit data directory and conduit.yml file. By default
+the config file uses an algod archival node importer and a block file
+writer exporter. The plugin templates can be changed using the
+different flags.
+
+Once initialized the conduit.yml file needs to be modified. Refer to the file
+comments for details.
+
+Once configured, launch conduit with './conduit -d /path/to/data'.`,
+		Example: "conduit init  -d /path/to/data -i importer -p processor1,processor2 -e exporter",
+		Args:    cobra.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return runConduitInit(data, importer, processors, exporter)
+		},
+		SilenceUsage: true,
+	}
+
+	cmd.Flags().StringVarP(&data, "data", "d", "", "Full path to new data directory. If not set, a directory named 'data' will be created in the current directory.")
+	cmd.Flags().StringVarP(&importer, "importer", "i", "", "data importer name.")
+	cmd.Flags().StringSliceVarP(&processors, "processors", "p", []string{}, "comma-separated list of processors.")
+	cmd.Flags().StringVarP(&exporter, "exporter", "e", "", "data exporter name.")
+	return cmd
+}
diff --git a/cmd/conduit/main.go b/cmd/conduit/main.go
index 3f87db4..362aed5 100644
--- a/cmd/conduit/main.go
+++ b/cmd/conduit/main.go
@@ -5,35 +5,33 @@ import (
 	_ "embed"
 	"fmt"
 	"os"
-	"path/filepath"
-	"strings"
 
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra/doc"
 
+	"github.com/algorand/indexer/cmd/conduit/internal/initialize"
 	"github.com/algorand/indexer/cmd/conduit/internal/list"
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/loggers"
 	"github.com/algorand/indexer/conduit/pipeline"
 	_ "github.com/algorand/indexer/conduit/plugins/exporters/all"
 	_ "github.com/algorand/indexer/conduit/plugins/importers/all"
 	_ "github.com/algorand/indexer/conduit/plugins/processors/all"
-	"github.com/algorand/indexer/loggers"
 	"github.com/algorand/indexer/version"
 )
 
 var (
-	logger               *log.Logger
-	conduitCmd           = makeConduitCmd()
-	initCmd              = makeInitCmd()
-	defaultDataDirectory = "data"
+	logger     *log.Logger
+	conduitCmd = makeConduitCmd()
 	//go:embed banner.txt
 	banner string
 )
 
 // init() function for main package
 func init() {
-	conduitCmd.AddCommand(initCmd)
+	conduitCmd.AddCommand(initialize.InitCommand)
+	conduitCmd.AddCommand(list.Command)
 }
 
 // runConduitCmdWithConfig run the main logic with a supplied conduit config
@@ -68,13 +66,22 @@ func runConduitCmdWithConfig(args *conduit.Args) error {
 	}
 
 	if pCfg.LogFile != "" {
-		logger.Infof("Conduit log file: %s", pCfg.LogFile)
+		fmt.Printf("Writing logs to file: %s\n", pCfg.LogFile)
+	} else {
+		fmt.Println("Writing logs to console.")
 	}
 
 	ctx := context.Background()
 	pipeline, err := pipeline.MakePipeline(ctx, pCfg, logger)
 	if err != nil {
-		return fmt.Errorf("pipeline creation error: %w", err)
+		err = fmt.Errorf("pipeline creation error: %w", err)
+
+		// Make sure the error is written to stdout once.
+		fmt.Println(err)
+		if pCfg.LogFile != "" {
+			logger.Error(err)
+		}
+		return err
 	}
 
 	err = pipeline.Init()
@@ -114,142 +121,6 @@ func makeConduitCmd() *cobra.Command {
 	cmd.Flags().Uint64VarP(&cfg.NextRoundOverride, "next-round-override", "r", 0, "set the starting round. Overrides next-round in metadata.json")
 	cmd.Flags().BoolVarP(&vFlag, "version", "v", false, "print the conduit version")
 
-	cmd.AddCommand(list.Command)
-
-	return cmd
-}
-
-//go:embed conduit.yml.example
-var sampleConfig string
-
-func formatArrayObject(obj string) string {
-
-	var ret string
-	lines := strings.Split(obj, "\n")
-	for i, line := range lines {
-		if i == 0 {
-			ret += "  - "
-		} else {
-			ret += "    "
-		}
-		ret += line + "\n"
-	}
-
-	return ret
-
-}
-
-func runConduitInit(path string, importerFlag string, processorsFlag []string, exporterFlag string) error {
-	var location string
-	if path == "" {
-		path = defaultDataDirectory
-		location = "in the current working directory"
-	} else {
-		location = fmt.Sprintf("at '%s'", path)
-	}
-
-	if err := os.MkdirAll(path, 0755); err != nil {
-		return err
-	}
-
-	configFilePath := filepath.Join(path, conduit.DefaultConfigName)
-	f, err := os.Create(configFilePath)
-	if err != nil {
-		return fmt.Errorf("runConduitInit(): failed to create %s", configFilePath)
-	}
-	defer f.Close()
-
-	var importer string
-	if importerFlag == "" {
-		importerFlag = "algod"
-	}
-	for _, metadata := range pipeline.ImporterMetadata() {
-		if metadata.Name == importerFlag {
-			importer = metadata.SampleConfig
-			break
-		}
-	}
-	if importer == "" {
-		return fmt.Errorf("runConduitInit(): unknown importer name: %v", importerFlag)
-	}
-
-	var exporter string
-	if exporterFlag == "" {
-		exporterFlag = "file_writer"
-	}
-	for _, metadata := range pipeline.ExporterMetadata() {
-		if metadata.Name == exporterFlag {
-			exporter = metadata.SampleConfig
-			break
-		}
-	}
-	if exporter == "" {
-		return fmt.Errorf("runConduitInit(): unknown exporter name: %v", exporterFlag)
-	}
-
-	var processors string
-	for _, processorName := range processorsFlag {
-		found := false
-		for _, metadata := range pipeline.ProcessorMetadata() {
-			if metadata.Name == processorName {
-				processors = processors + formatArrayObject(metadata.SampleConfig)
-				found = true
-				break
-			}
-		}
-		if !found {
-			return fmt.Errorf("runConduitInit(): unknown processor name: %v", processorName)
-		}
-	}
-
-	config := fmt.Sprintf(sampleConfig, importer, processors, exporter)
-
-	_, _ = f.WriteString(config)
-
-	if err != nil {
-		return fmt.Errorf("runConduitInit(): failed to write sample config: %w", err)
-	}
-
-	fmt.Printf("A data directory has been created %s.\n", location)
-	fmt.Printf("\nBefore it can be used, the config file needs to be updated with\n")
-	fmt.Printf("values for the selected import, export and processor modules. For example,\n")
-	fmt.Printf("if the default algod importer was used, set the address/token and the block-dir\n")
-	fmt.Printf("path where Conduit should write the block files.\n")
-	fmt.Printf("\nOnce the config file is updated, start Conduit with:\n")
-	fmt.Printf("  ./conduit -d %s\n", path)
-	return nil
-}
-
-// makeInitCmd creates a sample data directory.
-func makeInitCmd() *cobra.Command {
-	var data string
-	var importer string
-	var exporter string
-	var processors []string
-	cmd := &cobra.Command{
-		Use:   "init",
-		Short: "initializes a Conduit data directory",
-		Long: `Initializes a Conduit data directory and conduit.yml file. By default
-the config file uses an algod archival node importer and a block file
-writer exporter. The plugin templates can be changed using the
-different flags.
-
-Once initialized the conduit.yml file needs to be modified. Refer to the file
-comments for details.
-
-Once configured, launch conduit with './conduit -d /path/to/data'.`,
-		Example: "conduit init  -d /path/to/data -i importer -p processor1,processor2 -e exporter",
-		Args:    cobra.NoArgs,
-		RunE: func(cmd *cobra.Command, args []string) error {
-			return runConduitInit(data, importer, processors, exporter)
-		},
-		SilenceUsage: true,
-	}
-
-	cmd.Flags().StringVarP(&data, "data", "d", "", "Full path to new data directory. If not set, a directory named 'data' will be created in the current directory.")
-	cmd.Flags().StringVarP(&importer, "importer", "i", "", "data importer name.")
-	cmd.Flags().StringSliceVarP(&processors, "processors", "p", []string{}, "comma-separated list of processors.")
-	cmd.Flags().StringVarP(&exporter, "exporter", "e", "", "data exporter name.")
 	return cmd
 }
 
diff --git a/data/block_export_data.go b/conduit/data/block_export_data.go
similarity index 100%
rename from data/block_export_data.go
rename to conduit/data/block_export_data.go
diff --git a/conduit/hooks.go b/conduit/hooks.go
index a7df222..d26aece 100644
--- a/conduit/hooks.go
+++ b/conduit/hooks.go
@@ -3,7 +3,7 @@ package conduit
 import (
 	"github.com/prometheus/client_golang/prometheus"
 
-	"github.com/algorand/indexer/data"
+	"github.com/algorand/indexer/conduit/data"
 )
 
 // OnCompleteFunc is the signature for the Completed functional interface.
diff --git a/loggers/loggers.go b/conduit/loggers/loggers.go
similarity index 100%
rename from loggers/loggers.go
rename to conduit/loggers/loggers.go
diff --git a/loggers/loggers_test.go b/conduit/loggers/loggers_test.go
similarity index 100%
rename from loggers/loggers_test.go
rename to conduit/loggers/loggers_test.go
diff --git a/conduit/pipeline/pipeline.go b/conduit/pipeline/pipeline.go
index 99bceed..1c4d35d 100644
--- a/conduit/pipeline/pipeline.go
+++ b/conduit/pipeline/pipeline.go
@@ -19,11 +19,11 @@ import (
 	"gopkg.in/yaml.v3"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
 	"github.com/algorand/indexer/conduit/plugins/importers"
 	"github.com/algorand/indexer/conduit/plugins/processors"
-	"github.com/algorand/indexer/data"
 	"github.com/algorand/indexer/util"
 	"github.com/algorand/indexer/util/metrics"
 
@@ -91,7 +91,7 @@ func MakePipelineConfig(args *conduit.Args) (*Config, error) {
 	}
 
 	if !util.IsDir(args.ConduitDataDir) {
-		return nil, fmt.Errorf("MakePipelineConfig(): invalid data dir")
+		return nil, fmt.Errorf("MakePipelineConfig(): invalid data dir '%s'", args.ConduitDataDir)
 	}
 
 	// Search for pipeline configuration in data directory
@@ -588,7 +588,7 @@ func MakePipeline(ctx context.Context, cfg *Config, logger *log.Logger) (Pipelin
 
 	importerBuilder, err := importers.ImporterBuilderByName(importerName)
 	if err != nil {
-		return nil, fmt.Errorf("MakePipeline(): could not find importer builder with name: %s", importerName)
+		return nil, fmt.Errorf("MakePipeline(): could not build importer '%s': %w", importerName, err)
 	}
 
 	importer := importerBuilder.New()
@@ -602,7 +602,7 @@ func MakePipeline(ctx context.Context, cfg *Config, logger *log.Logger) (Pipelin
 
 		processorBuilder, err := processors.ProcessorBuilderByName(processorName)
 		if err != nil {
-			return nil, fmt.Errorf("MakePipeline(): could not find processor builder with name: %s", processorName)
+			return nil, fmt.Errorf("MakePipeline(): could not build processor '%s': %w", processorName, err)
 		}
 
 		processor := processorBuilder.New()
@@ -616,7 +616,7 @@ func MakePipeline(ctx context.Context, cfg *Config, logger *log.Logger) (Pipelin
 
 	exporterBuilder, err := exporters.ExporterBuilderByName(exporterName)
 	if err != nil {
-		return nil, fmt.Errorf("MakePipeline(): could not find exporter builder with name: %s", exporterName)
+		return nil, fmt.Errorf("MakePipeline(): could not build exporter '%s': %w", exporterName, err)
 	}
 
 	exporter := exporterBuilder.New()
diff --git a/conduit/plugins/exporters/example/example_exporter.go b/conduit/plugins/exporters/example/example_exporter.go
index 518e69e..25e9318 100644
--- a/conduit/plugins/exporters/example/example_exporter.go
+++ b/conduit/plugins/exporters/example/example_exporter.go
@@ -7,9 +7,9 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
-	"github.com/algorand/indexer/data"
 )
 
 // This is our exporter object. It should store all the in memory data required to run the Exporter.
diff --git a/conduit/plugins/exporters/exporter.go b/conduit/plugins/exporters/exporter.go
index dc12bdd..857f7a6 100644
--- a/conduit/plugins/exporters/exporter.go
+++ b/conduit/plugins/exporters/exporter.go
@@ -6,8 +6,8 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
-	"github.com/algorand/indexer/data"
 )
 
 // Exporter defines the interface for plugins
diff --git a/conduit/plugins/exporters/filewriter/file_exporter.go b/conduit/plugins/exporters/filewriter/file_exporter.go
index 441c063..cfb2c86 100644
--- a/conduit/plugins/exporters/filewriter/file_exporter.go
+++ b/conduit/plugins/exporters/filewriter/file_exporter.go
@@ -12,10 +12,9 @@ import (
 	"gopkg.in/yaml.v3"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
-	"github.com/algorand/indexer/data"
-	"github.com/algorand/indexer/util"
 )
 
 const (
@@ -95,7 +94,7 @@ func (exp *fileExporter) Receive(exportData data.BlockData) error {
 		}
 
 		blockFile := path.Join(exp.cfg.BlocksDir, fmt.Sprintf(exp.cfg.FilenamePattern, exportData.Round()))
-		err := util.EncodeJSONToFile(blockFile, exportData, true)
+		err := EncodeJSONToFile(blockFile, exportData, true)
 		if err != nil {
 			return fmt.Errorf("Receive(): failed to write file %s: %w", blockFile, err)
 		}
diff --git a/conduit/plugins/exporters/filewriter/util.go b/conduit/plugins/exporters/filewriter/util.go
new file mode 100644
index 0000000..3cb9012
--- /dev/null
+++ b/conduit/plugins/exporters/filewriter/util.go
@@ -0,0 +1,97 @@
+package filewriter
+
+import (
+	"bytes"
+	"compress/gzip"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"strings"
+
+	"github.com/algorand/go-codec/codec"
+
+	"github.com/algorand/go-algorand-sdk/v2/encoding/json"
+)
+
+var prettyHandle *codec.JsonHandle
+var jsonStrictHandle *codec.JsonHandle
+
+func init() {
+	prettyHandle = new(codec.JsonHandle)
+	prettyHandle.ErrorIfNoField = json.CodecHandle.ErrorIfNoField
+	prettyHandle.ErrorIfNoArrayExpand = json.CodecHandle.ErrorIfNoArrayExpand
+	prettyHandle.Canonical = json.CodecHandle.Canonical
+	prettyHandle.RecursiveEmptyCheck = json.CodecHandle.RecursiveEmptyCheck
+	prettyHandle.Indent = json.CodecHandle.Indent
+	prettyHandle.HTMLCharsAsIs = json.CodecHandle.HTMLCharsAsIs
+	prettyHandle.MapKeyAsString = true
+	prettyHandle.Indent = 2
+
+	jsonStrictHandle = new(codec.JsonHandle)
+	jsonStrictHandle.ErrorIfNoField = prettyHandle.ErrorIfNoField
+	jsonStrictHandle.ErrorIfNoArrayExpand = prettyHandle.ErrorIfNoArrayExpand
+	jsonStrictHandle.Canonical = prettyHandle.Canonical
+	jsonStrictHandle.RecursiveEmptyCheck = prettyHandle.RecursiveEmptyCheck
+	jsonStrictHandle.Indent = prettyHandle.Indent
+	jsonStrictHandle.HTMLCharsAsIs = prettyHandle.HTMLCharsAsIs
+	jsonStrictHandle.MapKeyAsString = true
+}
+
+// EncodeJSONToFile is used to encode an object to a file. If the file ends in .gz it will be gzipped.
+func EncodeJSONToFile(filename string, v interface{}, pretty bool) error {
+	var writer io.Writer
+
+	file, err := os.Create(filename)
+	if err != nil {
+		return fmt.Errorf("EncodeJSONToFile(): failed to create %s: %w", filename, err)
+	}
+	defer file.Close()
+
+	if strings.HasSuffix(filename, ".gz") {
+		gz := gzip.NewWriter(file)
+		gz.Name = filename
+		defer gz.Close()
+		writer = gz
+	} else {
+		writer = file
+	}
+
+	var handle *codec.JsonHandle
+	if pretty {
+		handle = prettyHandle
+	} else {
+		handle = jsonStrictHandle
+	}
+	enc := codec.NewEncoder(writer, handle)
+	return enc.Encode(v)
+}
+
+// DecodeJSONFromFile is used to decode a file to an object.
+func DecodeJSONFromFile(filename string, v interface{}, strict bool) error {
+	// Streaming into the decoder was slow.
+	fileBytes, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return fmt.Errorf("DecodeJSONFromFile(): failed to read %s: %w", filename, err)
+	}
+
+	var reader io.Reader = bytes.NewReader(fileBytes)
+
+	if strings.HasSuffix(filename, ".gz") {
+		gz, err := gzip.NewReader(reader)
+		defer gz.Close()
+		if err != nil {
+			return fmt.Errorf("DecodeJSONFromFile(): failed to make gzip reader: %w", err)
+		}
+		reader = gz
+	}
+	var handle *codec.JsonHandle
+	if strict {
+		handle = json.CodecHandle
+	} else {
+		handle = json.LenientCodecHandle
+	}
+
+	enc := codec.NewDecoder(reader, handle)
+	return enc.Decode(v)
+}
diff --git a/conduit/plugins/exporters/noop/noop_exporter.go b/conduit/plugins/exporters/noop/noop_exporter.go
index e57308f..82fe11b 100644
--- a/conduit/plugins/exporters/noop/noop_exporter.go
+++ b/conduit/plugins/exporters/noop/noop_exporter.go
@@ -9,9 +9,9 @@ import (
 	"gopkg.in/yaml.v3"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
-	"github.com/algorand/indexer/data"
 )
 
 // PluginName to use when configuring.
diff --git a/conduit/plugins/exporters/postgresql/postgresql_exporter.go b/conduit/plugins/exporters/postgresql/postgresql_exporter.go
index 1c5c755..44761ed 100644
--- a/conduit/plugins/exporters/postgresql/postgresql_exporter.go
+++ b/conduit/plugins/exporters/postgresql/postgresql_exporter.go
@@ -11,10 +11,10 @@ import (
 	"gopkg.in/yaml.v3"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
 	"github.com/algorand/indexer/conduit/plugins/exporters/postgresql/util"
-	"github.com/algorand/indexer/data"
 	"github.com/algorand/indexer/idb"
 	// Necessary to ensure the postgres implementation has been registered in the idb factory
 	_ "github.com/algorand/indexer/idb/postgres"
diff --git a/conduit/plugins/importers/algod/algod_importer.go b/conduit/plugins/importers/algod/algod_importer.go
index 6a05178..a24f506 100644
--- a/conduit/plugins/importers/algod/algod_importer.go
+++ b/conduit/plugins/importers/algod/algod_importer.go
@@ -13,9 +13,9 @@ import (
 	"gopkg.in/yaml.v3"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/importers"
-	"github.com/algorand/indexer/data"
 
 	"github.com/algorand/go-algorand-sdk/v2/client/v2/algod"
 	"github.com/algorand/go-algorand-sdk/v2/client/v2/common"
diff --git a/conduit/plugins/importers/filereader/filereader.go b/conduit/plugins/importers/filereader/filereader.go
index c28b35e..84c0d52 100644
--- a/conduit/plugins/importers/filereader/filereader.go
+++ b/conduit/plugins/importers/filereader/filereader.go
@@ -13,11 +13,10 @@ import (
 	"gopkg.in/yaml.v3"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters/filewriter"
 	"github.com/algorand/indexer/conduit/plugins/importers"
-	"github.com/algorand/indexer/data"
-	"github.com/algorand/indexer/util"
 
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
@@ -73,7 +72,7 @@ func (r *fileReader) Init(ctx context.Context, cfg plugins.PluginConfig, logger
 
 	genesisFile := path.Join(r.cfg.BlocksDir, "genesis.json")
 	var genesis sdk.Genesis
-	err = util.DecodeJSONFromFile(genesisFile, &genesis, false)
+	err = filewriter.DecodeJSONFromFile(genesisFile, &genesis, false)
 	if err != nil {
 		return nil, fmt.Errorf("Init(): failed to process genesis file: %w", err)
 	}
@@ -99,7 +98,7 @@ func (r *fileReader) GetBlock(rnd uint64) (data.BlockData, error) {
 		filename := path.Join(r.cfg.BlocksDir, fmt.Sprintf(r.cfg.FilenamePattern, rnd))
 		var blockData data.BlockData
 		start := time.Now()
-		err := util.DecodeJSONFromFile(filename, &blockData, false)
+		err := filewriter.DecodeJSONFromFile(filename, &blockData, false)
 		if err != nil && errors.Is(err, fs.ErrNotExist) {
 			// If the file read failed because the file didn't exist, wait before trying again
 			if attempts == 0 {
diff --git a/conduit/plugins/importers/importer.go b/conduit/plugins/importers/importer.go
index 969c8ea..8bebbfb 100644
--- a/conduit/plugins/importers/importer.go
+++ b/conduit/plugins/importers/importer.go
@@ -6,8 +6,8 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
-	"github.com/algorand/indexer/data"
 
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
diff --git a/conduit/plugins/processors/filterprocessor/filter_processor.go b/conduit/plugins/processors/filterprocessor/filter_processor.go
index e6ab7b5..85e677b 100644
--- a/conduit/plugins/processors/filterprocessor/filter_processor.go
+++ b/conduit/plugins/processors/filterprocessor/filter_processor.go
@@ -9,11 +9,11 @@ import (
 	"gopkg.in/yaml.v3"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/processors"
 	"github.com/algorand/indexer/conduit/plugins/processors/filterprocessor/expression"
 	"github.com/algorand/indexer/conduit/plugins/processors/filterprocessor/fields"
-	"github.com/algorand/indexer/data"
 
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
diff --git a/conduit/plugins/processors/noop/noop_processor.go b/conduit/plugins/processors/noop/noop_processor.go
index 87a4eea..5b838bc 100644
--- a/conduit/plugins/processors/noop/noop_processor.go
+++ b/conduit/plugins/processors/noop/noop_processor.go
@@ -7,9 +7,9 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/processors"
-	"github.com/algorand/indexer/data"
 )
 
 // PluginName to use when configuring.
diff --git a/conduit/plugins/processors/processor.go b/conduit/plugins/processors/processor.go
index 8b38ea7..e7fcf3a 100644
--- a/conduit/plugins/processors/processor.go
+++ b/conduit/plugins/processors/processor.go
@@ -6,8 +6,8 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
-	"github.com/algorand/indexer/data"
 )
 
 // Processor an interface that defines an object that can filter and process transactions
diff --git a/fetcher/fetcher.go b/config/datadir.go
similarity index 98%
rename from fetcher/fetcher.go
rename to config/datadir.go
index 040859e..9d40262 100644
--- a/fetcher/fetcher.go
+++ b/config/datadir.go
@@ -1,4 +1,4 @@
-package fetcher
+package config
 
 import (
 	"fmt"
diff --git a/go.mod b/go.mod
index 283bfea..495aa35 100644
--- a/go.mod
+++ b/go.mod
@@ -2,14 +2,10 @@ module github.com/algorand/indexer
 
 go 1.17
 
-replace github.com/algorand/go-algorand => ./third_party/go-algorand
-
 require (
 	github.com/algorand/avm-abi v0.2.0
-	github.com/algorand/go-algorand v0.0.0-20220211161928-53b157beb10f
 	github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230228201805-5b8c99b1412c
 	github.com/algorand/go-codec/codec v1.1.8
-	github.com/algorand/go-deadlock v0.2.2
 	github.com/algorand/oapi-codegen v1.12.0-algorand.0
 	github.com/davecgh/go-spew v1.1.1
 	github.com/getkin/kin-openapi v0.107.0
@@ -32,20 +28,11 @@ require (
 )
 
 require (
-	github.com/DataDog/zstd v1.5.2 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
-	github.com/algorand/falcon v0.0.0-20220727072124-02a2a64c4414 // indirect
-	github.com/algorand/go-sumhash v1.0.0 // indirect
-	github.com/algorand/msgp v1.1.53 // indirect
-	github.com/algorand/websocket v1.4.5 // indirect
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
-	github.com/aws/aws-sdk-go v1.33.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
-	github.com/consensys/gnark-crypto v0.7.0 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
-	github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 // indirect
-	github.com/dchest/siphash v1.2.1 // indirect
 	github.com/docker/distribution v2.7.1+incompatible // indirect
 	github.com/docker/docker v1.13.1 // indirect
 	github.com/docker/go-connections v0.4.0 // indirect
@@ -55,10 +42,8 @@ require (
 	github.com/go-openapi/swag v0.19.5 // indirect
 	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
-	github.com/golang/snappy v0.0.4 // indirect
 	github.com/google/go-querystring v1.0.0 // indirect
 	github.com/google/uuid v1.3.0 // indirect
-	github.com/gorilla/mux v1.8.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/inconshreveable/mousetrap v1.0.0 // indirect
 	github.com/invopop/yaml v0.1.0 // indirect
@@ -69,7 +54,6 @@ require (
 	github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
 	github.com/jackc/pgtype v1.8.1 // indirect
 	github.com/jackc/puddle v1.1.3 // indirect
-	github.com/jmespath/go-jmespath v0.3.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/kr/pretty v0.3.0 // indirect
 	github.com/labstack/gommon v0.4.0 // indirect
@@ -78,16 +62,11 @@ require (
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.12 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect
-	github.com/mattn/go-sqlite3 v1.10.0 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
-	github.com/miekg/dns v1.1.41 // indirect
 	github.com/mitchellh/mapstructure v1.4.3 // indirect
-	github.com/mmcloughlin/addchain v0.4.0 // indirect
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
-	github.com/olivere/elastic v6.2.14+incompatible // indirect
 	github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
 	github.com/pelletier/go-toml v1.9.4 // indirect
-	github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/prometheus/client_model v0.2.0 // indirect
 	github.com/prometheus/common v0.26.0 // indirect
@@ -113,6 +92,5 @@ require (
 	google.golang.org/protobuf v1.28.0 // indirect
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 	gopkg.in/ini.v1 v1.66.2 // indirect
-	gopkg.in/sohlich/elogrus.v3 v3.0.0-20180410122755-1fa29e2f2009 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 64a7137..8cea3d0 100644
--- a/go.sum
+++ b/go.sum
@@ -61,8 +61,6 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
-github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
-github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
 github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
@@ -86,33 +84,14 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
 github.com/algorand/avm-abi v0.1.1/go.mod h1:+CgwM46dithy850bpTeHh9MC99zpn2Snirb3QTl2O/g=
 github.com/algorand/avm-abi v0.2.0 h1:bkjsG+BOEcxUcnGSALLosmltE0JZdg+ZisXKx0UDX2k=
 github.com/algorand/avm-abi v0.2.0/go.mod h1:+CgwM46dithy850bpTeHh9MC99zpn2Snirb3QTl2O/g=
-github.com/algorand/falcon v0.0.0-20220727072124-02a2a64c4414 h1:nwYN+GQ7Z5OOfZwqBO1ma7DSlP7S1YrKWICOyjkwqrc=
-github.com/algorand/falcon v0.0.0-20220727072124-02a2a64c4414/go.mod h1:OkQyHlGvS0kLNcIWbC21/uQcnbfwSOQm+wiqWwBG9pQ=
-github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230209164439-140b997ed9ee h1:OGE5lhg7vQ+PGCkHW2CZL4oC1uxrJAuqy7Z52cCYzJw=
-github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230209164439-140b997ed9ee/go.mod h1:Nt3EHpP8AznLs0/EFfhr0/xsVf5ucnvjNeRygGgbUzM=
-github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230216185416-22ef3b66c617 h1:IOqgNBpxSk23ixJzysAYqRYz04rAE2+d1DJI1sD+z8M=
-github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230216185416-22ef3b66c617/go.mod h1:Nt3EHpP8AznLs0/EFfhr0/xsVf5ucnvjNeRygGgbUzM=
 github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230228201805-5b8c99b1412c h1:KAX6gb3+DLCTBcVhjDtuhcdbCeKnwIYKdj5Dv2JA/nI=
 github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230228201805-5b8c99b1412c/go.mod h1:Nt3EHpP8AznLs0/EFfhr0/xsVf5ucnvjNeRygGgbUzM=
-github.com/algorand/go-algorand-sdk/v2 v2.0.0 h1:hfi+YrzcaH20mrjdIQYOPFKPlJ/ULq9KLhLG9I6LJEY=
-github.com/algorand/go-algorand-sdk/v2 v2.0.0/go.mod h1:Nt3EHpP8AznLs0/EFfhr0/xsVf5ucnvjNeRygGgbUzM=
 github.com/algorand/go-codec v1.1.8 h1:XDSreeeZY8gMst6Edz4RBkl08/DGMJOeHYkoXL2B7wI=
 github.com/algorand/go-codec v1.1.8/go.mod h1:XhzVs6VVyWMLu6cApb9/192gBjGRVGm5cX5j203Heg4=
 github.com/algorand/go-codec/codec v1.1.8 h1:lsFuhcOH2LiEhpBH3BVUUkdevVmwCRyvb7FCAAPeY6U=
 github.com/algorand/go-codec/codec v1.1.8/go.mod h1:tQ3zAJ6ijTps6V+wp8KsGDnPC2uhHVC7ANyrtkIY0bA=
-github.com/algorand/go-deadlock v0.2.2 h1:L7AKATSUCzoeVuOgpTipfCEjdUu5ECmlje8R7lP9DOY=
-github.com/algorand/go-deadlock v0.2.2/go.mod h1:Hat1OXKqKNUcN/iv74FjGhF4hsOE2l7gOgQ9ZVIq6Fk=
-github.com/algorand/go-sumhash v0.1.0/go.mod h1:OOe7jdDWUhLkuP1XytkK5gnLu9entAviN5DfDZh6XAc=
-github.com/algorand/go-sumhash v1.0.0 h1:00PkvdWAvPGxjd51eF84gZV81hlx3Yt/5sGeHzmcY0U=
-github.com/algorand/go-sumhash v1.0.0/go.mod h1:OOe7jdDWUhLkuP1XytkK5gnLu9entAviN5DfDZh6XAc=
-github.com/algorand/graphtrace v0.1.0 h1:QemP1iT0W56SExD0NfiU6rsG34/v0Je6bg5UZnptEUM=
-github.com/algorand/graphtrace v0.1.0/go.mod h1:HscLQrzBdH1BH+5oehs3ICd8SYcXvnSL9BjfTu8WHCc=
-github.com/algorand/msgp v1.1.53 h1:D6HKLyvLE6ltfsf8Apsrc+kqYb/CcOZEAfh1DpkPrNg=
-github.com/algorand/msgp v1.1.53/go.mod h1:5K3d58/poT5fPmtiwuQft6GjgSrVEM46KoXdLrID8ZU=
 github.com/algorand/oapi-codegen v1.12.0-algorand.0 h1:W9PvED+wAJc+9EeXPONnA+0zE9UhynEqoDs4OgAxKhk=
 github.com/algorand/oapi-codegen v1.12.0-algorand.0/go.mod h1:tIWJ9K/qrLDVDt5A1p82UmxZIEGxv2X+uoujdhEAL48=
-github.com/algorand/websocket v1.4.5 h1:Cs6UTaCReAl02evYxmN8k57cNHmBILRcspfSxYg4AJE=
-github.com/algorand/websocket v1.4.5/go.mod h1:79n6FSZY08yQagHzE/YWZqTPBYfY5wc3IS+UTZe1W5c=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -129,8 +108,6 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l
 github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
 github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.30.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
-github.com/aws/aws-sdk-go v1.33.0 h1:Bq5Y6VTLbfnJp1IV8EL/qUU5qO1DYHda/zis/sqevkY=
-github.com/aws/aws-sdk-go v1.33.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
 github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -172,9 +149,6 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/consensys/bavard v0.1.10/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
-github.com/consensys/gnark-crypto v0.7.0 h1:rwdy8+ssmLYRqKp+ryRRgQJl/rCq2uv+n83cOydm5UE=
-github.com/consensys/gnark-crypto v0.7.0/go.mod h1:KPSuJzyxkJA8xZ/+CV47tyqkr9MmpZA3PXivK4VPrVg=
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@@ -182,22 +156,15 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man v1.0.8 h1:DwoNytLphI8hzS2Af4D0dfaEaiSq2bN05mEm4R6vf8M=
-github.com/cpuguy83/go-md2man v1.0.8/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
 github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA=
-github.com/daixiang0/gci v0.3.2/go.mod h1:jaASoJmv/ykO9dAAPy31iJnreV19248qKDdVWf3QgC4=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0=
-github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
-github.com/dchest/siphash v1.2.1 h1:4cLinnzVJDKxTCl9B01807Yiy+W7ZzVHj/KIroQRvT4=
-github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
 github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
 github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
@@ -237,8 +204,6 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
 github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
-github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
 github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -307,7 +272,6 @@ github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/V
 github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
 github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gofrs/flock v0.7.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
 github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
 github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
@@ -356,8 +320,6 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
-github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -398,7 +360,6 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
 github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -415,7 +376,6 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
 github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
 github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
@@ -464,7 +424,6 @@ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
 github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
-github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
 github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
@@ -530,9 +489,7 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv
 github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc=
 github.com/jarcoal/httpmock v1.2.0/go.mod h1:oCoTsnAz4+UoOUIf5lJOWV2QQIW5UoeUI6aM2YnWAZk=
 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
 github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
-github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -552,7 +509,6 @@ github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPci
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
 github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
-github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
 github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
 github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -584,8 +540,6 @@ github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZ
 github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
 github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
 github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
-github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
-github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
 github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
 github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
 github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ=
@@ -635,17 +589,12 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
 github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
-github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/maxatome/go-testdeep v1.11.0 h1:Tgh5efyCYyJFGUYiT0qxBSIDeXw0F5zSoatlou685kk=
 github.com/maxatome/go-testdeep v1.11.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ysdyKe7Dyogw70=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
-github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
-github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
 github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
@@ -658,9 +607,6 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
 github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
-github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
-github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
@@ -684,8 +630,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
 github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
 github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olivere/elastic v6.2.14+incompatible h1:k+KadwNP/dkXE0/eu+T6otk1+5fe0tEpPyQJ4XVm5i8=
-github.com/olivere/elastic v6.2.14+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -719,8 +663,6 @@ github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
 github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
-github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
 github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -778,8 +720,6 @@ github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6po
 github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
 github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
 github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
-github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -849,7 +789,6 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
 github.com/uber/jaeger-lib v2.4.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
@@ -930,7 +869,6 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
 golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
@@ -1144,8 +1082,6 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
@@ -1208,7 +1144,6 @@ golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -1426,8 +1361,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
 gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/sohlich/elogrus.v3 v3.0.0-20180410122755-1fa29e2f2009 h1:q/fZgS8MMadqFFGa8WL4Oyz+TmjiZfi8UrzWhTl8d5w=
-gopkg.in/sohlich/elogrus.v3 v3.0.0-20180410122755-1fa29e2f2009/go.mod h1:O0bY1e/dSoxMYZYTHP0SWKxG5EWLEvKR9/cOjWPPMKU=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
@@ -1467,7 +1400,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/idb/postgres/internal/writer/write_txn_participation.go b/idb/postgres/internal/writer/write_txn_participation.go
index 0ba7c91..65edf1c 100644
--- a/idb/postgres/internal/writer/write_txn_participation.go
+++ b/idb/postgres/internal/writer/write_txn_participation.go
@@ -6,11 +6,49 @@ import (
 
 	"github.com/jackc/pgx/v4"
 
-	"github.com/algorand/indexer/accounting"
-
 	"github.com/algorand/go-algorand-sdk/v2/types"
 )
 
+// addTransactionParticipants calls function `add` for every address referenced in the
+// given transaction, possibly with repetition.
+func addTransactionParticipants(stxnad *types.SignedTxnWithAD, includeInner bool, add func(address types.Address)) {
+	txn := &stxnad.Txn
+
+	add(txn.Sender)
+
+	switch txn.Type {
+	case types.PaymentTx:
+		add(txn.Receiver)
+		// Close address is optional.
+		if !txn.CloseRemainderTo.IsZero() {
+			add(txn.CloseRemainderTo)
+		}
+	case types.AssetTransferTx:
+		// If asset sender is non-zero, it is a clawback transaction. Otherwise,
+		// the transaction sender address is used.
+		if !txn.AssetSender.IsZero() {
+			add(txn.AssetSender)
+		}
+		add(txn.AssetReceiver)
+		// Asset close address is optional.
+		if !txn.AssetCloseTo.IsZero() {
+			add(txn.AssetCloseTo)
+		}
+	case types.AssetFreezeTx:
+		add(txn.FreezeAccount)
+	case types.ApplicationCallTx:
+		for _, address := range txn.ApplicationCallTxnFields.Accounts {
+			add(address)
+		}
+	}
+
+	if includeInner {
+		for _, inner := range stxnad.ApplyData.EvalDelta.InnerTxns {
+			addTransactionParticipants(&inner, includeInner, add)
+		}
+	}
+}
+
 // getTransactionParticipants returns referenced addresses from the txn and all inner txns
 func getTransactionParticipants(stxnad *types.SignedTxnWithAD, includeInner bool) []types.Address {
 	const acctsPerTxn = 7
@@ -27,7 +65,7 @@ func getTransactionParticipants(stxnad *types.SignedTxnWithAD, includeInner bool
 			res = append(res, address)
 		}
 
-		accounting.GetTransactionParticipants(stxnad, includeInner, add)
+		addTransactionParticipants(stxnad, includeInner, add)
 		return res
 	}
 
@@ -40,7 +78,7 @@ func getTransactionParticipants(stxnad *types.SignedTxnWithAD, includeInner bool
 		participants[address] = struct{}{}
 	}
 
-	accounting.GetTransactionParticipants(stxnad, includeInner, add)
+	addTransactionParticipants(stxnad, includeInner, add)
 
 	res := make([]types.Address, 0, len(participants))
 	for addr := range participants {
diff --git a/misc/requirements.txt b/misc/requirements.txt
index f6a3ca5..17a85e7 100644
--- a/misc/requirements.txt
+++ b/misc/requirements.txt
@@ -5,3 +5,4 @@ py-algorand-sdk >=1.3.0,<2
 pytest==6.2.5
 GitPython==3.1.26
 PyYAML==6.0
+requests==2.28.2
\ No newline at end of file
diff --git a/third_party/go-algorand b/third_party/go-algorand
deleted file mode 160000
index 4bc7250..0000000
--- a/third_party/go-algorand
+++ /dev/null
@@ -1,1 +0,0 @@
-Subproject commit 4bc725070054b81816ff2c1da5f347dd152b879c
diff --git a/types/types.go b/types/types.go
index 03e7339..058b926 100644
--- a/types/types.go
+++ b/types/types.go
@@ -2,8 +2,6 @@ package types
 
 import (
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
-	"github.com/algorand/go-algorand/data/bookkeeping"
-	"github.com/algorand/go-algorand/ledger/ledgercore"
 )
 
 // TODO: should these types be defined in the SDK? In the future there could be automation to keep certain
@@ -29,9 +27,3 @@ type SpecialAddresses struct {
 	FeeSink     sdk.Address
 	RewardsPool sdk.Address
 }
-
-// LegercoreValidatedBlock for serialization
-type LegercoreValidatedBlock struct {
-	Blk   bookkeeping.Block
-	Delta ledgercore.StateDelta
-}
diff --git a/util/disabledeadlock/disable_deadlock.go b/util/disabledeadlock/disable_deadlock.go
deleted file mode 100644
index ca1a199..0000000
--- a/util/disabledeadlock/disable_deadlock.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package disabledeadlock
-
-import "github.com/algorand/go-deadlock"
-
-func init() {
-	// disable go-deadlock detection
-	deadlock.Opts.Disable = true
-}
diff --git a/util/ledger_util.go b/util/ledger_util.go
deleted file mode 100644
index be77185..0000000
--- a/util/ledger_util.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package util
-
-import (
-	"fmt"
-	"io"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-
-	log "github.com/sirupsen/logrus"
-
-	sdk "github.com/algorand/go-algorand-sdk/v2/types"
-	algodConfig "github.com/algorand/go-algorand/config"
-	"github.com/algorand/go-algorand/data/basics"
-	"github.com/algorand/go-algorand/data/bookkeeping"
-	"github.com/algorand/go-algorand/ledger"
-	"github.com/algorand/go-algorand/ledger/ledgercore"
-	"github.com/algorand/go-algorand/logging"
-	"github.com/algorand/go-algorand/protocol"
-)
-
-// ReadGenesis converts a reader into a Genesis file.
-func ReadGenesis(in io.Reader) (sdk.Genesis, error) {
-	var genesis sdk.Genesis
-	if in == nil {
-		return sdk.Genesis{}, fmt.Errorf("ReadGenesis() err: reader is nil")
-	}
-	gbytes, err := ioutil.ReadAll(in)
-	if err != nil {
-		return sdk.Genesis{}, fmt.Errorf("ReadGenesis() err: %w", err)
-	}
-	err = protocol.DecodeJSON(gbytes, &genesis)
-	if err != nil {
-		return sdk.Genesis{}, fmt.Errorf("ReadGenesis() decode err: %w", err)
-	}
-	return genesis, nil
-}
-
-// CreateInitState makes an initState
-func createInitState(genesis *bookkeeping.Genesis) (ledgercore.InitState, error) {
-	balances, err := genesis.Balances()
-	if err != nil {
-		return ledgercore.InitState{}, fmt.Errorf("MakeProcessor() err: %w", err)
-	}
-	genesisBlock, err := bookkeeping.MakeGenesisBlock(genesis.Proto, balances, genesis.ID(), genesis.Hash())
-	if err != nil {
-		return ledgercore.InitState{}, fmt.Errorf("MakeProcessor() err: %w", err)
-	}
-
-	accounts := make(map[basics.Address]basics.AccountData)
-	for _, alloc := range genesis.Allocation {
-		address, err := basics.UnmarshalChecksumAddress(alloc.Address)
-		if err != nil {
-			return ledgercore.InitState{}, fmt.Errorf("openLedger() decode address err: %w", err)
-		}
-		accounts[address] = alloc.State
-	}
-	initState := ledgercore.InitState{
-		Block:       genesisBlock,
-		Accounts:    accounts,
-		GenesisHash: genesisBlock.GenesisHash(),
-	}
-	return initState, nil
-}
-
-// MakeLedger opens a ledger, initializing if necessary.
-func MakeLedger(logger *log.Logger, inMemory bool, genesis *bookkeeping.Genesis, dataDir string) (*ledger.Ledger, error) {
-	const prefix = "ledger"
-	err := os.MkdirAll(dataDir, 0755)
-	if err != nil {
-		return nil, fmt.Errorf("MakeProcessor() failed to create '%s': %w", dataDir, err)
-	}
-	dbPrefix := filepath.Join(dataDir, prefix)
-	initState, err := createInitState(genesis)
-	if err != nil {
-		return nil, fmt.Errorf("MakeProcessor() err: %w", err)
-	}
-	return ledger.OpenLedger(logging.NewWrappedLogger(logger), dbPrefix, inMemory, initState, algodConfig.GetDefaultLocal())
-}
diff --git a/util/util.go b/util/util.go
index 9a1fc73..a4540a8 100644
--- a/util/util.go
+++ b/util/util.go
@@ -1,9 +1,6 @@
 package util
 
 import (
-	"bytes"
-	"compress/gzip"
-	"encoding/base32"
 	"errors"
 	"fmt"
 	"io"
@@ -16,91 +13,13 @@ import (
 
 	"github.com/algorand/go-codec/codec"
 	"github.com/algorand/indexer/idb"
+	"github.com/algorand/indexer/protocol"
+	"github.com/algorand/indexer/protocol/config"
 
 	"github.com/algorand/go-algorand-sdk/v2/encoding/json"
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
-	"github.com/algorand/go-algorand/config"
-	"github.com/algorand/go-algorand/protocol"
 )
 
-const (
-	checksumLength = 4
-)
-
-var prettyHandle *codec.JsonHandle
-
-var base32Encoder = base32.StdEncoding.WithPadding(base32.NoPadding)
-
-func init() {
-	prettyHandle = new(codec.JsonHandle)
-	prettyHandle.ErrorIfNoField = json.CodecHandle.ErrorIfNoField
-	prettyHandle.ErrorIfNoArrayExpand = json.CodecHandle.ErrorIfNoArrayExpand
-	prettyHandle.Canonical = json.CodecHandle.Canonical
-	prettyHandle.RecursiveEmptyCheck = json.CodecHandle.RecursiveEmptyCheck
-	prettyHandle.Indent = json.CodecHandle.Indent
-	prettyHandle.HTMLCharsAsIs = json.CodecHandle.HTMLCharsAsIs
-	prettyHandle.MapKeyAsString = true
-	prettyHandle.Indent = 2
-}
-
-// EncodeJSONToFile is used to encode an object to a file. If the file ends in .gz it will be gzipped.
-func EncodeJSONToFile(filename string, v interface{}, pretty bool) error {
-	var writer io.Writer
-
-	file, err := os.Create(filename)
-	if err != nil {
-		return fmt.Errorf("EncodeJSONToFile(): failed to create %s: %w", filename, err)
-	}
-	defer file.Close()
-
-	if strings.HasSuffix(filename, ".gz") {
-		gz := gzip.NewWriter(file)
-		gz.Name = filename
-		defer gz.Close()
-		writer = gz
-	} else {
-		writer = file
-	}
-
-	var handle *codec.JsonHandle
-	if pretty {
-		handle = prettyHandle
-	} else {
-		handle = protocol.JSONStrictHandle
-	}
-	enc := codec.NewEncoder(writer, handle)
-	return enc.Encode(v)
-}
-
-// DecodeJSONFromFile is used to decode a file to an object.
-func DecodeJSONFromFile(filename string, v interface{}, strict bool) error {
-	// Streaming into the decoder was slow.
-	fileBytes, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return fmt.Errorf("DecodeJSONFromFile(): failed to read %s: %w", filename, err)
-	}
-
-	var reader io.Reader = bytes.NewReader(fileBytes)
-
-	if strings.HasSuffix(filename, ".gz") {
-		gz, err := gzip.NewReader(reader)
-		defer gz.Close()
-		if err != nil {
-			return fmt.Errorf("DecodeJSONFromFile(): failed to make gzip reader: %w", err)
-		}
-		reader = gz
-	}
-	var handle *codec.JsonHandle
-	if strict {
-		handle = json.CodecHandle
-	} else {
-		handle = json.LenientCodecHandle
-	}
-
-	enc := codec.NewDecoder(reader, handle)
-	return enc.Decode(v)
-}
-
 // PrintableUTF8OrEmpty checks to see if the entire string is a UTF8 printable string.
 // If this is the case, the string is returned as is. Otherwise, the empty string is returned.
 func PrintableUTF8OrEmpty(in string) string {
@@ -308,6 +227,23 @@ func checkGenesisHash(db idb.IndexerDb, gh sdk.Digest) error {
 	return nil
 }
 
+// ReadGenesis converts a reader into a Genesis file.
+func ReadGenesis(in io.Reader) (sdk.Genesis, error) {
+	var genesis sdk.Genesis
+	if in == nil {
+		return sdk.Genesis{}, fmt.Errorf("ReadGenesis() err: reader is nil")
+	}
+	gbytes, err := ioutil.ReadAll(in)
+	if err != nil {
+		return sdk.Genesis{}, fmt.Errorf("ReadGenesis() err: %w", err)
+	}
+	err = json.Decode(gbytes, &genesis)
+	if err != nil {
+		return sdk.Genesis{}, fmt.Errorf("ReadGenesis() decode err: %w", err)
+	}
+	return genesis, nil
+}
+
 func init() {
 	oneLineJSONCodecHandle = new(codec.JsonHandle)
 	oneLineJSONCodecHandle.ErrorIfNoField = true


Test patch:
diff --git a/cmd/conduit/internal/initialize/init_test.go b/cmd/conduit/internal/initialize/init_test.go
new file mode 100644
index 0000000..acdc326
--- /dev/null
+++ b/cmd/conduit/internal/initialize/init_test.go
@@ -0,0 +1,55 @@
+package initialize
+
+import (
+	_ "embed"
+	"fmt"
+	"gopkg.in/yaml.v3"
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/algorand/indexer/conduit/pipeline"
+	"github.com/algorand/indexer/conduit/plugins/exporters/filewriter"
+	noopExporter "github.com/algorand/indexer/conduit/plugins/exporters/noop"
+	algodimporter "github.com/algorand/indexer/conduit/plugins/importers/algod"
+	fileimporter "github.com/algorand/indexer/conduit/plugins/importers/filereader"
+	"github.com/algorand/indexer/conduit/plugins/processors/filterprocessor"
+	noopProcessor "github.com/algorand/indexer/conduit/plugins/processors/noop"
+)
+
+//go:embed conduit.test.init.default.yml
+var defaultYml string
+
+// TestInitDataDirectory tests the initialization of the data directory
+func TestInitDataDirectory(t *testing.T) {
+	verifyFile := func(file string, importer string, exporter string, processors []string) {
+		require.FileExists(t, file)
+		data, err := os.ReadFile(file)
+		require.NoError(t, err)
+		var cfg pipeline.Config
+		require.NoError(t, yaml.Unmarshal(data, &cfg))
+		assert.Equal(t, importer, cfg.Importer.Name)
+		assert.Equal(t, exporter, cfg.Exporter.Name)
+		require.Equal(t, len(processors), len(cfg.Processors))
+		for i := range processors {
+			assert.Equal(t, processors[i], cfg.Processors[i].Name)
+		}
+	}
+
+	// Defaults
+	dataDirectory := t.TempDir()
+	runConduitInit(dataDirectory, "", []string{}, "")
+	verifyFile(fmt.Sprintf("%s/conduit.yml", dataDirectory), algodimporter.PluginName, filewriter.PluginName, nil)
+
+	// Explicit defaults
+	dataDirectory = t.TempDir()
+	runConduitInit(dataDirectory, algodimporter.PluginName, []string{noopProcessor.PluginName}, filewriter.PluginName)
+	verifyFile(fmt.Sprintf("%s/conduit.yml", dataDirectory), algodimporter.PluginName, filewriter.PluginName, []string{noopProcessor.PluginName})
+
+	// Different
+	dataDirectory = t.TempDir()
+	runConduitInit(dataDirectory, fileimporter.PluginName, []string{noopProcessor.PluginName, filterprocessor.PluginName}, noopExporter.PluginName)
+	verifyFile(fmt.Sprintf("%s/conduit.yml", dataDirectory), fileimporter.PluginName, noopExporter.PluginName, []string{noopProcessor.PluginName, filterprocessor.PluginName})
+}
diff --git a/cmd/conduit/main_test.go b/cmd/conduit/main_test.go
index 968f78d..4238c60 100644
--- a/cmd/conduit/main_test.go
+++ b/cmd/conduit/main_test.go
@@ -2,7 +2,6 @@ package main
 
 import (
 	_ "embed"
-	"fmt"
 	"os"
 	"path"
 	"testing"
@@ -13,49 +12,8 @@ import (
 
 	"github.com/algorand/indexer/conduit"
 	"github.com/algorand/indexer/conduit/pipeline"
-	"github.com/algorand/indexer/conduit/plugins/exporters/filewriter"
-	noopExporter "github.com/algorand/indexer/conduit/plugins/exporters/noop"
-	algodimporter "github.com/algorand/indexer/conduit/plugins/importers/algod"
-	fileimporter "github.com/algorand/indexer/conduit/plugins/importers/filereader"
-	"github.com/algorand/indexer/conduit/plugins/processors/filterprocessor"
-	noopProcessor "github.com/algorand/indexer/conduit/plugins/processors/noop"
 )
 
-//go:embed conduit.test.init.default.yml
-var defaultYml string
-
-// TestInitDataDirectory tests the initialization of the data directory
-func TestInitDataDirectory(t *testing.T) {
-	verifyFile := func(file string, importer string, exporter string, processors []string) {
-		require.FileExists(t, file)
-		data, err := os.ReadFile(file)
-		require.NoError(t, err)
-		var cfg pipeline.Config
-		require.NoError(t, yaml.Unmarshal(data, &cfg))
-		assert.Equal(t, importer, cfg.Importer.Name)
-		assert.Equal(t, exporter, cfg.Exporter.Name)
-		require.Equal(t, len(processors), len(cfg.Processors))
-		for i := range processors {
-			assert.Equal(t, processors[i], cfg.Processors[i].Name)
-		}
-	}
-
-	// Defaults
-	dataDirectory := t.TempDir()
-	runConduitInit(dataDirectory, "", []string{}, "")
-	verifyFile(fmt.Sprintf("%s/conduit.yml", dataDirectory), algodimporter.PluginName, filewriter.PluginName, nil)
-
-	// Explicit defaults
-	dataDirectory = t.TempDir()
-	runConduitInit(dataDirectory, algodimporter.PluginName, []string{noopProcessor.PluginName}, filewriter.PluginName)
-	verifyFile(fmt.Sprintf("%s/conduit.yml", dataDirectory), algodimporter.PluginName, filewriter.PluginName, []string{noopProcessor.PluginName})
-
-	// Different
-	dataDirectory = t.TempDir()
-	runConduitInit(dataDirectory, fileimporter.PluginName, []string{noopProcessor.PluginName, filterprocessor.PluginName}, noopExporter.PluginName)
-	verifyFile(fmt.Sprintf("%s/conduit.yml", dataDirectory), fileimporter.PluginName, noopExporter.PluginName, []string{noopProcessor.PluginName, filterprocessor.PluginName})
-}
-
 func TestBanner(t *testing.T) {
 	test := func(t *testing.T, hideBanner bool) {
 		// Capture stdout.
@@ -139,6 +97,8 @@ func TestLogFile(t *testing.T) {
 		require.NoError(t, err)
 		dataStr := string(data)
 		require.Contains(t, dataStr, "{")
+		require.Contains(t, dataStr, "\nWriting logs to console.")
+		require.Contains(t, dataStr, "\npipeline creation error")
 	})
 
 	// logging to file
@@ -152,5 +112,9 @@ func TestLogFile(t *testing.T) {
 		require.NoError(t, err)
 		logdataStr := string(logdata)
 		require.Contains(t, logdataStr, "{")
+		// written to stdout and logfile
+		require.Contains(t, dataStr, "\npipeline creation error")
+		require.Contains(t, dataStr, "\nWriting logs to file:")
+		require.Contains(t, logdataStr, `"msg":"pipeline creation error`)
 	})
 }
diff --git a/conduit/pipeline/pipeline_test.go b/conduit/pipeline/pipeline_test.go
index 3c2815e..6c9bf9a 100644
--- a/conduit/pipeline/pipeline_test.go
+++ b/conduit/pipeline/pipeline_test.go
@@ -21,11 +21,11 @@ import (
 	"github.com/stretchr/testify/mock"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
 	"github.com/algorand/indexer/conduit/plugins/importers"
 	"github.com/algorand/indexer/conduit/plugins/processors"
-	"github.com/algorand/indexer/data"
 	_ "github.com/algorand/indexer/util/metrics"
 )
 
diff --git a/conduit/plugins/exporters/example/example_exporter_test.go b/conduit/plugins/exporters/example/example_exporter_test.go
index c928346..37e94fe 100644
--- a/conduit/plugins/exporters/example/example_exporter_test.go
+++ b/conduit/plugins/exporters/example/example_exporter_test.go
@@ -6,9 +6,9 @@ import (
 
 	"github.com/stretchr/testify/assert"
 
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
-	"github.com/algorand/indexer/data"
 )
 
 var exCons = exporters.ExporterConstructorFunc(func() exporters.Exporter {
diff --git a/conduit/plugins/exporters/filewriter/file_exporter_test.go b/conduit/plugins/exporters/filewriter/file_exporter_test.go
index d832b5b..8108448 100644
--- a/conduit/plugins/exporters/filewriter/file_exporter_test.go
+++ b/conduit/plugins/exporters/filewriter/file_exporter_test.go
@@ -13,11 +13,10 @@ import (
 	"github.com/stretchr/testify/require"
 	"gopkg.in/yaml.v3"
 
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
-	"github.com/algorand/indexer/data"
-	"github.com/algorand/indexer/util"
-	testutil "github.com/algorand/indexer/util/test"
+	"github.com/algorand/indexer/conduit/plugins/tools/testutil"
 
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
@@ -176,7 +175,7 @@ func TestExporterReceive(t *testing.T) {
 		assert.NotContains(t, string(blockBytes), " 0: ")
 
 		var blockData data.BlockData
-		err = util.DecodeJSONFromFile(path, &blockData, true)
+		err = DecodeJSONFromFile(path, &blockData, true)
 		require.Equal(t, sdk.Round(i), blockData.BlockHeader.Round)
 		require.NoError(t, err)
 		require.NotNil(t, blockData.Certificate)
@@ -208,7 +207,7 @@ func TestPatternOverride(t *testing.T) {
 		assert.FileExists(t, path)
 
 		var blockData data.BlockData
-		err := util.DecodeJSONFromFile(path, &blockData, true)
+		err := DecodeJSONFromFile(path, &blockData, true)
 		require.Equal(t, sdk.Round(i), blockData.BlockHeader.Round)
 		require.NoError(t, err)
 		require.NotNil(t, blockData.Certificate)
@@ -234,7 +233,7 @@ func TestDropCertificate(t *testing.T) {
 		path := fmt.Sprintf("%s/%s", tempdir, filename)
 		assert.FileExists(t, path)
 		var blockData data.BlockData
-		err := util.DecodeJSONFromFile(path, &blockData, true)
+		err := DecodeJSONFromFile(path, &blockData, true)
 		assert.NoError(t, err)
 		assert.Nil(t, blockData.Certificate)
 	}
diff --git a/conduit/plugins/exporters/filewriter/util_test.go b/conduit/plugins/exporters/filewriter/util_test.go
new file mode 100644
index 0000000..ba017e2
--- /dev/null
+++ b/conduit/plugins/exporters/filewriter/util_test.go
@@ -0,0 +1,63 @@
+package filewriter
+
+import (
+	"io/ioutil"
+	"path"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestEncodeToAndFromFile(t *testing.T) {
+	tempdir := t.TempDir()
+
+	type test struct {
+		One    string         `json:"one"`
+		Two    int            `json:"two"`
+		Strict map[int]string `json:"strict"`
+	}
+	data := test{
+		One: "one",
+		Two: 2,
+		Strict: map[int]string{
+			0: "int-key",
+		},
+	}
+
+	{
+		pretty := path.Join(tempdir, "pretty.json")
+		err := EncodeJSONToFile(pretty, data, true)
+		require.NoError(t, err)
+		require.FileExists(t, pretty)
+		var testDecode test
+		err = DecodeJSONFromFile(pretty, &testDecode, false)
+		require.Equal(t, data, testDecode)
+
+		// Check the pretty printing
+		bytes, err := ioutil.ReadFile(pretty)
+		require.NoError(t, err)
+		require.Contains(t, string(bytes), "  \"one\": \"one\",\n")
+		require.Contains(t, string(bytes), `"0": "int-key"`)
+	}
+
+	{
+		small := path.Join(tempdir, "small.json")
+		err := EncodeJSONToFile(small, data, false)
+		require.NoError(t, err)
+		require.FileExists(t, small)
+		var testDecode test
+		err = DecodeJSONFromFile(small, &testDecode, false)
+		require.Equal(t, data, testDecode)
+	}
+
+	// gzip test
+	{
+		small := path.Join(tempdir, "small.json.gz")
+		err := EncodeJSONToFile(small, data, false)
+		require.NoError(t, err)
+		require.FileExists(t, small)
+		var testDecode test
+		err = DecodeJSONFromFile(small, &testDecode, false)
+		require.Equal(t, data, testDecode)
+	}
+}
diff --git a/conduit/plugins/exporters/noop/noop_exporter_test.go b/conduit/plugins/exporters/noop/noop_exporter_test.go
index 2d20d38..0430174 100644
--- a/conduit/plugins/exporters/noop/noop_exporter_test.go
+++ b/conduit/plugins/exporters/noop/noop_exporter_test.go
@@ -7,10 +7,10 @@ import (
 	"github.com/stretchr/testify/assert"
 	"gopkg.in/yaml.v3"
 
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
-	"github.com/algorand/indexer/data"
-	testutil "github.com/algorand/indexer/util/test"
+	"github.com/algorand/indexer/conduit/plugins/tools/testutil"
 
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
diff --git a/conduit/plugins/exporters/postgresql/postgresql_exporter_test.go b/conduit/plugins/exporters/postgresql/postgresql_exporter_test.go
index c693aff..cfcdf6b 100644
--- a/conduit/plugins/exporters/postgresql/postgresql_exporter_test.go
+++ b/conduit/plugins/exporters/postgresql/postgresql_exporter_test.go
@@ -11,12 +11,12 @@ import (
 	"github.com/stretchr/testify/assert"
 	"gopkg.in/yaml.v3"
 
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters"
 	"github.com/algorand/indexer/conduit/plugins/exporters/postgresql/util"
-	"github.com/algorand/indexer/data"
+	"github.com/algorand/indexer/conduit/plugins/tools/testutil"
 	_ "github.com/algorand/indexer/idb/dummy"
-	testutil "github.com/algorand/indexer/util/test"
 )
 
 var pgsqlConstructor = exporters.ExporterConstructorFunc(func() exporters.Exporter {
diff --git a/conduit/plugins/importers/algod/algod_importer_test.go b/conduit/plugins/importers/algod/algod_importer_test.go
index bc7e64c..b46e558 100644
--- a/conduit/plugins/importers/algod/algod_importer_test.go
+++ b/conduit/plugins/importers/algod/algod_importer_test.go
@@ -14,7 +14,6 @@ import (
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 
 	"github.com/algorand/indexer/conduit/plugins"
-	"github.com/algorand/indexer/util/test"
 )
 
 var (
@@ -39,7 +38,7 @@ func TestImporterMetadata(t *testing.T) {
 }
 
 func TestCloseSuccess(t *testing.T) {
-	ts := test.NewAlgodServer(test.GenesisResponder)
+	ts := NewAlgodServer(GenesisResponder)
 	testImporter := New()
 	cfgStr := fmt.Sprintf(`---
 mode: %s
@@ -60,7 +59,7 @@ func TestInitSuccess(t *testing.T) {
 	}
 	for _, ttest := range tests {
 		t.Run(ttest.name, func(t *testing.T) {
-			ts := test.NewAlgodServer(test.GenesisResponder)
+			ts := NewAlgodServer(GenesisResponder)
 			testImporter := New()
 			cfgStr := fmt.Sprintf(`---
 mode: %s
@@ -101,7 +100,7 @@ func TestInitModeFailure(t *testing.T) {
 	}
 	for _, ttest := range tests {
 		t.Run(ttest.name, func(t *testing.T) {
-			ts := test.NewAlgodServer(test.GenesisResponder)
+			ts := NewAlgodServer(GenesisResponder)
 			testImporter := New()
 			cfgStr := fmt.Sprintf(`---
 mode: %s
@@ -114,7 +113,7 @@ netaddr: %s
 }
 
 func TestInitGenesisFailure(t *testing.T) {
-	ts := test.NewAlgodServer(test.MakeGenesisResponder(sdk.Genesis{}))
+	ts := NewAlgodServer(MakeGenesisResponder(sdk.Genesis{}))
 	testImporter := New()
 	cfgStr := fmt.Sprintf(`---
 mode: %s
@@ -144,7 +143,7 @@ func TestConfigDefault(t *testing.T) {
 }
 
 func TestWaitForBlockBlockFailure(t *testing.T) {
-	ts := test.NewAlgodServer(test.GenesisResponder)
+	ts := NewAlgodServer(GenesisResponder)
 	testImporter := New()
 	cfgStr := fmt.Sprintf(`---
 mode: %s
@@ -165,15 +164,15 @@ func TestGetBlockSuccess(t *testing.T) {
 		name        string
 		algodServer *httptest.Server
 	}{
-		{"", test.NewAlgodServer(test.GenesisResponder,
-			test.BlockResponder,
-			test.BlockAfterResponder)},
-		{"archival", test.NewAlgodServer(test.GenesisResponder,
-			test.BlockResponder,
-			test.BlockAfterResponder)},
-		{"follower", test.NewAlgodServer(test.GenesisResponder,
-			test.BlockResponder,
-			test.BlockAfterResponder, test.LedgerStateDeltaResponder)},
+		{"", NewAlgodServer(GenesisResponder,
+			BlockResponder,
+			BlockAfterResponder)},
+		{"archival", NewAlgodServer(GenesisResponder,
+			BlockResponder,
+			BlockAfterResponder)},
+		{"follower", NewAlgodServer(GenesisResponder,
+			BlockResponder,
+			BlockAfterResponder, LedgerStateDeltaResponder)},
 	}
 	for _, ttest := range tests {
 		t.Run(ttest.name, func(t *testing.T) {
@@ -214,12 +213,12 @@ func TestGetBlockContextCancelled(t *testing.T) {
 		name        string
 		algodServer *httptest.Server
 	}{
-		{"archival", test.NewAlgodServer(test.GenesisResponder,
-			test.BlockResponder,
-			test.BlockAfterResponder)},
-		{"follower", test.NewAlgodServer(test.GenesisResponder,
-			test.BlockResponder,
-			test.BlockAfterResponder, test.LedgerStateDeltaResponder)},
+		{"archival", NewAlgodServer(GenesisResponder,
+			BlockResponder,
+			BlockAfterResponder)},
+		{"follower", NewAlgodServer(GenesisResponder,
+			BlockResponder,
+			BlockAfterResponder, LedgerStateDeltaResponder)},
 	}
 
 	for _, ttest := range tests {
@@ -246,10 +245,10 @@ func TestGetBlockFailure(t *testing.T) {
 		name        string
 		algodServer *httptest.Server
 	}{
-		{"archival", test.NewAlgodServer(test.GenesisResponder,
-			test.BlockAfterResponder)},
-		{"follower", test.NewAlgodServer(test.GenesisResponder,
-			test.BlockAfterResponder, test.LedgerStateDeltaResponder)},
+		{"archival", NewAlgodServer(GenesisResponder,
+			BlockAfterResponder)},
+		{"follower", NewAlgodServer(GenesisResponder,
+			BlockAfterResponder, LedgerStateDeltaResponder)},
 	}
 	for _, ttest := range tests {
 		t.Run(ttest.name, func(t *testing.T) {
diff --git a/util/test/mock_algod.go b/conduit/plugins/importers/algod/mock_algod_test.go
similarity index 99%
rename from util/test/mock_algod.go
rename to conduit/plugins/importers/algod/mock_algod_test.go
index f1ddee8..7f0d7e2 100644
--- a/util/test/mock_algod.go
+++ b/conduit/plugins/importers/algod/mock_algod_test.go
@@ -1,4 +1,4 @@
-package test
+package algodimporter
 
 import (
 	"net/http"
diff --git a/conduit/plugins/importers/filereader/filereader_test.go b/conduit/plugins/importers/filereader/filereader_test.go
index e824492..435c054 100644
--- a/conduit/plugins/importers/filereader/filereader_test.go
+++ b/conduit/plugins/importers/filereader/filereader_test.go
@@ -14,11 +14,10 @@ import (
 	"github.com/stretchr/testify/require"
 	"gopkg.in/yaml.v3"
 
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/exporters/filewriter"
 	"github.com/algorand/indexer/conduit/plugins/importers"
-	"github.com/algorand/indexer/data"
-	"github.com/algorand/indexer/util"
 )
 
 var (
@@ -54,7 +53,7 @@ func initializeTestData(t *testing.T, dir string, numRounds int) sdk.Genesis {
 		Timestamp:   1234,
 	}
 
-	err := util.EncodeJSONToFile(path.Join(dir, "genesis.json"), genesisA, true)
+	err := filewriter.EncodeJSONToFile(path.Join(dir, "genesis.json"), genesisA, true)
 	require.NoError(t, err)
 
 	for i := 0; i < numRounds; i++ {
@@ -67,7 +66,7 @@ func initializeTestData(t *testing.T, dir string, numRounds int) sdk.Genesis {
 			Certificate: nil,
 		}
 		blockFile := path.Join(dir, fmt.Sprintf(filewriter.FilePattern, i))
-		err = util.EncodeJSONToFile(blockFile, block, true)
+		err = filewriter.EncodeJSONToFile(blockFile, block, true)
 		require.NoError(t, err)
 	}
 
diff --git a/conduit/plugins/processors/filterprocessor/filter_processor_bench_test.go b/conduit/plugins/processors/filterprocessor/filter_processor_bench_test.go
index 8214d6a..71fe1e4 100644
--- a/conduit/plugins/processors/filterprocessor/filter_processor_bench_test.go
+++ b/conduit/plugins/processors/filterprocessor/filter_processor_bench_test.go
@@ -9,8 +9,8 @@ import (
 
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
-	"github.com/algorand/indexer/data"
 	"github.com/sirupsen/logrus"
 	"github.com/stretchr/testify/assert"
 )
diff --git a/conduit/plugins/processors/filterprocessor/filter_processor_test.go b/conduit/plugins/processors/filterprocessor/filter_processor_test.go
index 02e4d50..cab9e4e 100644
--- a/conduit/plugins/processors/filterprocessor/filter_processor_test.go
+++ b/conduit/plugins/processors/filterprocessor/filter_processor_test.go
@@ -10,9 +10,9 @@ import (
 	"github.com/stretchr/testify/require"
 
 	"github.com/algorand/indexer/conduit"
+	"github.com/algorand/indexer/conduit/data"
 	"github.com/algorand/indexer/conduit/plugins"
 	"github.com/algorand/indexer/conduit/plugins/processors"
-	"github.com/algorand/indexer/data"
 )
 
 // create an empty block data so that txn fields can be set with less vertical space
diff --git a/conduit/plugins/tools/testutil/mockinit.go b/conduit/plugins/tools/testutil/mockinit.go
new file mode 100644
index 0000000..c8b9675
--- /dev/null
+++ b/conduit/plugins/tools/testutil/mockinit.go
@@ -0,0 +1,27 @@
+package testutil
+
+import sdk "github.com/algorand/go-algorand-sdk/v2/types"
+
+// MockInitProvider mock an init provider
+type MockInitProvider struct {
+	CurrentRound *sdk.Round
+	Genesis      *sdk.Genesis
+}
+
+// GetGenesis produces genesis pointer
+func (m *MockInitProvider) GetGenesis() *sdk.Genesis {
+	return m.Genesis
+}
+
+// NextDBRound provides next database round
+func (m *MockInitProvider) NextDBRound() sdk.Round {
+	return *m.CurrentRound
+}
+
+// MockedInitProvider returns an InitProvider for testing
+func MockedInitProvider(round *sdk.Round) *MockInitProvider {
+	return &MockInitProvider{
+		CurrentRound: round,
+		Genesis:      &sdk.Genesis{},
+	}
+}
diff --git a/fetcher/fetcher_test.go b/config/datadir_test.go
similarity index 98%
rename from fetcher/fetcher_test.go
rename to config/datadir_test.go
index c79204a..d252fcc 100644
--- a/fetcher/fetcher_test.go
+++ b/config/datadir_test.go
@@ -1,4 +1,4 @@
-package fetcher
+package config
 
 import (
 	"fmt"
diff --git a/e2e_tests/README.md b/e2e_tests/README.md
index f51b271..bd0fff4 100644
--- a/e2e_tests/README.md
+++ b/e2e_tests/README.md
@@ -63,3 +63,53 @@ make e2e
 ```
 
 Alternatively, modify `e2e_tests/docker/indexer/Dockerfile` by swapping out `$CI_E2E_FILENAME` with the test artifact you want to use. See `.circleci/config.yml` for the current values used by CI.
+
+### Creating new Conduit e2e tests
+
+## Creating a new plugin fixture
+All plugins for e2e tests are organized in `e2e_tests/src/e2e_conduit/fixtures/` under the proper directory structure. For example, processor plugin fixtures are under `e2e_tests/src/e2e_conduit/fixtures/processors/`.
+
+To create a new plugin, create a new class under the proper directory which subclasses `PluginFixture`.  
+__Note that some fixtures have further subclasses, such as ImporterPlugin, which support additional required behavior for those plugin types.__
+
+### Main Methods of PluginFixtures
+
+* `name`  
+Returns the name of the plugin--must be equivalent to the name which would be used in the conduit config.
+
+* `setup(self, accumulated_config)`  
+Setup is run before any of the config data is resolved. It accepts an `accumulated_config` which is a map containing all of the previously output config values.
+If your plugin needs to be fed some data, such as the algod directory which was created by the importer, this data can be retrieved from the accumulated_config.
+
+The setup method is responsible for any preparation your plugin needs to do before the pipeline starts.
+
+* `resolve_config_input`  
+This method sets values on `self.config_input`, a map which contains all of the Conduit config required to run your plugin. Any values set on this map will be serialized into
+the data section of your plugin's config when running it in Conduit.
+
+* `resolve_config_output`  
+Here, similarly to `config_input`, we set values on the `config_output` map. This map is what will be passed between plugins during initialization via the `accumulated_config`. If your plugin is creating any resources or initializing any values which other plugins need to know about, they should be set in the `config_output`.
+
+
+## Creating a new scenario using your plugin
+A `Scenario` is an abstraction for a given instantiation of a Conduit pipeline. In order to run a coduit e2e test, create a scenario in `e2e_tests/src/e2e_conduit/scenarios` and ensure that it is run in `e2e_tests/src/e2e_conduit/e2econduit.py`.
+
+For example,
+
+```
+Scenario(
+        "app_filter_indexer_scenario",
+        importer=importers.FollowerAlgodImporter(sourcenet),
+        processors=[
+            processors.FilterProcessor([
+                {"any": [
+                    {"tag": "txn.type",
+                     "expression-type": "equal",
+                     "expression": "appl"
+                    }
+                ]}
+            ]),
+        ],
+        exporter=exporters.PostgresqlExporter(),
+    )
+```
diff --git a/e2e_tests/src/e2e_conduit/e2econduit.py b/e2e_tests/src/e2e_conduit/e2econduit.py
index ad5798d..8473950 100644
--- a/e2e_tests/src/e2e_conduit/e2econduit.py
+++ b/e2e_tests/src/e2e_conduit/e2econduit.py
@@ -13,6 +13,7 @@ import e2e_conduit.fixtures.exporters as exporters
 from e2e_conduit.runner import ConduitE2ETestRunner
 from e2e_conduit.scenarios import scenarios
 from e2e_conduit.scenarios.follower_indexer_scenario import follower_indexer_scenario
+from e2e_conduit.scenarios.filter_scenario import app_filter_indexer_scenario, pay_filter_indexer_scenario
 
 logger = logging.getLogger(__name__)
 
@@ -49,6 +50,8 @@ def main():
     importer_source = sourcenet if sourcenet else args.s3_source_net
     if importer_source:
         scenarios.append(follower_indexer_scenario(importer_source))
+        scenarios.append(app_filter_indexer_scenario(importer_source))
+        scenarios.append(pay_filter_indexer_scenario(importer_source))
 
     runner = ConduitE2ETestRunner(args.conduit_bin, keep_temps=args.keep_temps)
 
diff --git a/e2e_tests/src/e2e_conduit/fixtures/processors/__init__.py b/e2e_tests/src/e2e_conduit/fixtures/processors/__init__.py
index e69de29..c7aee57 100644
--- a/e2e_tests/src/e2e_conduit/fixtures/processors/__init__.py
+++ b/e2e_tests/src/e2e_conduit/fixtures/processors/__init__.py
@@ -0,0 +1,1 @@
+from e2e_conduit.fixtures.processors.filter import FilterProcessor
\ No newline at end of file
diff --git a/e2e_tests/src/e2e_conduit/fixtures/processors/filter.py b/e2e_tests/src/e2e_conduit/fixtures/processors/filter.py
new file mode 100644
index 0000000..361534d
--- /dev/null
+++ b/e2e_tests/src/e2e_conduit/fixtures/processors/filter.py
@@ -0,0 +1,25 @@
+from e2e_conduit.fixtures.plugin_fixture import PluginFixture
+
+
+''' FilterProcessor is a simple passthrough for the `filter_processor`
+    which sets the scenario's filters to the initialized value
+'''
+class FilterProcessor(PluginFixture):
+    def __init__(self, filters, search_inner=True):
+        self.filters = filters
+        self.search_inner = search_inner
+        super().__init__()
+
+    @property
+    def name(self):
+        return "filter_processor"
+
+    def resolve_config_input(self):
+        self.config_input["filters"] = self.filters
+        self.config_input["search-inner"] = self.search_inner
+
+    def resolve_config_output(self):
+        pass
+
+    def setup(self, accumulated_config):
+        pass
diff --git a/e2e_tests/src/e2e_conduit/scenarios/filter_scenario.py b/e2e_tests/src/e2e_conduit/scenarios/filter_scenario.py
new file mode 100644
index 0000000..338c81a
--- /dev/null
+++ b/e2e_tests/src/e2e_conduit/scenarios/filter_scenario.py
@@ -0,0 +1,40 @@
+import e2e_conduit.fixtures.importers as importers
+import e2e_conduit.fixtures.processors as processors
+import e2e_conduit.fixtures.exporters as exporters
+from e2e_conduit.scenarios import Scenario, scenarios
+
+
+def app_filter_indexer_scenario(sourcenet):
+    return Scenario(
+        "app_filter_indexer_scenario",
+        importer=importers.FollowerAlgodImporter(sourcenet),
+        processors=[
+            processors.FilterProcessor([
+                {"any": [
+                    {"tag": "txn.type",
+                     "expression-type": "equal",
+                     "expression": "appl"
+                    }
+                ]}
+            ]),
+        ],
+        exporter=exporters.PostgresqlExporter(),
+    )
+
+
+def pay_filter_indexer_scenario(sourcenet):
+    return Scenario(
+        "pay_filter_indexer_scenario",
+        importer=importers.FollowerAlgodImporter(sourcenet),
+        processors=[
+            processors.FilterProcessor([
+                {"any": [
+                    {"tag": "txn.type",
+                     "expression-type": "equal",
+                     "expression": "pay"
+                    }
+                ]}
+            ]),
+        ],
+        exporter=exporters.PostgresqlExporter(),
+    )
diff --git a/e2e_tests/src/e2e_indexer/e2elive.py b/e2e_tests/src/e2e_indexer/e2elive.py
index 546fde8..5fe0a1b 100644
--- a/e2e_tests/src/e2e_indexer/e2elive.py
+++ b/e2e_tests/src/e2e_indexer/e2elive.py
@@ -1,6 +1,4 @@
 #!/usr/bin/env python3
-#
-
 import atexit
 import glob
 import gzip
diff --git a/misc/parity/test_indexer_v_algod.py b/misc/parity/test_indexer_v_algod.py
index 28dc4f6..5747319 100644
--- a/misc/parity/test_indexer_v_algod.py
+++ b/misc/parity/test_indexer_v_algod.py
@@ -3,6 +3,7 @@ import json
 from pathlib import Path
 from typing import List
 import yaml
+import requests
 
 from git import Repo
 
@@ -24,8 +25,7 @@ PATH_KEY_EXCLUDES = []
 REPO_DIR = Path.cwd()
 INDEXER_SWGR = REPO_DIR / "api" / "indexer.oas2.json"
 
-GOAL_DIR = REPO_DIR / "third_party" / "go-algorand"
-ALGOD_SWGR = GOAL_DIR / "daemon" / "algod" / "api" / "algod.oas2.json"
+ALGOD_SWGR = "https://raw.githubusercontent.com/algorand/go-algorand/rel/nightly/daemon/algod/api/algod.oas2.json"
 
 REPORTS_DIR = REPO_DIR / "misc" / "parity" / "reports"
 
@@ -42,13 +42,10 @@ def print_git_info_once():
     indexer = Repo(REPO_DIR)
     indexer_commit = indexer.git.rev_parse("HEAD")
 
-    goal = Repo(GOAL_DIR)
-    goal_commit = goal.git.rev_parse("HEAD")
-
     print(
         f"""Finished comparing:
     * Indexer Swagger {INDEXER_SWGR} for commit hash {indexer_commit}
-    * Algod Swagger {ALGOD_SWGR} for commit hash {goal_commit}
+    * Algod Swagger {ALGOD_SWGR}
 """
     )
 
@@ -60,9 +57,9 @@ def tsetup():
         indexer = json.loads(f.read())
         indexer = select(indexer, PATH_INCLUDES)
 
-    with open(ALGOD_SWGR, "r") as f:
-        algod = json.loads(f.read())
-        algod = select(algod, PATH_INCLUDES)
+    f=requests.get(ALGOD_SWGR)
+    algod = json.loads(f.text)
+    algod = select(algod, PATH_INCLUDES)
 
     return PATH_KEY_EXCLUDES, indexer, algod
 
diff --git a/util/ledger_util_test.go b/util/ledger_util_test.go
deleted file mode 100644
index 9f35599..0000000
--- a/util/ledger_util_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package util
-
-import (
-	"io"
-	"strings"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-
-	"github.com/algorand/go-algorand-sdk/v2/encoding/json"
-	"github.com/algorand/go-algorand/data/bookkeeping"
-)
-
-func TestReadGenesis(t *testing.T) {
-	var reader io.Reader
-	// nil reader
-	_, err := ReadGenesis(reader)
-	assert.Contains(t, err.Error(), "reader is nil")
-	// no match struct field
-	genesisStr := "{\"version\": 2}"
-	reader = strings.NewReader(genesisStr)
-	_, err = ReadGenesis(reader)
-	assert.Contains(t, err.Error(), "json decode error")
-
-	genesis := bookkeeping.Genesis{
-		SchemaID:    "1",
-		Network:     "test",
-		Proto:       "test",
-		RewardsPool: "AAAA",
-		FeeSink:     "AAAA",
-	}
-
-	// read and decode genesis
-	reader = strings.NewReader(string(json.Encode(genesis)))
-	_, err = ReadGenesis(reader)
-	assert.Nil(t, err)
-	// read from empty reader
-	_, err = ReadGenesis(reader)
-	assert.Contains(t, err.Error(), "EOF")
-}
diff --git a/util/test/testutil.go b/util/test/testutil.go
index effc6c6..cb1a303 100644
--- a/util/test/testutil.go
+++ b/util/test/testutil.go
@@ -119,30 +119,6 @@ func PrintTxnQuery(db idb.IndexerDb, q idb.TransactionFilter) {
 	}
 }
 
-// MockInitProvider mock an init provider
-type MockInitProvider struct {
-	CurrentRound *sdk.Round
-	Genesis      *sdk.Genesis
-}
-
-// GetGenesis produces genesis pointer
-func (m *MockInitProvider) GetGenesis() *sdk.Genesis {
-	return m.Genesis
-}
-
-// NextDBRound provides next database round
-func (m *MockInitProvider) NextDBRound() sdk.Round {
-	return *m.CurrentRound
-}
-
-// MockedInitProvider returns an InitProvider for testing
-func MockedInitProvider(round *sdk.Round) *MockInitProvider {
-	return &MockInitProvider{
-		CurrentRound: round,
-		Genesis:      &sdk.Genesis{},
-	}
-}
-
 // ReadValidatedBlockFromFile reads a validated block from file
 func ReadValidatedBlockFromFile(filename string) (types.ValidatedBlock, error) {
 	var vb types.ValidatedBlock
diff --git a/util/util_test.go b/util/util_test.go
index fbbf905..3c960b6 100644
--- a/util/util_test.go
+++ b/util/util_test.go
@@ -2,9 +2,7 @@ package util
 
 import (
 	"encoding/base64"
-	"io/ioutil"
 	"math/rand"
-	"path"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -12,60 +10,6 @@ import (
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
 
-func TestEncodeToAndFromFile(t *testing.T) {
-	tempdir := t.TempDir()
-
-	type test struct {
-		One    string         `json:"one"`
-		Two    int            `json:"two"`
-		Strict map[int]string `json:"strict"`
-	}
-	data := test{
-		One: "one",
-		Two: 2,
-		Strict: map[int]string{
-			0: "int-key",
-		},
-	}
-
-	{
-		pretty := path.Join(tempdir, "pretty.json")
-		err := EncodeJSONToFile(pretty, data, true)
-		require.NoError(t, err)
-		require.FileExists(t, pretty)
-		var testDecode test
-		err = DecodeJSONFromFile(pretty, &testDecode, false)
-		require.Equal(t, data, testDecode)
-
-		// Check the pretty printing
-		bytes, err := ioutil.ReadFile(pretty)
-		require.NoError(t, err)
-		require.Contains(t, string(bytes), "  \"one\": \"one\",\n")
-		require.Contains(t, string(bytes), `"0": "int-key"`)
-	}
-
-	{
-		small := path.Join(tempdir, "small.json")
-		err := EncodeJSONToFile(small, data, false)
-		require.NoError(t, err)
-		require.FileExists(t, small)
-		var testDecode test
-		err = DecodeJSONFromFile(small, &testDecode, false)
-		require.Equal(t, data, testDecode)
-	}
-
-	// gzip test
-	{
-		small := path.Join(tempdir, "small.json.gz")
-		err := EncodeJSONToFile(small, data, false)
-		require.NoError(t, err)
-		require.FileExists(t, small)
-		var testDecode test
-		err = DecodeJSONFromFile(small, &testDecode, false)
-		require.Equal(t, data, testDecode)
-	}
-}
-
 func TestPrintableUTF8OrEmpty(t *testing.T) {
 	encodeArg := func(str string) string {
 		return base64.StdEncoding.EncodeToString([]byte("input"))