Skip to content

Conversation

@JonathanOppenheimer
Copy link
Member

@JonathanOppenheimer JonathanOppenheimer commented Nov 3, 2025

Why this should be merged

This is phase 2 of the conversion from a npm/typescript based testing framework to a go based framework.

To start, let me provide some background: there are two basic approaches we could take here in transitioning the framework:

Option A: keep existing tmpnet infrastructure

  • Use existing tests/utils/subnet.go infrastructure
  • Deploy real subnet with precompile-enabled genesis
  • RPC
  • This is what TypeScript tests currently do

Option B: configure precompiles in libevm's simulated.Backend directly and test

  • More performant
  • No RPC/ginkgo

Upon investigation, I determined that Option B was not possible without modifications to libevm:

The libevm simulated backend always boots with the stock dev genesis (params.AllDevChainProtocolChanges) and never passes through any Avalanche-specific extras. You can see the hard-coded setup in libevm/ethclient/simulated/backend.go (NewBackend), where the default Genesis config is created with plain libevm params -- there’s no call into subnet-evm’s extras or precompile registration.

Even if we changed that to inject a subnet-evm ChainConfig, libevm’s core genesis logic has no idea what "GenesisPrecompiles" are. The go file in libevm simply initializes accounts and code; there’s no hook that walks the config and installs stateful precompiles. The subnet-evm tree explicitly does that work (it calls ApplyPrecompileActivations during genesis creation), but that function doesn’t exist in the libevm copy. Without it, the precompile contracts never get written to state, and as a result, every 0x0200… address still looks empty and the bindings revert with “no contract code”. I saw this first hand when trying to test it out.

In the absence of a better way to test these with libevm's simulated.Backend, I moved forward with Option A.

How this works

  • tests/precompile/contracttest/helpers.go - Test backend setup, utilities
  • tests/precompile/contracttest/roles.go - AllowList role management (needs tmpnet for precompiles)
  • tests/precompile/contracttest/tmpnet.go - Tmpnet/RPC backend helpers.
  • tests/precompile/contracttest/example_test.go - Examples (simulated backend)

I also migrated a single test contract_deployer_allow_list_test, as a proof of concept for this approach. I was largely able to match the format of the typescript test. Here is the mapping of tests to show no coverage was lost:

TypeScript Test Name Solidity Method Go Test Name
test("precompile should see owner address has admin role") step_verifySenderIsAdmin ginkgo.It("should verify deployer list shows admin has admin role via precompile")
test("precompile should see test address has no role") step_newAddressHasNoRole ginkgo.It("should verify new address has no role")
test("contract should report test address has no admin role") step_noRoleIsNotAdmin ginkgo.It("should verify contract correctly reports admin status") (partial)
test("contract should report owner address has admin role") step_ownerIsAdmin ginkgo.It("should verify contract correctly reports admin status") (combined)
test("should not let test address deploy") step_noRoleCannotDeploy ginkgo.It("should not let address with no role deploy contracts")
test("should allow admin to add contract as admin") step_adminAddContractAsAdmin ginkgo.It("should allow admin to add contract as admin via precompile")
test("should allow admin to add deployer address as deployer through contract") step_addDeployerThroughContract ginkgo.It("should allow admin to add deployer via contract")
test("should let deployer address to deploy") step_deployerCanDeploy ginkgo.It("should allow enabled address to deploy contracts")
test("should let admin revoke deployer") step_adminCanRevokeDeployer ginkgo.It("should allow admin to revoke deployer role")

I have also called out specific things of note via comments below. The next steps are to migrate each of the additional 6 tests, one at a time.

How this was tested

CI. We deliberately kept the Hardhat bridge in place so the TypeScript suites can run beside the new Go tests during migration. The tmpnet-backed Go suites (labeled Go) now execute via Ginkgo in CI, but RunHardhatTests() and the async TypeScript descriptors remain until Phase 3 completes the rewrites, and in Phase 4, we remove all the npm code in one go.

Need to be documented?

No

Need to update RELEASES.md?

No.

}

// TestAllowListRoles demonstrates role management
func TestAllowListRoles(t *testing.T) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test will fail as libevm's simulated backend has no visibility into subnetevm's precompiles, nor is there anyway to deploy them to libevm's simualted backend.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nor is there anyway to deploy them to libevm's simualted backend

Call evm.RegisterAllLibEVMExtras() in TestMain()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This not sufficient - see what I wrote in the original post. If you can get this test to work, I'd love to see it as that would allow us to get rid of the tmpnet stuff entirely.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this comment to Austin which hopefully provides more context to the original post:

#1830 (comment)

@JonathanOppenheimer JonathanOppenheimer changed the title Create Go Test Utilities feat: Add go test utilities for precompiles and migrate one test (Phase 2) Nov 3, 2025
@JonathanOppenheimer JonathanOppenheimer self-assigned this Nov 3, 2025
@JonathanOppenheimer JonathanOppenheimer added go Pull requests that update Go code testing This primarly focuses on testing labels Nov 3, 2025
@JonathanOppenheimer JonathanOppenheimer marked this pull request as ready for review November 3, 2025 22:12
@JonathanOppenheimer JonathanOppenheimer requested a review from a team as a code owner November 3, 2025 22:12
Copy link
Contributor

@alarso16 alarso16 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand your logic for eliminating option 2. We already use the custom subnet-evm/ethclient implementation everywhere in the repo because of the genesis differences, so why would you try and import the libevm implementation?

RewardManagerAddress = common.HexToAddress("0x0200000000000000000000000000000000000004")
WarpAddress = common.HexToAddress("0x0200000000000000000000000000000000000005")
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(note to self) Review the rest of the file, below this comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we testing against a tmpnet for any of this? The goal is just to confirm that the Solidity and the precompiles work properly together, which should be an integration and not an e2e test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my original PR, post, this comment thread , and my reply to Austin asking the same thing.

In short: personal skill issue. I don't think it works.

Copy link
Contributor

@ARR4N ARR4N left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub insists that I leave a comment ¯\_(ツ)_/¯

@JonathanOppenheimer
Copy link
Member Author

JonathanOppenheimer commented Nov 4, 2025

I'm not sure I understand your logic for eliminating option 2. We already use the custom subnet-evm/ethclient implementation everywhere in the repo because of the genesis differences, so why would you try and import the libevm implementation?

subnet-evm's backend uses subnet-evm's bind package, which is modified from libevm's bind package. However, there is no cmd/abigen (used to generate the bindings) package in subnet-evm. Since subnet-evm doesn't have its own abigen tool, we use libevm's instead, which generate bindings that import and use libevm's bind interfaces (which, of course lol) -- you can see our use in compile.go in this PR. This means that the bindings are not compatible with subnet-evm's bind package, and hence subnet-evm's simulated backend. Looking at the backends we see that:

libevm's bind.ContractTransactor:
https://github.com/ava-labs/libevm/blob/1bccf4f2ddb28ff440f9e24f46506a2e98ad2a0d/accounts/abi/bind/backend.go#L63-L69

subnet-evm's bind.ContractTransactor:

type AcceptedContractCaller interface {
// AcceptedCodeAt returns the code of the given account in the accepted state.
AcceptedCodeAt(ctx context.Context, contract common.Address) ([]byte, error)
// AcceptedCallContract executes an Ethereum contract call against the accepted state.
AcceptedCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error)
}

In summary:

  1. libevm's simulated backend (from github.com/ava-labs/libevm/ethclient/simulated):

    • Compatible with the generated bindings
    • Does not activate subnet-evm precompiles
    • Uses params.AllDevChainProtocolChanges (go-ethereum's dev config)
    • Never calls ApplyPrecompileActivations() during genesis
  2. subnet-evm's simulated backend (from github.com/ava-labs/subnet-evm/ethclient/simulated):

  • Not compatible with the generated bindings (different bind interface)
  • Activates subnet-evm precompiles via genesis
  • Uses params.TestChainConfig with subnet-evm extras
  • Calls ApplyPrecompileActivations() during core.Genesis.toBlock()

JonathanOppenheimer and others added 5 commits November 4, 2025 14:17
Co-authored-by: Arran Schlosberg <519948+ARR4N@users.noreply.github.com>
Signed-off-by: Jonathan Oppenheimer <147infiniti@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci go Pull requests that update Go code testing This primarly focuses on testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants