Repository: algorand/indexer
Pull request #1530 (2023-05-23 20:55:13)

encoding: Fix partupdrmv encoding.
## Summary

The go-algorand based version of Indexer missed the `partupdrmv` block header field. When switching back to the go-SDK this has caused a scenario where the old and new versions of Indexer database are no longer compatible. This fix makes the decoding more lenient and fixes the encoding to match the previous version.

In addition, this PR removes redundant overrides.

See commit 1 for removing redundant overrides.
See commit 2 for the `partupdrmv` override.

## Test Plan

Update unit tests.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/algorand/indexer/pull/1530?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand) Report
> Merging [#1530](https://app.codecov.io/gh/algorand/indexer/pull/1530?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand) (88ea8a0) into [develop](https://app.codecov.io/gh/algorand/indexer/commit/668eb053fed553eaeea879ae7ae3d2cccea197e2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand) (668eb05) will **decrease** coverage by `0.19%`.
> The diff coverage is `93.87%`.

```diff
@@             Coverage Diff             @@
##           develop    #1530      +/-   ##
===========================================
- Coverage    70.35%   70.17%   -0.19%     
===========================================
  Files           40       40              
  Lines         8136     8107      -29     
===========================================
- Hits          5724     5689      -35     
- Misses        1982     1986       +4     
- Partials       430      432       +2     
```


| [Impacted Files](https://app.codecov.io/gh/algorand/indexer/pull/1530?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand) | Coverage Δ | |
|---|---|---|
| [idb/postgres/internal/encoding/types.go](https://app.codecov.io/gh/algorand/indexer/pull/1530?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand#diff-aWRiL3Bvc3RncmVzL2ludGVybmFsL2VuY29kaW5nL3R5cGVzLmdv) | `66.66% <ø> (ø)` | |
| [idb/postgres/internal/encoding/encoding.go](https://app.codecov.io/gh/algorand/indexer/pull/1530?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand#diff-aWRiL3Bvc3RncmVzL2ludGVybmFsL2VuY29kaW5nL2VuY29kaW5nLmdv) | `88.55% <93.87%> (-1.20%)` | :arrow_down: |

... and [1 file with indirect coverage changes](https://app.codecov.io/gh/algorand/indexer/pull/1530/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=algorand)

: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 e874a70..a571f2f 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -46,7 +46,7 @@ jobs:
       go_version:
         type: string
     environment:
-      CI_E2E_FILENAME: "fa6ad40d/rel-nightly"
+      CI_E2E_FILENAME: "f99e7b0c/rel-nightly"
     steps:
       - go/install:
           version: << parameters.go_version >>
@@ -54,8 +54,9 @@ jobs:
       - install_linter
       - run_tests
       # Change this to run_e2e_tests once we have stable algod binaries containing delta APIs
-      # - run_e2e_tests_nightly
+      - run_e2e_tests_nightly
       - codecov/upload
+
   test_nightly:
     machine:
       image: << pipeline.parameters.ubuntu_image >>
@@ -133,6 +134,7 @@ commands:
           command: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.47.3
 
   run_e2e_tests:
+    # no "-nightly" in final 2 steps
     steps:
       - run:
           name: Install go-algorand stable binaries
@@ -144,6 +146,7 @@ commands:
       - run: make e2e-filter-test
 
   run_e2e_tests_nightly:
+    # "-nightly" suffix in final 2 steps
     steps:
       - run:
           name: Install go-algorand nightly binaries
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..966aa2c
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,128 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+  and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+  overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+  advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+  address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+conduct@algorand.com.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior,  harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/api/README.md b/api/README.md
index 5a821fd..3e2f2f2 100644
--- a/api/README.md
+++ b/api/README.md
@@ -9,27 +9,32 @@ The API is defined using [OpenAPI v2](https://swagger.io/specification/v2/) in *
 The Makefile will install our fork of **oapi-codegen**, use `make oapi-codegen` to install it directly.
 
 1. Document your changes by editing **indexer.oas2.yml**
-2. Regenerate the endpoints by running `make generate`. The sources at **generated/** will be updated.
+2. Regenerate the endpoints by running **generate.sh**. The sources at **generated/** will be updated.
 3. Update the implementation in **handlers.go**. It is sometimes useful to consult **generated/routes.go** to make sure the handler properly implements **ServerInterface**.
 
 ## What codegen tool is used?
 
-We found that [oapi-codegen](https://github.com/deepmap/oapi-codegen) produced the cleanest code, and had an easy to work with codebase. There is an algorand fork of this project which contains a couple modifications that were needed to properly support our needs.
+We found that [oapi-codegen](https://github.com/deepmap/oapi-codegen) produced the cleanest code, and had an easy to work with codebase. 
+There is an algorand fork of this project which contains a couple modifications that were needed to properly support our needs.
 
 Specifically, `uint64` types aren't strictly supported by OpenAPI. So we added a type-mapping feature to oapi-codegen.
 
 ## Why do we have indexer.oas2.yml and indexer.oas3.yml?
 
-We chose to maintain V2 and V3 versions of the spec because OpenAPI v3 doesn't seem to be widely supported. Some tools worked better with V3 and others with V2, so having both available has been useful. To reduce developer burdon, the v2 specfile is automatically converted v3 using [converter.swagger.io](http://converter.swagger.io/).
+We chose to maintain V2 and V3 versions of the spec because OpenAPI v3 doesn't seem to be widely supported. Some tools worked better with V3 and others with V2, so having both available has been useful.
+To reduce developer burdon, the v2 specfile is automatically converted v3 using [converter.swagger.io](http://converter.swagger.io/).
 
-# Fixtures Test
-## What is a **Fixtures Test**?
+## Fixtures Test
 
-Currently (September 2022) [fixtures_test.go](./fixtures_test.go) is a library that allows testing Indexer's router to verify that endpoints accept parameters and respond as expected, and guard against future regressions. [app_boxes_fixtures_test.go](./app_boxes_fixtures_test.go) is an example _fixtures test_ and is the _creator_ of the fixture [boxes.json](./test_resources/boxes.json).
+### What is a **Fixtures Test**?
+
+Currently (September 2022) [fixtures_test.go](./fixtures_test.go) is a library that allows testing Indexer's router to verify that endpoints accept parameters and respond as expected,
+and guard against future regressions. [app_boxes_fixtures_test.go](./app_boxes_fixtures_test.go) is an example _fixtures test_ and is the _creator_ of the fixture [boxes.json](./test_resources/boxes.json).
 
 A fixtures test
 
-1. is defined by a go-slice called a _Seed Fixture_  e.g. [var boxSeedFixture](https://github.com/algorand/indexer/blob/b5025ad640fabac0d778b4cac60d558a698ed560/api/app_boxes_fixtures_test.go#L302-L692) which contains request information for making HTTP requests against an Indexer server
+1. is defined by a go-slice called a _Seed Fixture_  e.g. [var boxSeedFixture](https://github.com/algorand/indexer/blob/b5025ad640fabac0d778b4cac60d558a698ed560/api/app_boxes_fixtures_test.go#L302-L692)
+which contains request information for making HTTP requests against an Indexer server
 2. iterates through the slice, making each of the defined requests and generating a _Live Fixture_
 3. reads a _Saved Fixture_ from a json file e.g. [boxes.json](./test_resources/boxes.json)
 4. persists the _Live Fixture_ to a json file not in source control
@@ -37,27 +42,35 @@ A fixtures test
 
 In reality, because we always want to save the _Live Fixture_ before making assertions that could fail the test and pre-empt saving, steps (3) and (4) happen in the opposite order.
 
-## What's the purpose of a Fixtures Test?
+### What's the purpose of a Fixtures Test?
+
+A fixtures test should allow one to quickly stand up an end-to-end test to validate that Indexer endpoints are working as expected. After Indexer's state is programmatically set up, 
+it's easy to add new requests and verify that the responses look exactly as expected. Once you're satisfied that the responses are correct, it's easy to _freeze_ the test and guard against future regressions.
 
-A fixtures test should allow one to quickly stand up an end-to-end test to validate that Indexer endpoints are working as expected. After Indexer's state is programmatically set up, it's easy to add new requests and verify that the responses look exactly as expected. Once you're satisfied that the responses are correct, it's easy to _freeze_ the test and guard against future regressions.
-## What does a **Fixtures Test Function** Look Like?
+### What does a **Fixtures Test Function** Look Like?
 
 [func TestBoxes](https://github.com/algorand/indexer/blob/b5025ad640fabac0d778b4cac60d558a698ed560/api/app_boxes_fixtures_test.go#L694_L704) shows the basic structure of a fixtures test.
 
 1. `setupIdbAndReturnShutdownFunc()` is called to set up the Indexer database
-  * this isn't expected to require modification
+
+   * this isn't expected to require modification
+
 2. `setupLiveBoxes()` is used to prepare the local ledger and process blocks in order to bring Indexer into a particular state
-  * this will always depend on what the test is trying to achieve
-  * in this case, an app was used to create and modify a set of boxes which are then queried against
-  * it is conceivable that instead of bringing Indexer into a particular state, the responses from the DB or even the handler may be mocked, so we could have had `setupLiveBoxesMocker()` instead of `setupLiveBoxes()`
+   * this will always depend on what the test is trying to achieve
+   * in this case, an app was used to create and modify a set of boxes which are then queried against
+   * it is conceivable that instead of bringing Indexer into a particular state, the responses from the DB or even the handler may be mocked, so we could have had `setupLiveBoxesMocker()` instead of `setupLiveBoxes()`
+
 3. `setupLiveServerAndReturnShutdownFunc()` is used to bring up an instance of a real Indexer.
-  * this shouldn't need to be modified; however, if running in parallel and making assertions that conflict with other tests, you may need to localize the variable `fixtestListenAddr` and run on a separate port
-  * if running a mock server instead, a different setup function would be needed
-4. `validateLiveVsSaved()` runs steps (1) through (5) defined in the previous section
-  * this is designed to be generic and ought not require much modification going forward
 
+   * this shouldn't need to be modified; however, if running in parallel and making assertions that conflict with other tests,
+   you may need to localize the variable `fixtestListenAddr` and run on a separate port
+   * if running a mock server instead, a different setup function would be needed
+
+4. `validateLiveVsSaved()` runs steps (1) through (5) defined in the previous section
+  
+   * this is designed to be generic and ought not require much modification going forward
 
-## Which Endpoints are Currently _Testable_ in a Fixtures Test?
+### Which Endpoints are Currently _Testable_ in a Fixtures Test?
 
 Endpoints defined in [proverRoutes](https://github.com/algorand/indexer/blob/b955a31b10d8dce7177383895ed8e57206d69f67/api/fixtures_test.go#L232-L263) are testable.
 
@@ -69,11 +82,11 @@ Currently (September 2022) these are:
 * `/v2/applications/:application-id/box`
 * `/v2/applications/:application-id/boxes`
 
-## How to Introduce a New Fixtures Test for an _Already Testable_ Endpoint?
+### How to Introduce a New Fixtures Test for an _Already Testable_ Endpoint?
 
 To set up a new test for endpoints defined above one needs to:
 
-### 1. Define a new _Seed Fixture_
+#### 1. Define a new _Seed Fixture_
 
 For example, consider
 
@@ -95,30 +108,48 @@ var boxSeedFixture = fixture{
 ```
 
 A seed fixture is a `struct` with fields
+
 * `File` (_required_) - the name in [test_resources](./test_resources/) where the fixture is read from (and written to with an `_` prefix)
 * `Owner` (_recommended_) - a name to define which test "owns" the seed
 * `Frozen` (_required_) - set _true_ when you need to run assertions of the _Live Fixture_ vs. the _Saved Fixture_. For tests to pass, it needs to be set _true_.
 * `Cases` - the slice of `testCase`s. Each of these has the fields:
-  *  `Name` (_required_) - an identifier for the test case
+
+  * `Name` (_required_) - an identifier for the test case
   * `Request` (_required_) - a `requestInfo` struct specifying:
     * `Path` (_required_) - the path to be queried
     * `Params` (_required but may be empty_) - the slice of parameters (strings `name` and `value`) to be appended to the path
-### 2. Define a new _Indexer State_ Setup Function
+
+#### 2. Define a new _Indexer State_ Setup Function
 
 There are many examples of setting up state that can be emulated. For example:
+
 * [setupLiveBoxes()](https://github.com/algorand/indexer/blob/b5025ad640fabac0d778b4cac60d558a698ed560/api/app_boxes_fixtures_test.go#L43) for application boxes
 * [TestApplicationHandlers()](https://github.com/algorand/indexer/blob/3a9095c2b5ee25093708f980445611a03f2cf4e2/api/handlers_e2e_test.go#L93) for applications
-* [TestBlockWithTransactions()](https://github.com/algorand/indexer/blob/800cb135a0c6da0109e7282acf85cbe1961930c6/idb/postgres/postgres_integration_test.go#L339) setup state consisting of a set of basic transactions
+* [TestBlockWithTransactions()](https://github.com/algorand/indexer/blob/800cb135a0c6da0109e7282acf85cbe1961930c6/idb/postgres/postgres_integration_test.go#L339)
+setup state consisting of a set of basic transactions
 
-## How to Make a _New Endpoint_ Testable by Fixtures Tests?
+### How to Make a _New Endpoint_ Testable by Fixtures Tests?
 
 There are 2 steps:
 
-1. Implement a new function _witness generator_ aka [prover function](https://github.com/algorand/indexer/blob/b955a31b10d8dce7177383895ed8e57206d69f67/api/fixtures_test.go#L103) of type `func(responseInfo) (interface{}, *string)` as examplified in [this section](https://github.com/algorand/indexer/blob/b955a31b10d8dce7177383895ed8e57206d69f67/api/fixtures_test.go#L107-L200). Such a function is supposed to parse an Indexer response's body into a generated model. Currently, all provers are boilerplate, and with generics, it's expected that this step will no longer be necessary (this [POC](https://github.com/tzaffi/indexer/blob/generic-boxes/api/fixtures_test.go#L119-L155) shows how it would be done with generics).
-2. Define a new route in the [proverRoutes struct](https://github.com/algorand/indexer/blob/b955a31b10d8dce7177383895ed8e57206d69f67/api/fixtures_test.go#L232_L263). This is a tree structure which is traversed by splitting a path using `/` and eventually reaching a leaf which consists of a `prover` as defined in #1. 
+1. Implement a new function _witness generator_ aka [prover function](https://github.com/algorand/indexer/blob/b955a31b10d8dce7177383895ed8e57206d69f67/api/fixtures_test.go#L103) of
+type `func(responseInfo) (interface{}, *string)` as examplified in [this section](https://github.com/algorand/indexer/blob/b955a31b10d8dce7177383895ed8e57206d69f67/api/fixtures_test.go#L107-L200).
+Such a function is supposed to parse an Indexer response's body into a generated model. Currently, all provers are boilerplate, and with generics, it's expected that this step will no longer be necessary
+(this [POC](https://github.com/tzaffi/indexer/blob/generic-boxes/api/fixtures_test.go#L119-L155) shows how it would be done with generics).
+2. Define a new route in the [proverRoutes struct](https://github.com/algorand/indexer/blob/b955a31b10d8dce7177383895ed8e57206d69f67/api/fixtures_test.go#L232_L263).
+This is a tree structure which is traversed by splitting a path using `/` and eventually reaching a leaf which consists of a `prover` as defined in #1. 
 
 For example, to enable the endpoint `GET /v2/applications/{application-id}/logs` for fixtures test, one need only define a `logsProof` witness generator and have it mapped in `proverRoutes` under:
 
-```
+```go
 proverRoutes.parts["v2"].parts["applications"].parts[":application-id"].parts["logs"] = logsProof
 ```
+
+### How to Fix a Fixtures Test?
+
+Supposing that there was a breaking change upstream, and a fixtures test is now failing. The following approach should work most of the time:
+
+1. Run the broken test generating a temporary fixture file in the `fixturesDirectory` (currently [test_resources](./test_resources/)) with a name the same as the json fixture except begining with `_`
+(e.g. `_boxes.json` vs. `boxes.json`).
+2. Observe the diff between the temporary fixture and the saved fixture. If the diff is acceptable, then simply copy the temporary fixture over the saved fixture.
+3. If the diff isn't acceptable, then make any necessary changes to the setup and seed and repeat steps 1 and 2.
diff --git a/cmd/validator/core/command.go b/cmd/validator/core/command.go
index 70d4041..17c9e6a 100644
--- a/cmd/validator/core/command.go
+++ b/cmd/validator/core/command.go
@@ -113,7 +113,7 @@ func run(config Params, errorLogFile, addr string, box string, threads int, proc
 	}
 }
 
-// start kicks off a bunch of  go routines to compare addresses, it also creates a work channel to feed the workers and
+// start kicks off a bunch of go routines to compare addresses, it also creates a work channel to feed the workers and
 // fills the work channel by reading from os.Stdin. Results are returned to the results channel.
 func start(processorID ProcessorID, threads int, config Params, results chan<- Result) {
 	work := make(chan string, 100*threads)
diff --git a/docs/PostgresqlIndexes.md b/docs/PostgresqlIndexes.md
index 2089498..c52d9fd 100644
--- a/docs/PostgresqlIndexes.md
+++ b/docs/PostgresqlIndexes.md
@@ -1,4 +1,4 @@
-# PostgeSQL Custom Indexes
+# PostgreSQL Custom Indexes
 
 Indexer ships with a minimal index set in order to process blocks, and return transactions for accounts. More advanced queries and filters require customization of the indexes.
 
diff --git a/go.mod b/go.mod
index 92ab0ae..bdeea9f 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.17
 
 require (
 	github.com/algorand/avm-abi v0.2.0
-	github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230228201805-5b8c99b1412c
+	github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230526160341-74a095c3f9e3
 	github.com/algorand/go-codec/codec v1.1.8
 	github.com/algorand/oapi-codegen v1.12.0-algorand.0
 	github.com/davecgh/go-spew v1.1.1
diff --git a/go.sum b/go.sum
index 9b8f405..2bcd8db 100644
--- a/go.sum
+++ b/go.sum
@@ -84,8 +84,8 @@ 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/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-20230526160341-74a095c3f9e3 h1:HVso8HOozyMMd9EQC0icfLDM7Z+5UCrX5wl1oCXjzng=
+github.com/algorand/go-algorand-sdk/v2 v2.0.0-20230526160341-74a095c3f9e3/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=
diff --git a/idb/postgres/internal/encoding/encoding.go b/idb/postgres/internal/encoding/encoding.go
index 7614da5..507400e 100644
--- a/idb/postgres/internal/encoding/encoding.go
+++ b/idb/postgres/internal/encoding/encoding.go
@@ -50,20 +50,57 @@ func decodeBase64(data string) ([]byte, error) {
 	return base64.StdEncoding.DecodeString(data)
 }
 
+// MarshalText returns the address string as an array of bytes
+func (addr *AlgodEncodedAddress) MarshalText() ([]byte, error) {
+	var a sdk.Address
+	copy(a[:], addr[:])
+	return []byte(a.String()), nil
+}
+
+// UnmarshalText initializes the Address from an array of bytes.
+// The bytes may be in the base32 checksum format, or the raw bytes base64 encoded.
+func (addr *AlgodEncodedAddress) UnmarshalText(text []byte) error {
+	var a sdk.Address
+	err := a.UnmarshalText(text)
+	if err != nil {
+		return err
+	}
+	copy(addr[:], a[:])
+	return nil
+}
+
+func convertExpiredAccounts(accounts []sdk.Address) []AlgodEncodedAddress {
+	if len(accounts) == 0 {
+		return nil
+	}
+	res := make([]AlgodEncodedAddress, len(accounts))
+	for i, addr := range accounts {
+		res[i] = AlgodEncodedAddress(addr)
+	}
+	return res
+}
+
+func unconvertExpiredAccounts(accounts []AlgodEncodedAddress) []sdk.Address {
+	if len(accounts) == 0 {
+		return nil
+	}
+	res := make([]sdk.Address, len(accounts))
+	for i, addr := range accounts {
+		res[i] = sdk.Address(addr)
+	}
+	return res
+}
+
 func convertBlockHeader(header sdk.BlockHeader) blockHeader {
 	return blockHeader{
-		BlockHeader:         header,
-		BranchOverride:      sdk.Digest(header.Branch),
-		FeeSinkOverride:     sdk.Digest(header.FeeSink),
-		RewardsPoolOverride: sdk.Digest(header.RewardsPool),
+		BlockHeader:                          header,
+		ExpiredParticipationAccountsOverride: convertExpiredAccounts(header.ExpiredParticipationAccounts),
 	}
 }
 
 func unconvertBlockHeader(header blockHeader) sdk.BlockHeader {
 	res := header.BlockHeader
-	res.Branch = sdk.BlockHash(header.BranchOverride)
-	res.FeeSink = sdk.Address(header.FeeSinkOverride)
-	res.RewardsPool = sdk.Address(header.RewardsPoolOverride)
+	res.ExpiredParticipationAccounts = unconvertExpiredAccounts(header.ExpiredParticipationAccountsOverride)
 	return res
 }
 
@@ -85,14 +122,10 @@ func DecodeBlockHeader(data []byte) (sdk.BlockHeader, error) {
 
 func convertAssetParams(params sdk.AssetParams) assetParams {
 	ret := assetParams{
-		AssetParams:      params,
-		ManagerOverride:  sdk.Digest(params.Manager),
-		ReserveOverride:  sdk.Digest(params.Reserve),
-		FreezeOverride:   sdk.Digest(params.Freeze),
-		ClawbackOverride: sdk.Digest(params.Clawback),
-		AssetNameBytes:   []byte(params.AssetName),
-		UnitNameBytes:    []byte(params.UnitName),
-		URLBytes:         []byte(params.URL),
+		AssetParams:    params,
+		AssetNameBytes: []byte(params.AssetName),
+		UnitNameBytes:  []byte(params.UnitName),
+		URLBytes:       []byte(params.URL),
 	}
 
 	ret.AssetName = util.PrintableUTF8OrEmpty(params.AssetName)
@@ -125,10 +158,6 @@ func unconvertAssetParams(params assetParams) sdk.AssetParams {
 	if len(res.URL) == 0 {
 		res.URL = string(params.URLBytes)
 	}
-	res.Manager = sdk.Address(params.ManagerOverride)
-	res.Reserve = sdk.Address(params.ReserveOverride)
-	res.Freeze = sdk.Address(params.FreezeOverride)
-	res.Clawback = sdk.Address(params.ClawbackOverride)
 	return res
 }
 
@@ -148,58 +177,16 @@ func DecodeAssetParams(data []byte) (sdk.AssetParams, error) {
 	return unconvertAssetParams(params), nil
 }
 
-func convertAccounts(accounts []sdk.Address) []sdk.Digest {
-	if accounts == nil {
-		return nil
-	}
-
-	res := make([]sdk.Digest, 0, len(accounts))
-	for _, address := range accounts {
-		res = append(res, sdk.Digest(address))
-	}
-	return res
-}
-
-func unconvertAccounts(accounts []sdk.Digest) []sdk.Address {
-	if accounts == nil {
-		return nil
-	}
-
-	res := make([]sdk.Address, 0, len(accounts))
-	for _, address := range accounts {
-		res = append(res, sdk.Address(address))
-	}
-	return res
-}
-
 func convertTransaction(txn sdk.Transaction) transaction {
 	return transaction{
-		Transaction:              txn,
-		SenderOverride:           sdk.Digest(txn.Sender),
-		RekeyToOverride:          sdk.Digest(txn.RekeyTo),
-		ReceiverOverride:         sdk.Digest(txn.Receiver),
-		AssetParamsOverride:      convertAssetParams(txn.AssetParams),
-		CloseRemainderToOverride: sdk.Digest(txn.CloseRemainderTo),
-		AssetSenderOverride:      sdk.Digest(txn.AssetSender),
-		AssetReceiverOverride:    sdk.Digest(txn.AssetReceiver),
-		AssetCloseToOverride:     sdk.Digest(txn.AssetCloseTo),
-		FreezeAccountOverride:    sdk.Digest(txn.FreezeAccount),
-		AccountsOverride:         convertAccounts(txn.Accounts),
+		Transaction:         txn,
+		AssetParamsOverride: convertAssetParams(txn.AssetParams),
 	}
 }
 
 func unconvertTransaction(txn transaction) sdk.Transaction {
 	res := txn.Transaction
-	res.Sender = sdk.Address(txn.SenderOverride)
-	res.RekeyTo = sdk.Address(txn.RekeyToOverride)
-	res.Receiver = sdk.Address(txn.ReceiverOverride)
-	res.CloseRemainderTo = sdk.Address(txn.CloseRemainderToOverride)
 	res.AssetParams = unconvertAssetParams(txn.AssetParamsOverride)
-	res.AssetSender = sdk.Address(txn.AssetSenderOverride)
-	res.AssetReceiver = sdk.Address(txn.AssetReceiverOverride)
-	res.AssetCloseTo = sdk.Address(txn.AssetCloseToOverride)
-	res.FreezeAccount = sdk.Address(txn.FreezeAccountOverride)
-	res.Accounts = unconvertAccounts(txn.AccountsOverride)
 	return res
 }
 
@@ -333,9 +320,9 @@ func unconvertEvalDelta(delta evalDelta) sdk.EvalDelta {
 
 func convertSignedTxnWithAD(stxn sdk.SignedTxnWithAD) signedTxnWithAD {
 	return signedTxnWithAD{
-		SignedTxnWithAD:   stxn,
-		TxnOverride:       convertTransaction(stxn.Txn),
-		AuthAddrOverride:  sdk.Digest(stxn.AuthAddr),
+		SignedTxnWithAD: stxn,
+		TxnOverride:     convertTransaction(stxn.Txn),
+		//AuthAddrOverride:  sdk.Digest(stxn.AuthAddr),
 		EvalDeltaOverride: convertEvalDelta(stxn.EvalDelta),
 	}
 }
@@ -343,7 +330,7 @@ func convertSignedTxnWithAD(stxn sdk.SignedTxnWithAD) signedTxnWithAD {
 func unconvertSignedTxnWithAD(stxn signedTxnWithAD) sdk.SignedTxnWithAD {
 	res := stxn.SignedTxnWithAD
 	res.Txn = unconvertTransaction(stxn.TxnOverride)
-	res.AuthAddr = sdk.Address(stxn.AuthAddrOverride)
+	res.AuthAddr = stxn.AuthAddr
 	res.EvalDelta = unconvertEvalDelta(stxn.EvalDeltaOverride)
 	return res
 }
@@ -371,7 +358,7 @@ func unconvertTrimmedAccountData(ad trimmedAccountData) sdk.AccountData {
 			MicroAlgos:          sdk.MicroAlgos(ad.MicroAlgos),
 			RewardsBase:         ad.RewardsBase,
 			RewardedMicroAlgos:  sdk.MicroAlgos(ad.RewardedMicroAlgos),
-			AuthAddr:            sdk.Address(ad.AuthAddr),
+			AuthAddr:            ad.AuthAddr,
 			TotalAppSchema:      ad.TotalAppSchema,
 			TotalExtraAppPages:  ad.TotalExtraAppPages,
 			TotalAppParams:      ad.TotalAppParams,
@@ -568,35 +555,20 @@ func DecodeAppLocalStateArray(data []byte) ([]sdk.AppLocalState, error) {
 
 	return unconvertAppLocalStateArray(array), nil
 }
-func convertSpecialAddresses(special itypes.SpecialAddresses) specialAddresses {
-	return specialAddresses{
-		SpecialAddresses:    special,
-		FeeSinkOverride:     sdk.Digest(special.FeeSink),
-		RewardsPoolOverride: sdk.Digest(special.RewardsPool),
-	}
-}
-
-func unconvertSpecialAddresses(special specialAddresses) itypes.SpecialAddresses {
-	res := special.SpecialAddresses
-	res.FeeSink = sdk.Address(special.FeeSinkOverride)
-	res.RewardsPool = sdk.Address(special.RewardsPoolOverride)
-	return res
-}
 
 // EncodeSpecialAddresses encodes special addresses (sink and rewards pool) into json.
 func EncodeSpecialAddresses(special itypes.SpecialAddresses) []byte {
-	return encodeJSON(convertSpecialAddresses(special))
+	return encodeJSON(special)
 }
 
 // DecodeSpecialAddresses decodes special addresses (sink and rewards pool) from json.
 func DecodeSpecialAddresses(data []byte) (itypes.SpecialAddresses, error) {
-	var special specialAddresses
+	var special itypes.SpecialAddresses
 	err := DecodeJSON(data, &special)
 	if err != nil {
 		return itypes.SpecialAddresses{}, err
 	}
-
-	return unconvertSpecialAddresses(special), nil
+	return special, nil
 }
 
 // EncodeTxnExtra encodes transaction extra info into json.
@@ -675,7 +647,7 @@ func TrimLcAccountData(ad sdk.AccountData) sdk.AccountData {
 func convertTrimmedLcAccountData(ad sdk.AccountData) baseAccountData {
 	return baseAccountData{
 		Status:              ad.Status,
-		AuthAddr:            sdk.Digest(ad.AuthAddr),
+		AuthAddr:            ad.AuthAddr,
 		TotalAppSchema:      ad.TotalAppSchema,
 		TotalExtraAppPages:  ad.TotalExtraAppPages,
 		TotalAssetParams:    ad.TotalAssetParams,
@@ -699,7 +671,7 @@ func unconvertTrimmedLcAccountData(ba baseAccountData) sdk.AccountData {
 	return sdk.AccountData{
 		AccountBaseData: sdk.AccountBaseData{
 			Status:              ba.Status,
-			AuthAddr:            sdk.Address(ba.AuthAddr),
+			AuthAddr:            ba.AuthAddr,
 			TotalAppSchema:      ba.TotalAppSchema,
 			TotalExtraAppPages:  ba.TotalExtraAppPages,
 			TotalAppParams:      ba.TotalAppParams,
diff --git a/idb/postgres/internal/encoding/types.go b/idb/postgres/internal/encoding/types.go
index 2d4575a..00b403b 100644
--- a/idb/postgres/internal/encoding/types.go
+++ b/idb/postgres/internal/encoding/types.go
@@ -1,41 +1,27 @@
 package encoding
 
 import (
-	"github.com/algorand/indexer/types"
-
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
 
+// AlgodEncodedAddress is an address encoded in the format used by algod.
+type AlgodEncodedAddress sdk.Address
+
 type blockHeader struct {
 	sdk.BlockHeader
-	BranchOverride      sdk.Digest `codec:"prev"`
-	FeeSinkOverride     sdk.Digest `codec:"fees"`
-	RewardsPoolOverride sdk.Digest `codec:"rwd"`
+	ExpiredParticipationAccountsOverride []AlgodEncodedAddress `codec:"partupdrmv"`
 }
 
 type assetParams struct {
 	sdk.AssetParams
-	UnitNameBytes    []byte     `codec:"un64"`
-	AssetNameBytes   []byte     `codec:"an64"`
-	URLBytes         []byte     `codec:"au64"`
-	ManagerOverride  sdk.Digest `codec:"m"`
-	ReserveOverride  sdk.Digest `codec:"r"`
-	FreezeOverride   sdk.Digest `codec:"f"`
-	ClawbackOverride sdk.Digest `codec:"c"`
+	UnitNameBytes  []byte `codec:"un64"`
+	AssetNameBytes []byte `codec:"an64"`
+	URLBytes       []byte `codec:"au64"`
 }
 
 type transaction struct {
 	sdk.Transaction
-	SenderOverride           sdk.Digest   `codec:"snd"`
-	RekeyToOverride          sdk.Digest   `codec:"rekey"`
-	ReceiverOverride         sdk.Digest   `codec:"rcv"`
-	CloseRemainderToOverride sdk.Digest   `codec:"close"`
-	AssetParamsOverride      assetParams  `codec:"apar"`
-	AssetSenderOverride      sdk.Digest   `codec:"asnd"`
-	AssetReceiverOverride    sdk.Digest   `codec:"arcv"`
-	AssetCloseToOverride     sdk.Digest   `codec:"aclose"`
-	FreezeAccountOverride    sdk.Digest   `codec:"fadd"`
-	AccountsOverride         []sdk.Digest `codec:"apat"`
+	AssetParamsOverride assetParams `codec:"apar"`
 }
 
 type valueDelta struct {
@@ -74,16 +60,14 @@ type evalDelta struct {
 type signedTxnWithAD struct {
 	sdk.SignedTxnWithAD
 	TxnOverride       transaction `codec:"txn"`
-	AuthAddrOverride  sdk.Digest  `codec:"sgnr"`
 	EvalDeltaOverride evalDelta   `codec:"dt"`
 }
 
 type trimmedAccountData struct {
 	baseAccountData
-	AuthAddrOverride   sdk.Digest `codec:"spend"`
-	MicroAlgos         uint64     `codec:"algo"`
-	RewardsBase        uint64     `codec:"ebase"`
-	RewardedMicroAlgos uint64     `codec:"ern"`
+	MicroAlgos         uint64 `codec:"algo"`
+	RewardsBase        uint64 `codec:"ebase"`
+	RewardedMicroAlgos uint64 `codec:"ern"`
 }
 
 type tealValue struct {
@@ -103,12 +87,6 @@ type appParams struct {
 	GlobalStateOverride tealKeyValue `codec:"gs"`
 }
 
-type specialAddresses struct {
-	types.SpecialAddresses
-	FeeSinkOverride     sdk.Digest `codec:"FeeSink"`
-	RewardsPoolOverride sdk.Digest `codec:"RewardsPool"`
-}
-
 type baseOnlineAccountData struct {
 	_struct struct{} `codec:",omitempty,omitemptyarray"`
 
@@ -124,7 +102,7 @@ type baseAccountData struct {
 	_struct struct{} `codec:",omitempty,omitemptyarray"`
 
 	Status              sdk.Status      `codec:"onl"`
-	AuthAddr            sdk.Digest      `codec:"spend"`
+	AuthAddr            sdk.Address     `codec:"spend"`
 	TotalAppSchema      sdk.StateSchema `codec:"tsch"`
 	TotalExtraAppPages  uint32          `codec:"teap"`
 	TotalAssetParams    uint64          `codec:"tasp"`
diff --git a/idb/postgres/postgres.go b/idb/postgres/postgres.go
index d09f05a..e0161b7 100644
--- a/idb/postgres/postgres.go
+++ b/idb/postgres/postgres.go
@@ -29,11 +29,11 @@ import (
 	"github.com/algorand/indexer/idb/postgres/internal/types"
 	pgutil "github.com/algorand/indexer/idb/postgres/internal/util"
 	"github.com/algorand/indexer/idb/postgres/internal/writer"
-	"github.com/algorand/indexer/protocol"
-	"github.com/algorand/indexer/protocol/config"
 	itypes "github.com/algorand/indexer/types"
 	"github.com/algorand/indexer/util"
 
+	"github.com/algorand/go-algorand-sdk/v2/protocol"
+	"github.com/algorand/go-algorand-sdk/v2/protocol/config"
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
 
diff --git a/protocol/config/config.go b/protocol/config/config.go
deleted file mode 100644
index bf50247..0000000
--- a/protocol/config/config.go
+++ /dev/null
@@ -1,1244 +0,0 @@
-// Copyright (C) 2019-2022 Algorand, Inc.
-// This file is part of go-algorand
-//
-// go-algorand is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// go-algorand is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with go-algorand.  If not, see <https://www.gnu.org/licenses/>.
-
-package config
-
-import (
-	"time"
-
-	"github.com/algorand/indexer/protocol"
-)
-
-// ConsensusParams specifies settings that might vary based on the
-// particular version of the consensus protocol.
-type ConsensusParams struct {
-	// Consensus protocol upgrades.  Votes for upgrades are collected for
-	// UpgradeVoteRounds.  If the number of positive votes is over
-	// UpgradeThreshold, the proposal is accepted.
-	//
-	// UpgradeVoteRounds needs to be long enough to collect an
-	// accurate sample of participants, and UpgradeThreshold needs
-	// to be high enough to ensure that there are sufficient participants
-	// after the upgrade.
-	//
-	// A consensus protocol upgrade may specify the delay between its
-	// acceptance and its execution.  This gives clients time to notify
-	// users.  This delay is specified by the upgrade proposer and must
-	// be between MinUpgradeWaitRounds and MaxUpgradeWaitRounds (inclusive)
-	// in the old protocol's parameters.  Note that these parameters refer
-	// to the representation of the delay in a block rather than the actual
-	// delay: if the specified delay is zero, it is equivalent to
-	// DefaultUpgradeWaitRounds.
-	//
-	// The maximum length of a consensus version string is
-	// MaxVersionStringLen.
-	UpgradeVoteRounds        uint64
-	UpgradeThreshold         uint64
-	DefaultUpgradeWaitRounds uint64
-	MinUpgradeWaitRounds     uint64
-	MaxUpgradeWaitRounds     uint64
-	MaxVersionStringLen      int
-
-	// MaxTxnBytesPerBlock determines the maximum number of bytes
-	// that transactions can take up in a block.  Specifically,
-	// the sum of the lengths of encodings of each transaction
-	// in a block must not exceed MaxTxnBytesPerBlock.
-	MaxTxnBytesPerBlock int
-
-	// MaxTxnBytesPerBlock is the maximum size of a transaction's Note field.
-	MaxTxnNoteBytes int
-
-	// MaxTxnLife is how long a transaction can be live for:
-	// the maximum difference between LastValid and FirstValid.
-	//
-	// Note that in a protocol upgrade, the ledger must first be upgraded
-	// to hold more past blocks for this value to be raised.
-	MaxTxnLife uint64
-
-	// ApprovedUpgrades describes the upgrade proposals that this protocol
-	// implementation will vote for, along with their delay value
-	// (in rounds).  A delay value of zero is the same as a delay of
-	// DefaultUpgradeWaitRounds.
-	ApprovedUpgrades map[protocol.ConsensusVersion]uint64
-
-	// SupportGenesisHash indicates support for the GenesisHash
-	// fields in transactions (and requires them in blocks).
-	SupportGenesisHash bool
-
-	// RequireGenesisHash indicates that GenesisHash must be present
-	// in every transaction.
-	RequireGenesisHash bool
-
-	// DefaultKeyDilution specifies the granularity of top-level ephemeral
-	// keys. KeyDilution is the number of second-level keys in each batch,
-	// signed by a top-level "batch" key.  The default value can be
-	// overridden in the account state.
-	DefaultKeyDilution uint64
-
-	// MinBalance specifies the minimum balance that can appear in
-	// an account.  To spend money below MinBalance requires issuing
-	// an account-closing transaction, which transfers all of the
-	// money from the account, and deletes the account state.
-	MinBalance uint64
-
-	// MinTxnFee specifies the minimum fee allowed on a transaction.
-	// A minimum fee is necessary to prevent DoS. In some sense this is
-	// a way of making the spender subsidize the cost of storing this transaction.
-	MinTxnFee uint64
-
-	// EnableFeePooling specifies that the sum of the fees in a
-	// group must exceed one MinTxnFee per Txn, rather than check that
-	// each Txn has a MinFee.
-	EnableFeePooling bool
-
-	// EnableAppCostPooling specifies that the sum of fees for application calls
-	// in a group is checked against the sum of the budget for application calls,
-	// rather than check each individual app call is within the budget.
-	EnableAppCostPooling bool
-
-	// RewardUnit specifies the number of MicroAlgos corresponding to one reward
-	// unit.
-	//
-	// Rewards are received by whole reward units.  Fractions of
-	// RewardUnits do not receive rewards.
-	//
-	// Ensure both considerations below  are taken into account if RewardUnit is planned for change:
-	// 1. RewardUnits should not be changed without touching all accounts to apply their rewards
-	// based on the old RewardUnits and then use the new RewardUnits for all subsequent calculations.
-	// 2. Having a consistent RewardUnit is also important for preserving
-	// a constant amount of total algos in the system:
-	// the block header tracks how many reward units worth of algos are in existence
-	// and have logically received rewards.
-	RewardUnit uint64
-
-	// RewardsRateRefreshInterval is the number of rounds after which the
-	// rewards level is recomputed for the next RewardsRateRefreshInterval rounds.
-	RewardsRateRefreshInterval uint64
-
-	// seed-related parameters
-	SeedLookback        uint64 // how many blocks back we use seeds from in sortition. delta_s in the spec
-	SeedRefreshInterval uint64 // how often an old block hash is mixed into the seed. delta_r in the spec
-
-	// ledger retention policy
-	MaxBalLookback uint64 // (current round - MaxBalLookback) is the oldest round the ledger must answer balance queries for
-
-	// sortition threshold factors
-	NumProposers           uint64
-	SoftCommitteeSize      uint64
-	SoftCommitteeThreshold uint64
-	CertCommitteeSize      uint64
-	CertCommitteeThreshold uint64
-	NextCommitteeSize      uint64 // for any non-FPR votes >= deadline step, committee sizes and thresholds are constant
-	NextCommitteeThreshold uint64
-	LateCommitteeSize      uint64
-	LateCommitteeThreshold uint64
-	RedoCommitteeSize      uint64
-	RedoCommitteeThreshold uint64
-	DownCommitteeSize      uint64
-	DownCommitteeThreshold uint64
-
-	// time for nodes to wait for block proposal headers for period > 0, value should be set to 2 * SmallLambda
-	AgreementFilterTimeout time.Duration
-	// time for nodes to wait for block proposal headers for period = 0, value should be configured to suit best case
-	// critical path
-	AgreementFilterTimeoutPeriod0 time.Duration
-
-	FastRecoveryLambda time.Duration // time between fast recovery attempts
-
-	// how to commit to the payset: flat or merkle tree
-	PaysetCommit PaysetCommitType
-
-	MaxTimestampIncrement int64 // maximum time between timestamps on successive blocks
-
-	// support for the efficient encoding in SignedTxnInBlock
-	SupportSignedTxnInBlock bool
-
-	// force the FeeSink address to be non-participating in the genesis balances.
-	ForceNonParticipatingFeeSink bool
-
-	// support for ApplyData in SignedTxnInBlock
-	ApplyData bool
-
-	// track reward distributions in ApplyData
-	RewardsInApplyData bool
-
-	// domain-separated credentials
-	CredentialDomainSeparationEnabled bool
-
-	// support for transactions that mark an account non-participating
-	SupportBecomeNonParticipatingTransactions bool
-
-	// fix the rewards calculation by avoiding subtracting too much from the rewards pool
-	PendingResidueRewards bool
-
-	// asset support
-	Asset bool
-
-	// max number of assets per account
-	MaxAssetsPerAccount int
-
-	// max length of asset name
-	MaxAssetNameBytes int
-
-	// max length of asset unit name
-	MaxAssetUnitNameBytes int
-
-	// max length of asset url
-	MaxAssetURLBytes int
-
-	// support sequential transaction counter TxnCounter
-	TxnCounter bool
-
-	// transaction groups
-	SupportTxGroups bool
-
-	// max group size
-	MaxTxGroupSize int
-
-	// support for transaction leases
-	// note: if FixTransactionLeases is not set, the transaction
-	// leases supported are faulty; specifically, they do not
-	// enforce exclusion correctly when the FirstValid of
-	// transactions do not match.
-	SupportTransactionLeases bool
-	FixTransactionLeases     bool
-
-	// 0 for no support, otherwise highest version supported
-	LogicSigVersion uint64
-
-	// len(LogicSig.Logic) + len(LogicSig.Args[*]) must be less than this
-	LogicSigMaxSize uint64
-
-	// sum of estimated op cost must be less than this
-	LogicSigMaxCost uint64
-
-	// max decimal precision for assets
-	MaxAssetDecimals uint32
-
-	// SupportRekeying indicates support for account rekeying (the RekeyTo and AuthAddr fields)
-	SupportRekeying bool
-
-	// application support
-	Application bool
-
-	// max number of ApplicationArgs for an ApplicationCall transaction
-	MaxAppArgs int
-
-	// max sum([len(arg) for arg in txn.ApplicationArgs])
-	MaxAppTotalArgLen int
-
-	// maximum byte len of application approval program or clear state
-	// When MaxExtraAppProgramPages > 0, this is the size of those pages.
-	// So two "extra pages" would mean 3*MaxAppProgramLen bytes are available.
-	MaxAppProgramLen int
-
-	// maximum total length of an application's programs (approval + clear state)
-	// When MaxExtraAppProgramPages > 0, this is the size of those pages.
-	// So two "extra pages" would mean 3*MaxAppTotalProgramLen bytes are available.
-	MaxAppTotalProgramLen int
-
-	// extra length for application program in pages. A page is MaxAppProgramLen bytes
-	MaxExtraAppProgramPages int
-
-	// maximum number of accounts in the ApplicationCall Accounts field.
-	// this determines, in part, the maximum number of balance records
-	// accessed by a single transaction
-	MaxAppTxnAccounts int
-
-	// maximum number of app ids in the ApplicationCall ForeignApps field.
-	// these are the only applications besides the called application for
-	// which global state may be read in the transaction
-	MaxAppTxnForeignApps int
-
-	// maximum number of asset ids in the ApplicationCall ForeignAssets
-	// field. these are the only assets for which the asset parameters may
-	// be read in the transaction
-	MaxAppTxnForeignAssets int
-
-	// maximum number of "foreign references" (accounts, asa, app, boxes)
-	// that can be attached to a single app call.
-	MaxAppTotalTxnReferences int
-
-	// maximum cost of application approval program or clear state program
-	MaxAppProgramCost int
-
-	// maximum length of a key used in an application's global or local
-	// key/value store
-	MaxAppKeyLen int
-
-	// maximum length of a bytes value used in an application's global or
-	// local key/value store
-	MaxAppBytesValueLen int
-
-	// maximum sum of the lengths of the key and value of one app state entry
-	MaxAppSumKeyValueLens int
-
-	// maximum number of inner transactions that can be created by an app call.
-	// with EnableInnerTransactionPooling, limit is multiplied by MaxTxGroupSize
-	// and enforced over the whole group.
-	MaxInnerTransactions int
-
-	// should the number of inner transactions be pooled across group?
-	EnableInnerTransactionPooling bool
-
-	// provide greater isolation for clear state programs
-	IsolateClearState bool
-
-	// The minimum app version that can be called in an inner transaction
-	MinInnerApplVersion uint64
-
-	// maximum number of applications a single account can create and store
-	// AppParams for at once
-	MaxAppsCreated int
-
-	// maximum number of applications a single account can opt in to and
-	// store AppLocalState for at once
-	MaxAppsOptedIn int
-
-	// flat MinBalance requirement for creating a single application and
-	// storing its AppParams
-	AppFlatParamsMinBalance uint64
-
-	// flat MinBalance requirement for opting in to a single application
-	// and storing its AppLocalState
-	AppFlatOptInMinBalance uint64
-
-	// MinBalance requirement per key/value entry in LocalState or
-	// GlobalState key/value stores, regardless of value type
-	SchemaMinBalancePerEntry uint64
-
-	// MinBalance requirement (in addition to SchemaMinBalancePerEntry) for
-	// integer values stored in LocalState or GlobalState key/value stores
-	SchemaUintMinBalance uint64
-
-	// MinBalance requirement (in addition to SchemaMinBalancePerEntry) for
-	// []byte values stored in LocalState or GlobalState key/value stores
-	SchemaBytesMinBalance uint64
-
-	// Maximum length of a box (Does not include name/key length. That is capped by MaxAppKeyLen)
-	MaxBoxSize uint64
-
-	// Minimum Balance Requirement (MBR) per box created (this accounts for a
-	// bit of overhead used to store the box bytes)
-	BoxFlatMinBalance uint64
-
-	// MBR per byte of box storage. MBR is incremented by BoxByteMinBalance * (len(name)+len(value))
-	BoxByteMinBalance uint64
-
-	// Number of box references allowed
-	MaxAppBoxReferences int
-
-	// Amount added to a txgroup's box I/O budget per box ref supplied.
-	// For reads: the sum of the sizes of all boxes in the group must be less than I/O budget
-	// For writes: the sum of the sizes of all boxes created or written must be less than I/O budget
-	// In both cases, what matters is the sizes of the boxes touched, not the
-	// number of times they are touched, or the size of the touches.
-	BytesPerBoxReference uint64
-
-	// maximum number of total key/value pairs allowed by a given
-	// LocalStateSchema (and therefore allowed in LocalState)
-	MaxLocalSchemaEntries uint64
-
-	// maximum number of total key/value pairs allowed by a given
-	// GlobalStateSchema (and therefore allowed in GlobalState)
-	MaxGlobalSchemaEntries uint64
-
-	// maximum total minimum balance requirement for an account, used
-	// to limit the maximum size of a single balance record
-	MaximumMinimumBalance uint64
-
-	// StateProofInterval defines the frequency with which state
-	// proofs are generated.  Every round that is a multiple
-	// of StateProofInterval, the block header will include a vector
-	// commitment to the set of online accounts (that can vote after
-	// another StateProofInterval rounds), and that block will be signed
-	// (forming a state proof) by the voters from the previous
-	// such vector commitment.  A value of zero means no state proof.
-	StateProofInterval uint64
-
-	// StateProofTopVoters is a bound on how many online accounts get to
-	// participate in forming the state proof, by including the
-	// top StateProofTopVoters accounts (by normalized balance) into the
-	// vector commitment.
-	StateProofTopVoters uint64
-
-	// StateProofVotersLookback is the number of blocks we skip before
-	// publishing a vector commitment to the online accounts.  Namely,
-	// if block number N contains a vector commitment to the online
-	// accounts (which, incidentally, means N%StateProofInterval=0),
-	// then the balances reflected in that commitment must come from
-	// block N-StateProofVotersLookback.  This gives each node some
-	// time (StateProofVotersLookback blocks worth of time) to
-	// construct this vector commitment, so as to avoid placing the
-	// construction of this vector commitment (and obtaining the requisite
-	// accounts and balances) in the critical path.
-	StateProofVotersLookback uint64
-
-	// StateProofWeightThreshold specifies the fraction of top voters weight
-	// that must sign the message (block header) for security.  The state
-	// proof ensures this threshold holds; however, forming a valid
-	// state proof requires a somewhat higher number of signatures,
-	// and the more signatures are collected, the smaller the state proof
-	// can be.
-	//
-	// This threshold can be thought of as the maximum fraction of
-	// malicious weight that state proofs defend against.
-	//
-	// The threshold is computed as StateProofWeightThreshold/(1<<32).
-	StateProofWeightThreshold uint32
-
-	// StateProofStrengthTarget represents either k+q (for pre-quantum security) or k+2q (for post-quantum security)
-	StateProofStrengthTarget uint64
-
-	// StateProofMaxRecoveryIntervals represents the number of state proof intervals that the network will try to catch-up with.
-	// When the difference between the latest state proof and the current round will be greater than value, Nodes will
-	// release resources allocated for creating state proofs.
-	StateProofMaxRecoveryIntervals uint64
-
-	// StateProofExcludeTotalWeightWithRewards specifies whether to subtract rewards from excluded online accounts along with
-	// their account balances.
-	StateProofExcludeTotalWeightWithRewards bool
-
-	// EnableAssetCloseAmount adds an extra field to the ApplyData. The field contains the amount of the remaining
-	// asset that were sent to the close-to address.
-	EnableAssetCloseAmount bool
-
-	// update the initial rewards rate calculation to take the reward pool minimum balance into account
-	InitialRewardsRateCalculation bool
-
-	// NoEmptyLocalDeltas updates how ApplyDelta.EvalDelta.LocalDeltas are stored
-	NoEmptyLocalDeltas bool
-
-	// EnableKeyregCoherencyCheck enable the following extra checks on key registration transactions:
-	// 1. checking that [VotePK/SelectionPK/VoteKeyDilution] are all set or all clear.
-	// 2. checking that the VoteFirst is less or equal to VoteLast.
-	// 3. checking that in the case of going offline, both the VoteFirst and VoteLast are clear.
-	// 4. checking that in the case of going online the VoteLast is non-zero and greater then the current network round.
-	// 5. checking that in the case of going online the VoteFirst is less or equal to the LastValid+1.
-	// 6. checking that in the case of going online the VoteFirst is less or equal to the next network round.
-	EnableKeyregCoherencyCheck bool
-
-	EnableExtraPagesOnAppUpdate bool
-
-	// MaxProposedExpiredOnlineAccounts is the maximum number of online accounts, which need
-	// to be taken offline, that would be proposed to be taken offline.
-	MaxProposedExpiredOnlineAccounts int
-
-	// EnableAccountDataResourceSeparation enables the support for extended application and asset storage
-	// in a separate table.
-	EnableAccountDataResourceSeparation bool
-
-	// When rewards rate changes, use the new value immediately.
-	RewardsCalculationFix bool
-
-	// EnableStateProofKeyregCheck enables the check for stateProof key on key registration
-	EnableStateProofKeyregCheck bool
-
-	// MaxKeyregValidPeriod defines the longest period (in rounds) allowed for a keyreg transaction.
-	// This number sets a limit to prevent the number of StateProof keys generated by the user from being too large, and also checked by the WellFormed method.
-	// The hard-limit for number of StateProof keys is derived from the maximum depth allowed for the merkle signature scheme's tree - 2^16.
-	// More keys => deeper merkle tree => longer proof required => infeasible for our SNARK.
-	MaxKeyregValidPeriod uint64
-
-	// UnifyInnerTxIDs enables a consistent, unified way of computing inner transaction IDs
-	UnifyInnerTxIDs bool
-
-	// EnableSHA256TxnCommitmentHeader enables the creation of a transaction vector commitment tree using SHA256 hash function. (vector commitment extends Merkle tree by having a position binding property).
-	// This new header is in addition to the existing SHA512_256 merkle root.
-	// It is useful for verifying transaction on different blockchains, as some may not support SHA512_256 OPCODE natively but SHA256 is common.
-	EnableSHA256TxnCommitmentHeader bool
-
-	// CatchpointLookback specifies a round lookback to take catchpoints at.
-	// Accounts snapshot for round X will be taken at X-CatchpointLookback
-	CatchpointLookback uint64
-
-	// DeeperBlockHeaderHistory defines number of rounds in addition to MaxTxnLife
-	// available for lookup for smart contracts and smart signatures.
-	// Setting it to 1 for example allows querying data up to MaxTxnLife + 1 rounds back from the Latest.
-	DeeperBlockHeaderHistory uint64
-
-	// EnableOnlineAccountCatchpoints specifies when to re-enable catchpoints after the online account table migration has occurred.
-	EnableOnlineAccountCatchpoints bool
-
-	// UnfundedSenders ensures that accounts with no balance (so they don't even
-	// "exist") can still be a transaction sender by avoiding updates to rewards
-	// state for accounts with no algos. The actual change implemented to allow
-	// this is to avoid updating an account if the only change would have been
-	// the rewardsLevel, but the rewardsLevel has no meaning because the account
-	// has fewer than RewardUnit algos.
-	UnfundedSenders bool
-}
-
-// PaysetCommitType enumerates possible ways for the block header to commit to
-// the set of transactions in the block.
-type PaysetCommitType int
-
-const (
-	// PaysetCommitUnsupported is the zero value, reflecting the fact
-	// that some early protocols used a Merkle tree to commit to the
-	// transactions in a way that we no longer support.
-	PaysetCommitUnsupported PaysetCommitType = iota
-
-	// PaysetCommitFlat hashes the entire payset array.
-	PaysetCommitFlat
-
-	// PaysetCommitMerkle uses merkle array to commit to the payset.
-	PaysetCommitMerkle
-)
-
-// ConsensusProtocols defines a set of supported protocol versions and their
-// corresponding parameters.
-type ConsensusProtocols map[protocol.ConsensusVersion]ConsensusParams
-
-// Consensus tracks the protocol-level settings for different versions of the
-// consensus protocol.
-var Consensus ConsensusProtocols
-
-// MaxVoteThreshold is the largest threshold for a bundle over all supported
-// consensus protocols, used for decoding purposes.
-var MaxVoteThreshold int
-
-// MaxEvalDeltaAccounts is the largest number of accounts that may appear in
-// an eval delta, used for decoding purposes.
-var MaxEvalDeltaAccounts int
-
-// MaxStateDeltaKeys is the largest number of key/value pairs that may appear
-// in a StateDelta, used for decoding purposes.
-var MaxStateDeltaKeys int
-
-// MaxLogCalls is the highest allowable log messages that may appear in
-// any version, used only for decoding purposes. Never decrease this value.
-var MaxLogCalls int
-
-// MaxInnerTransactionsPerDelta is the maximum number of inner transactions in one EvalDelta
-var MaxInnerTransactionsPerDelta int
-
-// MaxLogicSigMaxSize is the largest logical signature appear in any of the supported
-// protocols, used for decoding purposes.
-var MaxLogicSigMaxSize int
-
-// MaxTxnNoteBytes is the largest supported nodes field array size supported by any
-// of the consensus protocols. used for decoding purposes.
-var MaxTxnNoteBytes int
-
-// MaxTxGroupSize is the largest supported number of transactions per transaction group supported by any
-// of the consensus protocols. used for decoding purposes.
-var MaxTxGroupSize int
-
-// MaxAppProgramLen is the largest supported app program size supported by any
-// of the consensus protocols. used for decoding purposes.
-var MaxAppProgramLen int
-
-// MaxBytesKeyValueLen is a maximum length of key or value across all protocols.
-// used for decoding purposes.
-var MaxBytesKeyValueLen int
-
-// MaxExtraAppProgramLen is the maximum extra app program length supported by any
-// of the consensus protocols. used for decoding purposes.
-var MaxExtraAppProgramLen int
-
-// MaxAvailableAppProgramLen is the largest supported app program size include the extra pages
-//supported supported by any of the consensus protocols. used for decoding purposes.
-var MaxAvailableAppProgramLen int
-
-// MaxProposedExpiredOnlineAccounts is the maximum number of online accounts, which need
-// to be taken offline, that would be proposed to be taken offline.
-var MaxProposedExpiredOnlineAccounts int
-
-func checkSetMax(value int, curMax *int) {
-	if value > *curMax {
-		*curMax = value
-	}
-}
-
-// checkSetAllocBounds sets some global variables used during msgpack decoding
-// to enforce memory allocation limits. The values should be generous to
-// prevent correctness bugs, but not so large that DoS attacks are trivial
-func checkSetAllocBounds(p ConsensusParams) {
-	checkSetMax(int(p.SoftCommitteeThreshold), &MaxVoteThreshold)
-	checkSetMax(int(p.CertCommitteeThreshold), &MaxVoteThreshold)
-	checkSetMax(int(p.NextCommitteeThreshold), &MaxVoteThreshold)
-	checkSetMax(int(p.LateCommitteeThreshold), &MaxVoteThreshold)
-	checkSetMax(int(p.RedoCommitteeThreshold), &MaxVoteThreshold)
-	checkSetMax(int(p.DownCommitteeThreshold), &MaxVoteThreshold)
-
-	// These bounds could be tighter, but since these values are just to
-	// prevent DoS, setting them to be the maximum number of allowed
-	// executed TEAL instructions should be fine (order of ~1000)
-	checkSetMax(p.MaxAppProgramLen, &MaxStateDeltaKeys)
-	checkSetMax(p.MaxAppProgramLen, &MaxEvalDeltaAccounts)
-	checkSetMax(p.MaxAppProgramLen, &MaxAppProgramLen)
-	checkSetMax(int(p.LogicSigMaxSize), &MaxLogicSigMaxSize)
-	checkSetMax(p.MaxTxnNoteBytes, &MaxTxnNoteBytes)
-	checkSetMax(p.MaxTxGroupSize, &MaxTxGroupSize)
-	// MaxBytesKeyValueLen is max of MaxAppKeyLen and MaxAppBytesValueLen
-	checkSetMax(p.MaxAppKeyLen, &MaxBytesKeyValueLen)
-	checkSetMax(p.MaxAppBytesValueLen, &MaxBytesKeyValueLen)
-	checkSetMax(p.MaxExtraAppProgramPages, &MaxExtraAppProgramLen)
-	// MaxAvailableAppProgramLen is the max of supported app program size
-	MaxAvailableAppProgramLen = MaxAppProgramLen * (1 + MaxExtraAppProgramLen)
-	// There is no consensus parameter for MaxLogCalls and MaxAppProgramLen as an approximation
-	// Its value is much larger than any possible reasonable MaxLogCalls value in future
-	checkSetMax(p.MaxAppProgramLen, &MaxLogCalls)
-	checkSetMax(p.MaxInnerTransactions*p.MaxTxGroupSize, &MaxInnerTransactionsPerDelta)
-	checkSetMax(p.MaxProposedExpiredOnlineAccounts, &MaxProposedExpiredOnlineAccounts)
-}
-
-// DeepCopy creates a deep copy of a consensus protocols map.
-func (cp ConsensusProtocols) DeepCopy() ConsensusProtocols {
-	staticConsensus := make(ConsensusProtocols)
-	for consensusVersion, consensusParams := range cp {
-		// recreate the ApprovedUpgrades map since we don't want to modify the original one.
-		if consensusParams.ApprovedUpgrades != nil {
-			newApprovedUpgrades := make(map[protocol.ConsensusVersion]uint64)
-			for ver, when := range consensusParams.ApprovedUpgrades {
-				newApprovedUpgrades[ver] = when
-			}
-			consensusParams.ApprovedUpgrades = newApprovedUpgrades
-		}
-		staticConsensus[consensusVersion] = consensusParams
-	}
-	return staticConsensus
-}
-
-// Merge merges a configurable consensus on top of the existing consensus protocol and return
-// a new consensus protocol without modify any of the incoming structures.
-func (cp ConsensusProtocols) Merge(configurableConsensus ConsensusProtocols) ConsensusProtocols {
-	staticConsensus := cp.DeepCopy()
-
-	for consensusVersion, consensusParams := range configurableConsensus {
-		if consensusParams.ApprovedUpgrades == nil {
-			// if we were provided with an empty ConsensusParams, delete the existing reference to this consensus version
-			for cVer, cParam := range staticConsensus {
-				if cVer == consensusVersion {
-					delete(staticConsensus, cVer)
-				} else if _, has := cParam.ApprovedUpgrades[consensusVersion]; has {
-					// delete upgrade to deleted version
-					delete(cParam.ApprovedUpgrades, consensusVersion)
-				}
-			}
-		} else {
-			// need to add/update entry
-			staticConsensus[consensusVersion] = consensusParams
-		}
-	}
-
-	return staticConsensus
-}
-
-func initConsensusProtocols() {
-	// WARNING: copying a ConsensusParams by value into a new variable
-	// does not copy the ApprovedUpgrades map.  Make sure that each new
-	// ConsensusParams structure gets a fresh ApprovedUpgrades map.
-
-	// Base consensus protocol version, v7.
-	v7 := ConsensusParams{
-		UpgradeVoteRounds:        10000,
-		UpgradeThreshold:         9000,
-		DefaultUpgradeWaitRounds: 10000,
-		MaxVersionStringLen:      64,
-
-		MinBalance:          10000,
-		MinTxnFee:           1000,
-		MaxTxnLife:          1000,
-		MaxTxnNoteBytes:     1024,
-		MaxTxnBytesPerBlock: 1000000,
-		DefaultKeyDilution:  10000,
-
-		MaxTimestampIncrement: 25,
-
-		RewardUnit:                 1e6,
-		RewardsRateRefreshInterval: 5e5,
-
-		ApprovedUpgrades: map[protocol.ConsensusVersion]uint64{},
-
-		NumProposers:           30,
-		SoftCommitteeSize:      2500,
-		SoftCommitteeThreshold: 1870,
-		CertCommitteeSize:      1000,
-		CertCommitteeThreshold: 720,
-		NextCommitteeSize:      10000,
-		NextCommitteeThreshold: 7750,
-		LateCommitteeSize:      10000,
-		LateCommitteeThreshold: 7750,
-		RedoCommitteeSize:      10000,
-		RedoCommitteeThreshold: 7750,
-		DownCommitteeSize:      10000,
-		DownCommitteeThreshold: 7750,
-
-		AgreementFilterTimeout:        4 * time.Second,
-		AgreementFilterTimeoutPeriod0: 4 * time.Second,
-
-		FastRecoveryLambda: 5 * time.Minute,
-
-		SeedLookback:        2,
-		SeedRefreshInterval: 100,
-
-		MaxBalLookback: 320,
-
-		MaxTxGroupSize: 1,
-	}
-
-	v7.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV7] = v7
-
-	// v8 uses parameters and a seed derivation policy (the "twin seeds") from Georgios' new analysis
-	v8 := v7
-
-	v8.SeedRefreshInterval = 80
-	v8.NumProposers = 9
-	v8.SoftCommitteeSize = 2990
-	v8.SoftCommitteeThreshold = 2267
-	v8.CertCommitteeSize = 1500
-	v8.CertCommitteeThreshold = 1112
-	v8.NextCommitteeSize = 5000
-	v8.NextCommitteeThreshold = 3838
-	v8.LateCommitteeSize = 5000
-	v8.LateCommitteeThreshold = 3838
-	v8.RedoCommitteeSize = 5000
-	v8.RedoCommitteeThreshold = 3838
-	v8.DownCommitteeSize = 5000
-	v8.DownCommitteeThreshold = 3838
-
-	v8.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV8] = v8
-
-	// v7 can be upgraded to v8.
-	v7.ApprovedUpgrades[protocol.ConsensusV8] = 0
-
-	// v9 increases the minimum balance to 100,000 microAlgos.
-	v9 := v8
-	v9.MinBalance = 100000
-	v9.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV9] = v9
-
-	// v8 can be upgraded to v9.
-	v8.ApprovedUpgrades[protocol.ConsensusV9] = 0
-
-	// v10 introduces fast partition recovery (and also raises NumProposers).
-	v10 := v9
-	v10.NumProposers = 20
-	v10.LateCommitteeSize = 500
-	v10.LateCommitteeThreshold = 320
-	v10.RedoCommitteeSize = 2400
-	v10.RedoCommitteeThreshold = 1768
-	v10.DownCommitteeSize = 6000
-	v10.DownCommitteeThreshold = 4560
-	v10.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV10] = v10
-
-	// v9 can be upgraded to v10.
-	v9.ApprovedUpgrades[protocol.ConsensusV10] = 0
-
-	// v11 introduces SignedTxnInBlock.
-	v11 := v10
-	v11.SupportSignedTxnInBlock = true
-	v11.PaysetCommit = PaysetCommitFlat
-	v11.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV11] = v11
-
-	// v10 can be upgraded to v11.
-	v10.ApprovedUpgrades[protocol.ConsensusV11] = 0
-
-	// v12 increases the maximum length of a version string.
-	v12 := v11
-	v12.MaxVersionStringLen = 128
-	v12.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV12] = v12
-
-	// v11 can be upgraded to v12.
-	v11.ApprovedUpgrades[protocol.ConsensusV12] = 0
-
-	// v13 makes the consensus version a meaningful string.
-	v13 := v12
-	v13.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV13] = v13
-
-	// v12 can be upgraded to v13.
-	v12.ApprovedUpgrades[protocol.ConsensusV13] = 0
-
-	// v14 introduces tracking of closing amounts in ApplyData, and enables
-	// GenesisHash in transactions.
-	v14 := v13
-	v14.ApplyData = true
-	v14.SupportGenesisHash = true
-	v14.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV14] = v14
-
-	// v13 can be upgraded to v14.
-	v13.ApprovedUpgrades[protocol.ConsensusV14] = 0
-
-	// v15 introduces tracking of reward distributions in ApplyData.
-	v15 := v14
-	v15.RewardsInApplyData = true
-	v15.ForceNonParticipatingFeeSink = true
-	v15.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV15] = v15
-
-	// v14 can be upgraded to v15.
-	v14.ApprovedUpgrades[protocol.ConsensusV15] = 0
-
-	// v16 fixes domain separation in credentials.
-	v16 := v15
-	v16.CredentialDomainSeparationEnabled = true
-	v16.RequireGenesisHash = true
-	v16.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV16] = v16
-
-	// v15 can be upgraded to v16.
-	v15.ApprovedUpgrades[protocol.ConsensusV16] = 0
-
-	// ConsensusV17 points to 'final' spec commit
-	v17 := v16
-	v17.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV17] = v17
-
-	// v16 can be upgraded to v17.
-	v16.ApprovedUpgrades[protocol.ConsensusV17] = 0
-
-	// ConsensusV18 points to reward calculation spec commit
-	v18 := v17
-	v18.PendingResidueRewards = true
-	v18.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	v18.TxnCounter = true
-	v18.Asset = true
-	v18.LogicSigVersion = 1
-	v18.LogicSigMaxSize = 1000
-	v18.LogicSigMaxCost = 20000
-	v18.MaxAssetsPerAccount = 1000
-	v18.SupportTxGroups = true
-	v18.MaxTxGroupSize = 16
-	v18.SupportTransactionLeases = true
-	v18.SupportBecomeNonParticipatingTransactions = true
-	v18.MaxAssetNameBytes = 32
-	v18.MaxAssetUnitNameBytes = 8
-	v18.MaxAssetURLBytes = 32
-	Consensus[protocol.ConsensusV18] = v18
-
-	// ConsensusV19 is the official spec commit ( teal, assets, group tx )
-	v19 := v18
-	v19.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	Consensus[protocol.ConsensusV19] = v19
-
-	// v18 can be upgraded to v19.
-	v18.ApprovedUpgrades[protocol.ConsensusV19] = 0
-	// v17 can be upgraded to v19.
-	v17.ApprovedUpgrades[protocol.ConsensusV19] = 0
-
-	// v20 points to adding the precision to the assets.
-	v20 := v19
-	v20.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	v20.MaxAssetDecimals = 19
-	// we want to adjust the upgrade time to be roughly one week.
-	// one week, in term of rounds would be:
-	// 140651 = (7 * 24 * 60 * 60 / 4.3)
-	// for the sake of future manual calculations, we'll round that down
-	// a bit :
-	v20.DefaultUpgradeWaitRounds = 140000
-	Consensus[protocol.ConsensusV20] = v20
-
-	// v19 can be upgraded to v20.
-	v19.ApprovedUpgrades[protocol.ConsensusV20] = 0
-
-	// v21 fixes a bug in Credential.lowestOutput that would cause larger accounts to be selected to propose disproportionately more often than small accounts
-	v21 := v20
-	v21.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusV21] = v21
-	// v20 can be upgraded to v21.
-	v20.ApprovedUpgrades[protocol.ConsensusV21] = 0
-
-	// v22 is an upgrade which allows tuning the number of rounds to wait to execute upgrades.
-	v22 := v21
-	v22.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	v22.MinUpgradeWaitRounds = 10000
-	v22.MaxUpgradeWaitRounds = 150000
-	Consensus[protocol.ConsensusV22] = v22
-
-	// v23 is an upgrade which fixes the behavior of leases so that
-	// it conforms with the intended spec.
-	v23 := v22
-	v23.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	v23.FixTransactionLeases = true
-	Consensus[protocol.ConsensusV23] = v23
-	// v22 can be upgraded to v23.
-	v22.ApprovedUpgrades[protocol.ConsensusV23] = 10000
-	// v21 can be upgraded to v23.
-	v21.ApprovedUpgrades[protocol.ConsensusV23] = 0
-
-	// v24 is the stateful teal and rekeying upgrade
-	v24 := v23
-	v24.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	v24.LogicSigVersion = 2
-
-	// Enable application support
-	v24.Application = true
-
-	// Although Inners were not allowed yet, this gates downgrade checks, which must be allowed
-	v24.MinInnerApplVersion = 6
-
-	// Enable rekeying
-	v24.SupportRekeying = true
-
-	// 100.1 Algos (MinBalance for creating 1,000 assets)
-	v24.MaximumMinimumBalance = 100100000
-
-	v24.MaxAppArgs = 16
-	v24.MaxAppTotalArgLen = 2048
-	v24.MaxAppProgramLen = 1024
-	v24.MaxAppTotalProgramLen = 2048 // No effect until v28, when MaxAppProgramLen increased
-	v24.MaxAppKeyLen = 64
-	v24.MaxAppBytesValueLen = 64
-	v24.MaxAppSumKeyValueLens = 128 // Set here to have no effect until MaxAppBytesValueLen increases
-
-	// 0.1 Algos (Same min balance cost as an Asset)
-	v24.AppFlatParamsMinBalance = 100000
-	v24.AppFlatOptInMinBalance = 100000
-
-	// Can look up Sender + 4 other balance records per Application txn
-	v24.MaxAppTxnAccounts = 4
-
-	// Can look up 2 other app creator balance records to see global state
-	v24.MaxAppTxnForeignApps = 2
-
-	// Can look up 2 assets to see asset parameters
-	v24.MaxAppTxnForeignAssets = 2
-
-	// Intended to have no effect in v24 (it's set to accounts +
-	// asas + apps). In later vers, it allows increasing the
-	// individual limits while maintaining same max references.
-	v24.MaxAppTotalTxnReferences = 8
-
-	// 64 byte keys @ ~333 microAlgos/byte + delta
-	v24.SchemaMinBalancePerEntry = 25000
-
-	// 9 bytes @ ~333 microAlgos/byte + delta
-	v24.SchemaUintMinBalance = 3500
-
-	// 64 byte values @ ~333 microAlgos/byte + delta
-	v24.SchemaBytesMinBalance = 25000
-
-	// Maximum number of key/value pairs per local key/value store
-	v24.MaxLocalSchemaEntries = 16
-
-	// Maximum number of key/value pairs per global key/value store
-	v24.MaxGlobalSchemaEntries = 64
-
-	// Maximum cost of ApprovalProgram/ClearStateProgram
-	v24.MaxAppProgramCost = 700
-
-	// Maximum number of apps a single account can create
-	v24.MaxAppsCreated = 10
-
-	// Maximum number of apps a single account can opt into
-	v24.MaxAppsOptedIn = 10
-	Consensus[protocol.ConsensusV24] = v24
-
-	// v23 can be upgraded to v24, with an update delay of 7 days ( see calculation above )
-	v23.ApprovedUpgrades[protocol.ConsensusV24] = 140000
-
-	// v25 enables AssetCloseAmount in the ApplyData
-	v25 := v24
-	v25.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Enable AssetCloseAmount field
-	v25.EnableAssetCloseAmount = true
-	Consensus[protocol.ConsensusV25] = v25
-
-	// v26 adds support for teal3
-	v26 := v25
-	v26.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Enable the InitialRewardsRateCalculation fix
-	v26.InitialRewardsRateCalculation = true
-
-	// Enable transaction Merkle tree.
-	v26.PaysetCommit = PaysetCommitMerkle
-
-	// Enable teal3
-	v26.LogicSigVersion = 3
-
-	Consensus[protocol.ConsensusV26] = v26
-
-	// v25 or v24 can be upgraded to v26, with an update delay of 7 days ( see calculation above )
-	v25.ApprovedUpgrades[protocol.ConsensusV26] = 140000
-	v24.ApprovedUpgrades[protocol.ConsensusV26] = 140000
-
-	// v27 updates ApplyDelta.EvalDelta.LocalDeltas format
-	v27 := v26
-	v27.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Enable the ApplyDelta.EvalDelta.LocalDeltas fix
-	v27.NoEmptyLocalDeltas = true
-
-	Consensus[protocol.ConsensusV27] = v27
-
-	// v26 can be upgraded to v27, with an update delay of 3 days
-	// 60279 = (3 * 24 * 60 * 60 / 4.3)
-	// for the sake of future manual calculations, we'll round that down
-	// a bit :
-	v26.ApprovedUpgrades[protocol.ConsensusV27] = 60000
-
-	// v28 introduces new TEAL features, larger program size, fee pooling and longer asset max URL
-	v28 := v27
-	v28.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Enable TEAL 4 / AVM 0.9
-	v28.LogicSigVersion = 4
-	// Enable support for larger app program size
-	v28.MaxExtraAppProgramPages = 3
-	v28.MaxAppProgramLen = 2048
-	// Increase asset URL length to allow for IPFS URLs
-	v28.MaxAssetURLBytes = 96
-	// Let the bytes value take more space. Key+Value is still limited to 128
-	v28.MaxAppBytesValueLen = 128
-
-	// Individual limits raised
-	v28.MaxAppTxnForeignApps = 8
-	v28.MaxAppTxnForeignAssets = 8
-
-	// MaxAppTxnAccounts has not been raised yet.  It is already
-	// higher (4) and there is a multiplicative effect in
-	// "reachability" between accounts and creatables, so we
-	// retain 4 x 4 as worst case.
-
-	v28.EnableFeePooling = true
-	v28.EnableKeyregCoherencyCheck = true
-
-	Consensus[protocol.ConsensusV28] = v28
-
-	// v27 can be upgraded to v28, with an update delay of 7 days ( see calculation above )
-	v27.ApprovedUpgrades[protocol.ConsensusV28] = 140000
-
-	// v29 fixes application update by using ExtraProgramPages in size calculations
-	v29 := v28
-	v29.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Enable ExtraProgramPages for application update
-	v29.EnableExtraPagesOnAppUpdate = true
-
-	Consensus[protocol.ConsensusV29] = v29
-
-	// v28 can be upgraded to v29, with an update delay of 3 days ( see calculation above )
-	v28.ApprovedUpgrades[protocol.ConsensusV29] = 60000
-
-	// v30 introduces AVM 1.0 and TEAL 5, increases the app opt in limit to 50,
-	// and allows costs to be pooled in grouped stateful transactions.
-	v30 := v29
-	v30.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Enable TEAL 5 / AVM 1.0
-	v30.LogicSigVersion = 5
-
-	// Enable App calls to pool budget in grouped transactions
-	v30.EnableAppCostPooling = true
-
-	// Enable Inner Transactions, and set maximum number. 0 value is
-	// disabled.  Value > 0 also activates storage of creatable IDs in
-	// ApplyData, as that is required to support REST API when inner
-	// transactions are activated.
-	v30.MaxInnerTransactions = 16
-
-	// Allow 50 app opt ins
-	v30.MaxAppsOptedIn = 50
-
-	Consensus[protocol.ConsensusV30] = v30
-
-	// v29 can be upgraded to v30, with an update delay of 7 days ( see calculation above )
-	v29.ApprovedUpgrades[protocol.ConsensusV30] = 140000
-
-	v31 := v30
-	v31.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	v31.RewardsCalculationFix = true
-	v31.MaxProposedExpiredOnlineAccounts = 32
-
-	// Enable TEAL 6 / AVM 1.1
-	v31.LogicSigVersion = 6
-	v31.EnableInnerTransactionPooling = true
-	v31.IsolateClearState = true
-
-	// stat proof key registration
-	v31.EnableStateProofKeyregCheck = true
-
-	// Maximum validity period for key registration, to prevent generating too many StateProof keys
-	v31.MaxKeyregValidPeriod = 256*(1<<16) - 1
-
-	Consensus[protocol.ConsensusV31] = v31
-
-	// v30 can be upgraded to v31, with an update delay of 7 days ( see calculation above )
-	v30.ApprovedUpgrades[protocol.ConsensusV31] = 140000
-
-	v32 := v31
-	v32.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Enable extended application storage; binaries that contain support for this
-	// flag would already be restructuring their internal storage for extended
-	// application storage, and therefore would not produce catchpoints and/or
-	// catchpoint labels prior to this feature being enabled.
-	v32.EnableAccountDataResourceSeparation = true
-
-	// Remove limits on MinimumBalance
-	v32.MaximumMinimumBalance = 0
-
-	// Remove limits on assets / account.
-	v32.MaxAssetsPerAccount = 0
-
-	// Remove limits on maximum number of apps a single account can create
-	v32.MaxAppsCreated = 0
-
-	// Remove limits on maximum number of apps a single account can opt into
-	v32.MaxAppsOptedIn = 0
-
-	Consensus[protocol.ConsensusV32] = v32
-
-	// v31 can be upgraded to v32, with an update delay of 7 days ( see calculation above )
-	v31.ApprovedUpgrades[protocol.ConsensusV32] = 140000
-
-	v33 := v32
-	v33.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Make the accounts snapshot for round X at X-CatchpointLookback
-	// order to guarantee all nodes produce catchpoint at the same round.
-	v33.CatchpointLookback = 320
-
-	// Require MaxTxnLife + X blocks and headers preserved by a node
-	v33.DeeperBlockHeaderHistory = 1
-
-	v33.MaxTxnBytesPerBlock = 5 * 1024 * 1024
-
-	Consensus[protocol.ConsensusV33] = v33
-
-	// v32 can be upgraded to v33, with an update delay of 7 days ( see calculation above )
-	v32.ApprovedUpgrades[protocol.ConsensusV33] = 140000
-
-	v34 := v33
-	v34.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Enable state proofs.
-	v34.StateProofInterval = 256
-	v34.StateProofTopVoters = 1024
-	v34.StateProofVotersLookback = 16
-	v34.StateProofWeightThreshold = (1 << 32) * 30 / 100
-	v34.StateProofStrengthTarget = 256
-	v34.StateProofMaxRecoveryIntervals = 10
-
-	v34.LogicSigVersion = 7
-	v34.MinInnerApplVersion = 4
-
-	v34.UnifyInnerTxIDs = true
-
-	v34.EnableSHA256TxnCommitmentHeader = true
-	v34.EnableOnlineAccountCatchpoints = true
-
-	v34.UnfundedSenders = true
-
-	v34.AgreementFilterTimeoutPeriod0 = 3400 * time.Millisecond
-
-	Consensus[protocol.ConsensusV34] = v34
-
-	v35 := v34
-	v35.StateProofExcludeTotalWeightWithRewards = true
-
-	v35.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	Consensus[protocol.ConsensusV35] = v35
-
-	// v33 and v34 can be upgraded to v35, with an update delay of 12h:
-	// 10046 = (12 * 60 * 60 / 4.3)
-	// for the sake of future manual calculations, we'll round that down a bit :
-	v33.ApprovedUpgrades[protocol.ConsensusV35] = 10000
-	v34.ApprovedUpgrades[protocol.ConsensusV35] = 10000
-
-	v36 := v35
-	v36.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	// Boxes (unlimited global storage)
-	v36.LogicSigVersion = 8
-	v36.MaxBoxSize = 32768
-	v36.BoxFlatMinBalance = 2500
-	v36.BoxByteMinBalance = 400
-	v36.MaxAppBoxReferences = 8
-	v36.BytesPerBoxReference = 1024
-
-	Consensus[protocol.ConsensusV36] = v36
-
-	v35.ApprovedUpgrades[protocol.ConsensusV36] = 140000
-
-	// ConsensusFuture is used to test features that are implemented
-	// but not yet released in a production protocol version.
-	vFuture := v36
-	vFuture.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-
-	vFuture.LogicSigVersion = 9 // When moving this to a release, put a new higher LogicSigVersion here
-
-	Consensus[protocol.ConsensusFuture] = vFuture
-
-	// vAlphaX versions are an separate series of consensus parameters and versions for alphanet
-	vAlpha1 := v32
-	vAlpha1.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	vAlpha1.AgreementFilterTimeoutPeriod0 = 2 * time.Second
-	vAlpha1.MaxTxnBytesPerBlock = 5000000
-	Consensus[protocol.ConsensusVAlpha1] = vAlpha1
-
-	vAlpha2 := vAlpha1
-	vAlpha2.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	vAlpha2.AgreementFilterTimeoutPeriod0 = 3500 * time.Millisecond
-	vAlpha2.MaxTxnBytesPerBlock = 5 * 1024 * 1024
-	Consensus[protocol.ConsensusVAlpha2] = vAlpha2
-	vAlpha1.ApprovedUpgrades[protocol.ConsensusVAlpha2] = 10000
-
-	// vAlpha3 and vAlpha4 use the same parameters as v33 and v34
-	vAlpha3 := v33
-	vAlpha3.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusVAlpha3] = vAlpha3
-	vAlpha2.ApprovedUpgrades[protocol.ConsensusVAlpha3] = 10000
-
-	vAlpha4 := v34
-	vAlpha4.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusVAlpha4] = vAlpha4
-	vAlpha3.ApprovedUpgrades[protocol.ConsensusVAlpha4] = 10000
-
-	// vAlpha5 uses the same parameters as v36
-	vAlpha5 := v36
-	vAlpha5.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
-	Consensus[protocol.ConsensusVAlpha5] = vAlpha5
-	vAlpha4.ApprovedUpgrades[protocol.ConsensusVAlpha5] = 10000
-}
-
-// Global defines global Algorand protocol parameters which should not be overridden.
-type Global struct {
-	SmallLambda time.Duration // min amount of time to wait for leader's credential (i.e., time to propagate one credential)
-	BigLambda   time.Duration // max amount of time to wait for leader's proposal (i.e., time to propagate one block)
-}
-
-// Protocol holds the global configuration settings for the agreement protocol,
-// initialized with our current defaults. This is used across all nodes we create.
-var Protocol = Global{
-	SmallLambda: 2000 * time.Millisecond,
-	BigLambda:   15000 * time.Millisecond,
-}
-
-func init() {
-	Consensus = make(ConsensusProtocols)
-
-	initConsensusProtocols()
-
-	// Set allocation limits
-	for _, p := range Consensus {
-		checkSetAllocBounds(p)
-	}
-
-}
diff --git a/protocol/consensus.go b/protocol/consensus.go
deleted file mode 100644
index f9ee2ec..0000000
--- a/protocol/consensus.go
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright (C) 2019-2022 Algorand, Inc.
-// This file is part of go-algorand
-//
-// go-algorand is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// go-algorand is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with go-algorand.  If not, see <https://www.gnu.org/licenses/>.
-
-package protocol
-
-import (
-	"fmt"
-)
-
-// ConsensusVersion is a string that identifies a version of the
-// consensus protocol.
-type ConsensusVersion string
-
-// DEPRECATEDConsensusV0 is a baseline version of the Algorand consensus protocol.
-// at the time versioning was introduced.
-// It is now deprecated.
-const DEPRECATEDConsensusV0 = ConsensusVersion("v0")
-
-// DEPRECATEDConsensusV1 adds support for Genesis ID in transactions, but does not
-// require it (transactions missing a GenesisID value are still allowed).
-// It is now deprecated.
-const DEPRECATEDConsensusV1 = ConsensusVersion("v1")
-
-// DEPRECATEDConsensusV2 fixes a bug in the agreement protocol where proposalValues
-// fail to commit to the original period and sender of a block.
-const DEPRECATEDConsensusV2 = ConsensusVersion("v2")
-
-// DEPRECATEDConsensusV3 adds support for fine-grained ephemeral keys.
-const DEPRECATEDConsensusV3 = ConsensusVersion("v3")
-
-// DEPRECATEDConsensusV4 adds support for a min balance and a transaction that
-// closes out an account.
-const DEPRECATEDConsensusV4 = ConsensusVersion("v4")
-
-// DEPRECATEDConsensusV5 sets MinTxnFee to 1000 and fixes a blance lookback bug
-const DEPRECATEDConsensusV5 = ConsensusVersion("v5")
-
-// DEPRECATEDConsensusV6 adds support for explicit ephemeral-key parameters
-const DEPRECATEDConsensusV6 = ConsensusVersion("v6")
-
-// ConsensusV7 increases MaxBalLookback to 320 in preparation for
-// the twin seeds change.
-const ConsensusV7 = ConsensusVersion("v7")
-
-// ConsensusV8 uses the new parameters and seed derivation policy
-// from the agreement protocol's security analysis.
-const ConsensusV8 = ConsensusVersion("v8")
-
-// ConsensusV9 increases min balance to 100,000 microAlgos.
-const ConsensusV9 = ConsensusVersion("v9")
-
-// ConsensusV10 introduces fast partition recovery.
-const ConsensusV10 = ConsensusVersion("v10")
-
-// ConsensusV11 introduces efficient encoding of SignedTxn using SignedTxnInBlock.
-const ConsensusV11 = ConsensusVersion("v11")
-
-// ConsensusV12 increases the maximum length of a version string.
-const ConsensusV12 = ConsensusVersion("v12")
-
-// ConsensusV13 makes the consensus version a meaningful string.
-const ConsensusV13 = ConsensusVersion(
-	// Points to version of the Algorand spec as of May 21, 2019.
-	"https://github.com/algorand/spec/tree/0c8a9dc44d7368cc266d5407b79fb3311f4fc795",
-)
-
-// ConsensusV14 adds tracking of closing amounts in ApplyData,
-// and enables genesis hash in transactions.
-const ConsensusV14 = ConsensusVersion(
-	"https://github.com/algorand/spec/tree/2526b6ae062b4fe5e163e06e41e1d9b9219135a9",
-)
-
-// ConsensusV15 adds tracking of reward distributions in ApplyData.
-const ConsensusV15 = ConsensusVersion(
-	"https://github.com/algorand/spec/tree/a26ed78ed8f834e2b9ccb6eb7d3ee9f629a6e622",
-)
-
-// ConsensusV16 fixes domain separation in Credentials and requires GenesisHash.
-const ConsensusV16 = ConsensusVersion(
-	"https://github.com/algorand/spec/tree/22726c9dcd12d9cddce4a8bd7e8ccaa707f74101",
-)
-
-// ConsensusV17 points to 'final' spec commit for 2019 june release
-const ConsensusV17 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/5615adc36bad610c7f165fa2967f4ecfa75125f0",
-)
-
-// ConsensusV18 points to reward calculation spec commit
-const ConsensusV18 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/6c6bd668be0ab14098e51b37e806c509f7b7e31f",
-)
-
-// ConsensusV19 points to 'final' spec commit for 2019 nov release
-const ConsensusV19 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/0e196e82bfd6e327994bec373c4cc81bc878ef5c",
-)
-
-// ConsensusV20 points to adding the decimals field to assets
-const ConsensusV20 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/4a9db6a25595c6fd097cf9cc137cc83027787eaa",
-)
-
-// ConsensusV21 fixes a bug in credential.lowestOutput
-const ConsensusV21 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/8096e2df2da75c3339986317f9abe69d4fa86b4b",
-)
-
-// ConsensusV22 allows tuning the upgrade delay.
-const ConsensusV22 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/57016b942f6d97e6d4c0688b373bb0a2fc85a1a2",
-)
-
-// ConsensusV23 fixes lease behavior.
-const ConsensusV23 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/e5f565421d720c6f75cdd186f7098495caf9101f",
-)
-
-// ConsensusV24 include the applications, rekeying and AVM v2
-const ConsensusV24 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/3a83c4c743f8b17adfd73944b4319c25722a6782",
-)
-
-// ConsensusV25 adds support for AssetCloseAmount in the ApplyData
-const ConsensusV25 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/bea19289bf41217d2c0af30522fa222ef1366466",
-)
-
-// ConsensusV26 adds support for TEAL 3, initial rewards calculation and merkle tree hash commitments
-const ConsensusV26 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/ac2255d586c4474d4ebcf3809acccb59b7ef34ff",
-)
-
-// ConsensusV27 updates ApplyDelta.EvalDelta.LocalDeltas format
-const ConsensusV27 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/d050b3cade6d5c664df8bd729bf219f179812595",
-)
-
-// ConsensusV28 introduces new TEAL features, larger program size, fee pooling and longer asset max URL
-const ConsensusV28 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/65b4ab3266c52c56a0fa7d591754887d68faad0a",
-)
-
-// ConsensusV29 fixes application update by using ExtraProgramPages in size calculations
-const ConsensusV29 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/abc54f79f9ad679d2d22f0fb9909fb005c16f8a1",
-)
-
-// ConsensusV30 introduces AVM 1.0 and TEAL 5, increases the app opt in limit to 50,
-// and allows costs to be pooled in grouped stateful transactions.
-const ConsensusV30 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/bc36005dbd776e6d1eaf0c560619bb183215645c",
-)
-
-// ConsensusV31 enables the batch verification for ed25519 signatures, Fix reward calculation issue, introduces the ability
-// to force an expired participation offline, enables TEAL 6 ( AVM 1.1 ) and add support for creating
-// state proof keys.
-const ConsensusV31 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/85e6db1fdbdef00aa232c75199e10dc5fe9498f6",
-)
-
-// ConsensusV32 enables the unlimited assets.
-const ConsensusV32 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/d5ac876d7ede07367dbaa26e149aa42589aac1f7",
-)
-
-// ConsensusV33 enables large blocks, the deeper block history for TEAL
-// and catchpoint generation round after lowering in-memory deltas size (320 -> 4).
-const ConsensusV33 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/830a4e673148498cc7230a0d1ba1ed0a5471acc6",
-)
-
-// ConsensusV34 enables the TEAL v7 opcodes, stateproofs, shorter lambda.
-const ConsensusV34 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/2dd5435993f6f6d65691140f592ebca5ef19ffbd",
-)
-
-// ConsensusV35 updates the calculation of total stake in state proofs.
-const ConsensusV35 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/433d8e9a7274b6fca703d91213e05c7e6a589e69",
-)
-
-// ConsensusV36 adds box storage
-const ConsensusV36 = ConsensusVersion(
-	"https://github.com/algorandfoundation/specs/tree/44fa607d6051730f5264526bf3c108d51f0eadb6",
-)
-
-// ConsensusFuture is a protocol that should not appear in any production
-// network, but is used to test features before they are released.
-const ConsensusFuture = ConsensusVersion(
-	"future",
-)
-
-// ConsensusVAlpha1 is the first consensus protocol for AlphaNet, which is the same as
-// v32, but with a 2-second filter timeout and 5M block size.
-const ConsensusVAlpha1 = ConsensusVersion("alpha1")
-
-// ConsensusVAlpha2 is the second consensus protocol for AlphaNet, which increases the
-// filter timeout to 3.5 seconds and uses 5MiB blocks.
-const ConsensusVAlpha2 = ConsensusVersion("alpha2")
-
-// ConsensusVAlpha3 uses the same parameters as ConsensusV33.
-const ConsensusVAlpha3 = ConsensusVersion("alpha3")
-
-// ConsensusVAlpha4 uses the same parameters as ConsensusV34.
-const ConsensusVAlpha4 = ConsensusVersion("alpha4")
-
-// ConsensusVAlpha5 uses the same parameters as ConsensusV36.
-const ConsensusVAlpha5 = ConsensusVersion("alpha5")
-
-// !!! ********************* !!!
-// !!! *** Please update ConsensusCurrentVersion when adding new protocol versions *** !!!
-// !!! ********************* !!!
-
-// ConsensusCurrentVersion is the latest version and should be used
-// when a specific version is not provided.
-const ConsensusCurrentVersion = ConsensusV36
-
-// Error is used to indicate that an unsupported protocol has been detected.
-type Error ConsensusVersion
-
-// Error satisfies builtin interface `error`
-func (err Error) Error() string {
-	proto := ConsensusVersion(err)
-	return fmt.Sprintf("protocol not supported: %s", proto)
-}
diff --git a/util/util.go b/util/util.go
index a4540a8..e291196 100644
--- a/util/util.go
+++ b/util/util.go
@@ -13,10 +13,10 @@ 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"
+	"github.com/algorand/go-algorand-sdk/v2/protocol"
+	"github.com/algorand/go-algorand-sdk/v2/protocol/config"
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )
 


Test patch:
diff --git a/e2e_tests/README.md b/e2e_tests/README.md
index bd0fff4..a2d67bb 100644
--- a/e2e_tests/README.md
+++ b/e2e_tests/README.md
@@ -2,11 +2,12 @@
 
 An integration testing tool. It leverages an artifact generated by the go-algorand integration tests to ensure all features are exercised.
 
-# Usage
+## Usage
 
 A python virtual environment is highly encouraged.
 
-## Setup environment with venv
+### Setup environment with venv
+
 ```sh
 cd e2e_tests
 
@@ -22,8 +23,7 @@ python3 -m pip install .
 
 ## Running locally
 
-
-### e2elive
+### `e2elive`
 
 This tests runs the `algorand-indexer` binary. Depending on what you're doing, you may want to use a different value for `--s3-source-net`. After the test finishes, a few simple queries are executed.
 
@@ -33,16 +33,18 @@ This command requires a postgres database, you can run one in docker:
 docker run --rm -it --name some-postgres -p 5555:5432 -e POSTGRES_PASSWORD=pgpass -e POSTGRES_USER=pguser -e POSTGRES_DB=mydb postgres
 ```
 
-Running e2elive
+#### Running `e2elive`
 
 **Note**: you will need to restart this container between tests, otherwise the database will already be initialized. Being out of sync with the data directory may cause unexpected behavior and failing tests.
+
 ```sh
 e2elive --connection-string "host=127.0.0.1 port=5555 user=pguser password=pgpass dbname=mydb" --s3-source-net "fafa8862/rel-nightly" --indexer-bin ../cmd/algorand-indexer/algorand-indexer --indexer-port 9890
 ```
 
-### e2econduit
+### `e2econduit`
 
 This runs a series of pipeline scenarios with conduit. Each module manages its own resources and may have dependencies. For example the PostgreSQL exporter starts a docker container to initialize a database server.
+
 ```sh
 e2econduit --s3-source-net rel-nightly --conduit-bin ../cmd/conduit/conduit
 ```
@@ -64,39 +66,40 @@ 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 new Conduit e2e tests
+
+### Creating a new plugin fixture
 
-## 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.__
+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
+#### Main Methods of PluginFixtures
 
-* `name`  
+* `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(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`  
+* `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`  
+* `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
 
-## 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,
 
-```
+```go
 Scenario(
         "app_filter_indexer_scenario",
         importer=importers.FollowerAlgodImporter(sourcenet),
diff --git a/e2e_tests/docker/indexer-filtered/e2e-read/Dockerfile b/e2e_tests/docker/indexer-filtered/e2e-read/Dockerfile
index 4bbdff8..c1e7f27 100644
--- a/e2e_tests/docker/indexer-filtered/e2e-read/Dockerfile
+++ b/e2e_tests/docker/indexer-filtered/e2e-read/Dockerfile
@@ -21,4 +21,4 @@ RUN pip3 install ./
 ENV INDEXER_DATA="${HOME}/indexer/"
 WORKDIR /opt/go/indexer
 # Run test script
-ENTRYPOINT ["/bin/bash", "-c", "sleep 5 && e2elive $EXTRA --connection-string \"$CONNECTION_STRING\" --indexer-bin /opt/go/indexer/cmd/algorand-indexer/algorand-indexer --indexer-port 9890 --read-only True --verbose"]
+ENTRYPOINT ["/bin/bash", "-c", "env && sleep 5 && e2elive $EXTRA --connection-string \"$CONNECTION_STRING\" --indexer-bin /opt/go/indexer/cmd/algorand-indexer/algorand-indexer --indexer-port 9890 --read-only True --verbose"]
diff --git a/e2e_tests/docker/indexer-filtered/e2e-write/Dockerfile b/e2e_tests/docker/indexer-filtered/e2e-write/Dockerfile
index dc8b3b6..29c8f28 100644
--- a/e2e_tests/docker/indexer-filtered/e2e-write/Dockerfile
+++ b/e2e_tests/docker/indexer-filtered/e2e-write/Dockerfile
@@ -25,7 +25,7 @@ WORKDIR /opt/go/indexer
 RUN make
 ENV PATH="${HOME}/go/bin/:${PATH}"
 WORKDIR /opt/go
-RUN git clone https://github.com/algorand/conduit
+RUN git clone --depth 1 -b master https://github.com/algorand/conduit
 WORKDIR /opt/go/conduit
 RUN make
 WORKDIR /opt/go/indexer/e2e_tests
@@ -37,10 +37,14 @@ WORKDIR /opt/go/indexer
 # Retrieve the network data
 RUN get-test-data --s3-source-net ${CI_E2E_FILENAME} --algod-dir /opt/algod-dir
 
+RUN echo "Channel: $CHANNEL"
+RUN echo "AWS tarball: $CI_E2E_FILENAME"
+
 # Run test script
 CMD ["/bin/bash", "-c", \
-"goal network start -r /opt/algod-dir/net/ && \
-export ALGOD_ADDR=http://$(cat /opt/algod-dir/net/Node/algod.net) && \
-export ALGOD_TOKEN=$(cat /opt/algod-dir/net/Node/algod.token) && \
-cat ./e2e_tests/docker/indexer-filtered/e2e-write/conduit.yml | envsubst > /opt/conduit-dir/conduit.yml && \
-/opt/go/conduit/cmd/conduit/conduit -d /opt/conduit-dir"]
+    "env && \
+    goal network start -r /opt/algod-dir/net/ && \
+    export ALGOD_ADDR=http://$(cat /opt/algod-dir/net/Node/algod.net) && \
+    export ALGOD_TOKEN=$(cat /opt/algod-dir/net/Node/algod.token) && \
+    cat ./e2e_tests/docker/indexer-filtered/e2e-write/conduit.yml | envsubst > /opt/conduit-dir/conduit.yml && \
+    /opt/go/conduit/cmd/conduit/conduit -d /opt/conduit-dir"]
diff --git a/e2e_tests/docker/indexer/Dockerfile b/e2e_tests/docker/indexer/Dockerfile
index e97b978..b3c4772 100644
--- a/e2e_tests/docker/indexer/Dockerfile
+++ b/e2e_tests/docker/indexer/Dockerfile
@@ -22,7 +22,7 @@ WORKDIR /opt/go/indexer
 RUN make
 ENV PATH="${HOME}/go/bin/:${PATH}"
 WORKDIR /opt/go
-RUN git clone https://github.com/algorand/conduit
+RUN git clone --depth 1 -b master https://github.com/algorand/conduit
 WORKDIR /opt/go/conduit
 RUN make
 WORKDIR /opt/go/indexer/e2e_tests
@@ -31,5 +31,8 @@ RUN mkdir -p /opt/tmp-conduit && cp /opt/go/indexer/e2e_tests/docker/indexer/con
 
 ENV INDEXER_DATA="${HOME}/indexer/"
 WORKDIR /opt/go/indexer
+
+RUN echo "Channel: $CHANNEL"
+
 # Run test script
-ENTRYPOINT ["/bin/bash", "-c", "sleep 5 && e2elive $EXTRA --connection-string \"$CONNECTION_STRING\" --s3-source-net \"$CI_E2E_FILENAME\" --indexer-bin /opt/go/indexer/cmd/algorand-indexer/algorand-indexer --indexer-port 9890 --conduit-bin /opt/go/conduit/cmd/conduit/conduit --conduit-dir /opt/tmp-conduit"]
+ENTRYPOINT ["/bin/bash", "-c", "env && sleep 5 && e2elive $EXTRA --connection-string \"$CONNECTION_STRING\" --s3-source-net \"$CI_E2E_FILENAME\" --indexer-bin /opt/go/indexer/cmd/algorand-indexer/algorand-indexer --indexer-port 9890 --conduit-bin /opt/go/conduit/cmd/conduit/conduit --conduit-dir /opt/tmp-conduit"]
diff --git a/e2e_tests/src/e2e_common/util.py b/e2e_tests/src/e2e_common/util.py
index 599e594..cbad965 100644
--- a/e2e_tests/src/e2e_common/util.py
+++ b/e2e_tests/src/e2e_common/util.py
@@ -78,6 +78,7 @@ def xrun(cmd, *args, **kwargs):
     kwargs["stderr"] = subprocess.STDOUT
     cmdr = " ".join(map(repr, cmd))
     try:
+        logger.debug(f"subprocess.Popen({cmdr, args, kwargs})")
         p = subprocess.Popen(cmd, *args, **kwargs)
     except Exception as e:
         logger.error("subprocess failed {}".format(cmdr), exc_info=True)
@@ -121,6 +122,28 @@ def xrun(cmd, *args, **kwargs):
         )
 
 
+def nxrun(func, **kwargs):
+    """
+    nxrun = NOT xrun
+    Like xrun but for executing python code and to
+        * call directly
+        * without a timeout
+        * with **kwargs only
+
+    NOTE: xrun has the advantage of shielding the caller from any side effects. So be aware when choosing nxrun over xrun
+    """
+    fname = func.__name__
+    try:
+        result = func(**kwargs)
+        if result > 0:
+            logger.error(msg := f"Non-zero return code {result} = {fname}({kwargs=})")
+            raise Exception(msg)
+    except Exception as e:
+        logger.error(f"Exception in {fname}({kwargs=}): {e}", exc_info=True)
+        raise
+    return 0
+
+
 def atexitrun(cmd, *args, **kwargs):
     cargs = [cmd] + list(args)
     atexit.register(xrun, *cargs, **kwargs)
@@ -148,7 +171,9 @@ def ensure_test_db(connection_string, keep_temps=False):
         return connection_string
     # create a temporary database
     dbname = "e2eindex_{}_{}".format(int(time.time()), random.randrange(1000))
+    logger.debug(f'xrun: {"dropdb", "--if-exists", dbname}')
     xrun(["dropdb", "--if-exists", dbname], timeout=5)
+    logger.debug(f'xrun: {"createdb", dbname}')
     xrun(["createdb", dbname], timeout=5)
     if not keep_temps:
         atexitrun(["dropdb", "--if-exists", dbname], timeout=5)
@@ -182,7 +207,7 @@ def firstFromS3Prefix(
             break
 
     if not found_needle:
-        logger.warning("file {} not found in s3://{}/{}".format(desired_filename, bucket, prefix))
+        logger.warning(f"file {desired_filename} not found in s3://{bucket}/{prefix}")
     return found_needle
 
 
diff --git a/e2e_tests/src/e2e_indexer/e2elive.py b/e2e_tests/src/e2e_indexer/e2elive.py
index 8e03a46..7876879 100644
--- a/e2e_tests/src/e2e_indexer/e2elive.py
+++ b/e2e_tests/src/e2e_indexer/e2elive.py
@@ -1,7 +1,9 @@
 #!/usr/bin/env python3
 import atexit
+import functools
 import glob
 import gzip
+import inspect
 import io
 import json
 import logging
@@ -15,7 +17,9 @@ import threading
 import time
 import urllib.request
 
+import e2e_common.util
 from e2e_common.util import (
+    nxrun,
     xrun,
     atexitrun,
     find_binary,
@@ -24,63 +28,25 @@ from e2e_common.util import (
     hassuffix,
     countblocks,
 )
+import e2e_indexer.validate_accounting
+from e2e_indexer.validate_accounting import logger as va_logger, validate_accounting
 
 logger = logging.getLogger(__name__)
 
 
 def main():
     start = time.time()
-    import argparse
 
-    ap = argparse.ArgumentParser()
-    ap.add_argument("--keep-temps", default=False, action="store_true")
-    # keep alive is convenient in docker environments to prevent exiting after an error
-    ap.add_argument("--keep-alive", default=False, action="store_true")
-    ap.add_argument(
-        "--indexer-bin",
-        default=None,
-        help="path to algorand-indexer binary, otherwise search PATH",
-    )
-    ap.add_argument(
-        "--indexer-port",
-        default=None,
-        type=int,
-        help="port to run indexer on. defaults to random in [4000,30000]",
-    )
-    ap.add_argument(
-        "--conduit-bin",
-        default=None,
-        help="path to the conduit binary, otherwise search PATH"
-    )
-    ap.add_argument(
-        "--conduit-dir",
-        default=None,
-        help="Path to the directory in which to run conduit. Required when not read-only."
-    )
-    ap.add_argument(
-        "--connection-string",
-        help="Use this connection string instead of attempting to manage a local database.",
-    )
-    ap.add_argument(
-        "--source-net",
-        help="Path to test network directory containing Primary and other nodes. May be a tar file.",
-    )
-    ap.add_argument(
-        "--s3-source-net",
-        help="AWS S3 key suffix to test network tarball containing Primary and other nodes. Must be a tar bz2 file.",
-    )
-    ap.add_argument(
-        "--read-only",
-        default=False,
-        type=bool,
-        help="Run the indexer daemon in read-only mode.",
-    )
-    ap.add_argument("--verbose", default=False, action="store_true")
-    args = ap.parse_args()
+    args = get_args()
     if args.verbose:
         logging.basicConfig(level=logging.DEBUG)
+        wrap_funcs(sys.modules[__name__])
+        wrap_funcs(e2e_common.util)
+        wrap_funcs(e2e_indexer.validate_accounting)
     else:
         logging.basicConfig(level=logging.INFO)
+
+    logger.debug(f"{args=}")
     indexer_bin = find_binary(args.indexer_bin)
     tempdir = tempfile.mkdtemp()
     if not args.keep_temps:
@@ -93,7 +59,16 @@ def main():
     if args.keep_alive:
         # register after keep_temps so that the temp files are still there.
         atexitrun(["sleep", "infinity"])
+
     psqlstring = ensure_test_db(args.connection_string, args.keep_temps)
+
+    conduitout = None
+    if not args.read_only:
+        lastblock, algoddir, conduitout = prep_and_run_conduit(
+            args, tempdir, psqlstring
+        )
+        time.sleep(5)
+
     aiport = args.indexer_port or random.randint(4000, 30000)
     cmd = [
         indexer_bin,
@@ -104,25 +79,7 @@ def main():
         "--server",
         ":{}".format(aiport),
     ]
-    conduitout = None
-    if not args.read_only:
-        conduit_bin = find_binary(args.conduit_bin, binary_name="conduit")
-        if not args.conduit_dir:
-            raise Exception("Must provide --conduit-dir when not readonly")
-        tempnet, lastblock = setup_algod(tempdir, args.source_net, args.s3_source_net)
-        algoddir = os.path.join(tempnet, "Node")
-        with open(os.path.join(algoddir, "algod.token"), "r") as token_file:
-            algod_token = token_file.read()
-        with open(os.path.join(algoddir, "algod.net"), "r") as net_file:
-            algod_net = net_file.read()
-        cfg = None
-        with open(os.path.join(args.conduit_dir, "conduit.yml"), "r") as conduit_cfg:
-            cfg = conduit_cfg.read()
-        cfg = cfg.format(ALGOD_ADDR=algod_net, ALGOD_TOKEN=algod_token, CONNECTION_STRING=psqlstring)
-        with open(os.path.join(args.conduit_dir, "conduit.yml"), "w") as conduit_cfg:
-            conduit_cfg.write(cfg)
-        conduitout = run_conduit(conduit_bin, args.conduit_dir, algod_token, algod_net)
-        time.sleep(5)
+
     logger.debug("%s", " ".join(map(repr, cmd)))
     indexerdp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     indexerout = subslurp(indexerdp.stdout)
@@ -151,17 +108,7 @@ def main():
     try:
         logger.info("reached expected round={}".format(lastblock))
         if not args.read_only:
-            xrun(
-                [
-                    "validate-accounting",
-                    "--verbose",
-                    "--algod",
-                    algoddir,
-                    "--indexer",
-                    indexerurl,
-                ],
-                timeout=20,
-            )
+            nxrun(validate_accounting, verbose=True, algod=algoddir, indexer=indexerurl)
         xrun(
             ["go", "run", "cmd/e2equeries/main.go", "-pg", psqlstring, "-q"], timeout=15
         )
@@ -176,6 +123,56 @@ def main():
     return 0
 
 
+def get_args():
+    import argparse
+
+    ap = argparse.ArgumentParser()
+    ap.add_argument("--keep-temps", default=False, action="store_true")
+    # keep alive is convenient in docker environments to prevent exiting after an error
+    ap.add_argument("--keep-alive", default=False, action="store_true")
+    ap.add_argument(
+        "--indexer-bin",
+        default=None,
+        help="path to algorand-indexer binary, otherwise search PATH",
+    )
+    ap.add_argument(
+        "--indexer-port",
+        default=None,
+        type=int,
+        help="port to run indexer on. defaults to random in [4000,30000]",
+    )
+    ap.add_argument(
+        "--conduit-bin",
+        default=None,
+        help="path to the conduit binary, otherwise search PATH",
+    )
+    ap.add_argument(
+        "--conduit-dir",
+        default=None,
+        help="Path to the directory in which to run conduit. Required when not read-only.",
+    )
+    ap.add_argument(
+        "--connection-string",
+        help="Use this connection string instead of attempting to manage a local database.",
+    )
+    ap.add_argument(
+        "--source-net",
+        help="Path to test network directory containing Primary and other nodes. May be a tar file.",
+    )
+    ap.add_argument(
+        "--s3-source-net",
+        help="AWS S3 key suffix to test network tarball containing Primary and other nodes. Must be a tar bz2 file.",
+    )
+    ap.add_argument(
+        "--read-only",
+        default=False,
+        type=bool,
+        help="Run the indexer daemon in read-only mode.",
+    )
+    ap.add_argument("--verbose", default=False, action="store_true")
+    return ap.parse_args()
+
+
 def setup_algod(tempdir, sourcenet, s3_source_net):
     source_is_tar = False
     if not sourcenet:
@@ -202,8 +199,8 @@ def setup_algod(tempdir, sourcenet, s3_source_net):
         if "/" in tarname:
             cmhash_tarnme = tarname.split("/")
             cmhash = cmhash_tarnme[0]
-            tarname =cmhash_tarnme[1]
-            prefix+="/"+cmhash
+            tarname = cmhash_tarnme[1]
+            prefix += "/" + cmhash
             tarpath = os.path.join(tempdir, tarname)
         else:
             tarpath = os.path.join(tempdir, tarname)
@@ -224,16 +221,17 @@ def setup_algod(tempdir, sourcenet, s3_source_net):
         os.path.join(tempdir, "net", "Primary", "*", "*.block.sqlite")
     )
     lastblock = countblocks(blockfiles[0])
+    logger.info(f"lastblock in downloaded network is {lastblock}")
     # Reset the secondary node, and enable follow mode.
     # This is what conduit will connect to for data access.
-    for root, dirs, files in os.walk(os.path.join(tempnet, 'Node', 'tbd-v1')):
+    for root, dirs, files in os.walk(os.path.join(tempnet, "Node", "tbd-v1")):
         for f in files:
             if ".sqlite" in f:
                 os.remove(os.path.join(root, f))
     cf = {}
     with open(os.path.join(tempnet, "Node", "config.json"), "r") as config_file:
         cf = json.load(config_file)
-        cf['EnableFollowMode'] = True
+        cf["EnableFollowMode"] = True
     with open(os.path.join(tempnet, "Node", "config.json"), "w") as config_file:
         config_file.write(json.dumps(cf))
     try:
@@ -241,7 +239,10 @@ def setup_algod(tempdir, sourcenet, s3_source_net):
     except Exception:
         logger.error("failed to start private network, looking for node.log")
         found = False
-        log_files = ("node.log", "algod-err.log",)
+        log_files = (
+            "node.log",
+            "algod-err.log",
+        )
         for root, dirs, files in os.walk(tempnet):
             for f in files:
                 if f in log_files:
@@ -277,9 +278,37 @@ def tryhealthurl(healthurl, verbose=False, waitforround=200):
         return (False, "")
 
 
+def prep_and_run_conduit(args, tempdir, psqlstring):
+    conduit_bin = find_binary(args.conduit_bin, binary_name="conduit")
+    if not args.conduit_dir:
+        raise Exception("Must provide --conduit-dir when not readonly")
+    tempnet, lastblock = setup_algod(tempdir, args.source_net, args.s3_source_net)
+    algoddir = os.path.join(tempnet, "Node")
+    with open(os.path.join(algoddir, "algod.token"), "r") as token_file:
+        algod_token = token_file.read()
+    with open(os.path.join(algoddir, "algod.net"), "r") as net_file:
+        algod_net = net_file.read()
+    cfg = None
+    with open(os.path.join(args.conduit_dir, "conduit.yml"), "r") as conduit_cfg:
+        cfg = conduit_cfg.read()
+    cfg = cfg.format(
+        ALGOD_ADDR=algod_net, ALGOD_TOKEN=algod_token, CONNECTION_STRING=psqlstring
+    )
+    with open(os.path.join(args.conduit_dir, "conduit.yml"), "w") as conduit_cfg:
+        conduit_cfg.write(cfg)
+    conduitout = run_conduit(conduit_bin, args.conduit_dir, algod_token, algod_net)
+    return lastblock, algoddir, conduitout
+
+
 def run_conduit(conduit_binary, conduit_dir, algod_token, algod_net):
-    conduitcmd = [conduit_binary, "-d", conduit_dir,]
-    conduitproc = subprocess.Popen(conduitcmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    conduitcmd = [
+        conduit_binary,
+        "-d",
+        conduit_dir,
+    ]
+    conduitproc = subprocess.Popen(
+        conduitcmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
+    )
     conduitout = subslurp(conduitproc.stdout)
     conduitout.start()
     atexit.register(conduitproc.kill)
@@ -316,5 +345,38 @@ class subslurp:
         self.t.start()
 
 
+def trace(func, lg):
+    @functools.wraps(func)
+    def wrapper(*args, **kwargs):
+        lg.debug(f"<<<<<Entering {func.__name__}>>>>>")
+        result = func(*args, **kwargs)
+        lg.debug(f"<<<<<Exiting {func.__name__}>>>>>")
+        return result
+
+    return wrapper
+
+
+def wrap_funcs(pymod):
+    is_va = pymod is e2e_indexer.validate_accounting
+    for name, obj in inspect.getmembers(pymod):
+        if inspect.isfunction(obj) and name not in (
+            "_dap",
+            "compare",
+            "deepeq",
+            "dictifyAppParams",
+            "main",
+            "maybedecode",
+            "remove_indexer_only_fields",
+            "trace",
+            "wrap_all_functions",
+        ):
+            print(f"wrapping {name}")
+            setattr(
+                pymod,
+                name,
+                trace(obj, va_logger if is_va else logger),
+            )
+
+
 if __name__ == "__main__":
     sys.exit(main())
diff --git a/e2e_tests/src/e2e_indexer/validate_accounting.py b/e2e_tests/src/e2e_indexer/validate_accounting.py
index e5f5214..21ab751 100644
--- a/e2e_tests/src/e2e_indexer/validate_accounting.py
+++ b/e2e_tests/src/e2e_indexer/validate_accounting.py
@@ -6,6 +6,7 @@
 #  pip install "msgpack >=1" py-algorand-sdk
 
 import base64
+from dataclasses import asdict, dataclass
 import json
 import logging
 import os
@@ -36,6 +37,89 @@ ssl_no_validate = None
 
 graceful_stop = False
 
+DEFAULT_MISMATCHES = 10
+DEFAULT_THREADS = 4
+
+
+@dataclass
+class Arguments:
+    algod: str = None
+    algod_net: str = None
+    algod_token: str = None
+    genesis: str = None
+    limit: int = None
+    indexer: str = None
+    indexer_token: str = None
+    asset: str = None
+    mismatches: int = DEFAULT_MISMATCHES
+    quiet: bool = False
+    verbose: bool = False
+    accounts: str = None
+    ssl_no_validate: bool = False
+    threads: int = DEFAULT_THREADS
+    gtaddr: str = None
+    shard: str = None
+
+    def asdict(self):
+        return asdict(self)
+
+
+def get_args() -> Arguments:
+    import argparse
+
+    ap = argparse.ArgumentParser()
+    ap.add_argument("-d", "--algod", default=None, help="algorand data dir")
+    ap.add_argument("--algod-net", default=None, help="algod host:port")
+    ap.add_argument("--algod-token", default=None, help="algod token")
+    ap.add_argument("--genesis", default=None, help="path to genesis.json")
+    ap.add_argument(
+        "--limit", default=None, type=int, help="debug limit number of accoutns to dump"
+    )
+    ap.add_argument("--indexer", default=None, help="URL to indexer to fetch from")
+    ap.add_argument("--indexer-token", default=None, help="indexer API token")
+    ap.add_argument(
+        "--asset", default=None, help="filter on accounts possessing asset id"
+    )
+    ap.add_argument(
+        "--mismatches",
+        default=DEFAULT_MISMATCHES,
+        type=int,
+        help="max number of mismatches to show details on (0 for no limit)",
+    )
+    # Dohhh... so which is it: quiet or verbose?
+    # TODO: only keep one of these
+    ap.add_argument("-q", "--quiet", default=False, action="store_true")
+    ap.add_argument("--verbose", default=False, action="store_true")
+    ap.add_argument("--accounts", help="comma separated list of accounts to test")
+    ap.add_argument("--ssl-no-validate", default=False, action="store_true")
+    ap.add_argument(
+        "--threads",
+        default=DEFAULT_THREADS,
+        type=int,
+        help="number of request-compare threads to run",
+    )
+    ap.add_argument("--gtaddr", default=None, help="fetch accounts after this addr")
+    ap.add_argument("--shard", default=None, help="a/b for a in [1..b]")
+    args = ap.parse_args()
+    return Arguments(
+        algod=args.algod,
+        algod_net=args.algod_net,
+        algod_token=args.algod_token,
+        genesis=args.genesis,
+        limit=args.limit,
+        indexer=args.indexer,
+        indexer_token=args.indexer_token,
+        asset=args.asset,
+        mismatches=args.mismatches,
+        quiet=args.quiet,
+        verbose=args.verbose,
+        accounts=args.accounts,
+        ssl_no_validate=args.ssl_no_validate,
+        threads=args.threads,
+        gtaddr=args.gtaddr,
+        shard=args.shard,
+    )
+
 
 def do_graceful_stop(signum, frame):
     global graceful_stop
@@ -656,6 +740,7 @@ def token_addr_from_args(args):
         token = args.algod_token
     if not addr.startswith("http"):
         addr = "http://" + addr
+    logger.info(f"algod {addr=} {token=}")
     return token, addr
 
 
@@ -665,6 +750,9 @@ def compare(indexer_account, i2a_checker, algod, indexer, indexer_headers):
         return
     algod_account = algod.account_info(niceaddr)
     if algod_account["round"] != indexer_account["round"]:
+        logger.warning(
+            f'round mismatch: {algod_account["round"]=} VS {indexer_account["round"]=}: {niceaddr=}'
+        )
         indexer_account = indexerAccountFromAddr(
             indexer,
             niceaddr,
@@ -788,42 +876,10 @@ def check_from_algod(args):
     return i2a_checker
 
 
-def main():
-    import argparse
-
-    ap = argparse.ArgumentParser()
-    ap.add_argument("-d", "--algod", default=None, help="algorand data dir")
-    ap.add_argument("--algod-net", default=None, help="algod host:port")
-    ap.add_argument("--algod-token", default=None, help="algod token")
-    ap.add_argument("--genesis", default=None, help="path to genesis.json")
-    ap.add_argument(
-        "--limit", default=None, type=int, help="debug limit number of accoutns to dump"
-    )
-    ap.add_argument("--indexer", default=None, help="URL to indexer to fetch from")
-    ap.add_argument("--indexer-token", default=None, help="indexer API token")
-    ap.add_argument(
-        "--asset", default=None, help="filter on accounts possessing asset id"
-    )
-    ap.add_argument(
-        "--mismatches",
-        default=10,
-        type=int,
-        help="max number of mismatches to show details on (0 for no limit)",
-    )
-    ap.add_argument("-q", "--quiet", default=False, action="store_true")
-    ap.add_argument("--verbose", default=False, action="store_true")
-    ap.add_argument("--accounts", help="comma separated list of accounts to test")
-    ap.add_argument("--ssl-no-validate", default=False, action="store_true")
-    ap.add_argument(
-        "--threads",
-        default=4,
-        type=int,
-        help="number of request-compare threads to run",
-    )
-    ap.add_argument("--gtaddr", default=None, help="fetch accounts after this addr")
-    ap.add_argument("--shard", default=None, help="a/b for a in [1..b]")
-    args = ap.parse_args()
+def validate_accounting(**kwargs) -> int:
+    logger.info(f"Begin validate_accounting with {kwargs=}")
 
+    args = Arguments(**kwargs)
     if args.verbose:
         logging.basicConfig(level=logging.DEBUG)
     else:
@@ -843,7 +899,6 @@ def main():
     if args.gtaddr and args.shard:
         logger.error("--gtaddr and --shard are incompatible")
         return 1
-    out = sys.stdout
     err = sys.stderr
 
     i2a_checker = check_from_algod(args)
@@ -910,5 +965,10 @@ def main():
     return retval
 
 
+def main():
+    args = get_args()
+    return validate_accounting(**args.asdict())
+
+
 if __name__ == "__main__":
     sys.exit(main())
diff --git a/idb/postgres/internal/encoding/encoding_test.go b/idb/postgres/internal/encoding/encoding_test.go
index ac5b93b..ca7fc1c 100644
--- a/idb/postgres/internal/encoding/encoding_test.go
+++ b/idb/postgres/internal/encoding/encoding_test.go
@@ -1,6 +1,7 @@
 package encoding
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/algorand/go-algorand-sdk/v2/encoding/msgpack"
@@ -227,16 +228,26 @@ func TestBlockHeaderEncoding(t *testing.T) {
 			FeeSink:     newaddr(),
 			RewardsPool: newaddr(),
 		},
+		ParticipationUpdates: sdk.ParticipationUpdates{
+			ExpiredParticipationAccounts: []sdk.Address{newaddr()},
+		},
 	}
 
 	buf := EncodeBlockHeader(header)
 
-	expectedString := `{"fees":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","prev":"BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","rnd":3,"rwd":"AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}`
+	template := `{"fees":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","partupdrmv":["%s"],"prev":"BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","rnd":3,"rwd":"AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}`
+	expectedString := fmt.Sprintf(template, "AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANVWEXNA")
 	assert.Equal(t, expectedString, string(buf))
 
 	headerNew, err := DecodeBlockHeader(buf)
 	require.NoError(t, err)
 	assert.Equal(t, header, headerNew)
+
+	// Lenient decode from the corrupted data
+	badString := fmt.Sprintf(template, "AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
+	headerNewFromBad, err := DecodeBlockHeader([]byte(badString))
+	require.NoError(t, err)
+	assert.Equal(t, header, headerNewFromBad)
 }
 
 // Test that the encoding of byteArray in JSON is as expected and that decoding results in
diff --git a/idb/postgres/internal/writer/writer_test.go b/idb/postgres/internal/writer/writer_test.go
index 19a2903..2e232ad 100644
--- a/idb/postgres/internal/writer/writer_test.go
+++ b/idb/postgres/internal/writer/writer_test.go
@@ -1435,12 +1435,12 @@ func TestWriterAddBlockInnerTxnsAssetCreate(t *testing.T) {
 	// Inner pay 2
 	require.Equal(t, "", txns[2].txid)
 	require.Equal(t, expectedExtra, txns[2].extra)
-	require.NotContains(t, txns[2].txn, "itx", "The inner transactions should be pruned.")
+	require.NotContains(t, txns[2].txn, `"itx"`, "The inner transactions should be pruned.")
 
 	// Inner xfer
 	require.Equal(t, "", txns[3].txid)
 	require.Equal(t, expectedExtra, txns[3].extra)
-	require.NotContains(t, txns[3].txn, "itx", "The inner transactions should be pruned.")
+	require.NotContains(t, txns[3].txn, `"itx"`, "The inner transactions should be pruned.")
 
 	// Verify correct App and Asset IDs
 	require.Equal(t, 1, txns[0].asset, "intra == 0 -> ApplicationID = 1")
diff --git a/idb/postgres/postgres_boxes_test.go b/idb/postgres/postgres_boxes_test.go
index 906bf47..de57340 100644
--- a/idb/postgres/postgres_boxes_test.go
+++ b/idb/postgres/postgres_boxes_test.go
@@ -15,9 +15,10 @@ import (
 	"github.com/algorand/indexer/idb"
 	"github.com/algorand/indexer/idb/postgres/internal/encoding"
 	"github.com/algorand/indexer/idb/postgres/internal/writer"
-	"github.com/algorand/indexer/protocol"
-	"github.com/algorand/indexer/protocol/config"
 	"github.com/algorand/indexer/util/test"
+
+	"github.com/algorand/go-algorand-sdk/v2/protocol"
+	"github.com/algorand/go-algorand-sdk/v2/protocol/config"
 )
 
 type boxTestComparator func(t *testing.T, db *IndexerDb, appBoxes map[sdk.AppIndex]map[string]string,
diff --git a/idb/postgres/postgres_integration_test.go b/idb/postgres/postgres_integration_test.go
index 7bc8d5e..e60536f 100644
--- a/idb/postgres/postgres_integration_test.go
+++ b/idb/postgres/postgres_integration_test.go
@@ -26,11 +26,11 @@ import (
 	"github.com/algorand/indexer/idb/postgres/internal/schema"
 	pgtest "github.com/algorand/indexer/idb/postgres/internal/testing"
 	pgutil "github.com/algorand/indexer/idb/postgres/internal/util"
-	"github.com/algorand/indexer/protocol"
 	"github.com/algorand/indexer/util"
 	"github.com/algorand/indexer/util/test"
 
 	"github.com/algorand/go-algorand-sdk/v2/encoding/json"
+	"github.com/algorand/go-algorand-sdk/v2/protocol"
 	"github.com/algorand/go-codec/codec"
 )
 
diff --git a/util/test/account_testutil.go b/util/test/account_testutil.go
index f96bdfe..36187ae 100644
--- a/util/test/account_testutil.go
+++ b/util/test/account_testutil.go
@@ -5,11 +5,11 @@ import (
 	"fmt"
 	"math/rand"
 
-	"github.com/algorand/indexer/protocol"
-	"github.com/algorand/indexer/protocol/config"
 	"github.com/algorand/indexer/util"
 
 	"github.com/algorand/go-algorand-sdk/v2/encoding/msgpack"
+	"github.com/algorand/go-algorand-sdk/v2/protocol"
+	"github.com/algorand/go-algorand-sdk/v2/protocol/config"
 	sdk "github.com/algorand/go-algorand-sdk/v2/types"
 )