Skip to content

Conversation

@re-gius
Copy link

@re-gius re-gius commented Sep 9, 2025

Support genesis configuration customization for anvil-polkadot.
This is implemented through a wrapper struct around ChainSpec, called DevelopmentChainSpec, which re-implements assimilate_storage for the BuildStorage trait to override genesis storage for customizable items: chain id, block number, and timestamp.

For reference, also see #260 (comment)

Notice that there are still some missing genesis storage items to override: alloc (accounts with code/balances), coinbase (block author), gas settings.

@iulianbarbu iulianbarbu linked an issue Sep 15, 2025 that may be closed by this pull request
@re-gius re-gius marked this pull request as ready for review September 17, 2025 15:17
@re-gius
Copy link
Author

re-gius commented Sep 17, 2025

EDIT: actually, I don't see it's producing blocks, what I was seeing was probably the anvil config printed as string, not the genesis block storage. So I would say it's not working yet

@alindima
Copy link

alindima commented Sep 18, 2025

EDIT: actually, I don't see it's producing blocks, what I was seeing was probably the anvil config printed as string, not the genesis block storage. So I would say it's not working yet

After Alex's block production PR, we no longer start producing blocks by default. You either need to configure it via RPC or CLI. A simple way is to use the -b <block_interval> CLI param, which will produce a block every block_interval seconds

@alindima
Copy link

I tried customising the genesis block number but without success. When querying the numer from polkadot.js, I get <unknown>. Could it be because you are encoding it as u64 instead of u32?

Anyway, setting it in the genesis state is not going to be enough. The block builder uses the block number from the header of the genesis block (not from the runtime state). I think we need to implement another GenesisBlockBuilder (by implementing BuildGenesisBlock on a newtype), which uses the configured block number. See the construct_genesis_block function, this is the place where we set the block number to 0.

@alindima
Copy link

And for timestamp, we also need to modify the timestamp of the mining engine (similar to what the setTime RPC is doing), so that the next blocks will be based on this timestamp (otherwise they'll just jump right back to the present moment on the next block). CC: @AlexandruCihodaru

@iulianbarbu
Copy link

iulianbarbu commented Sep 19, 2025

And for timestamp, we also need to modify the timestamp of the mining engine (similar to what the setTime RPC is doing), so that the next blocks will be based on this timestamp (otherwise they'll just jump right back to the present moment on the next block). CC: @AlexandruCihodaru

Yeh, looks like block 1 references current time. I don't think we're able to tell what timestamp does block 0 reference, with polkadotjs (no extrinsic shows up in it, like in block 1 case, and the header doesn't seem to show this info either). Would be nice. Not sure how subscan shows it for the production networks.

@iulianbarbu
Copy link

iulianbarbu commented Sep 19, 2025

Anyway, setting it in the genesis state is not going to be enough. The block builder uses the block number from the header of the genesis block (not from the runtime state).

I am thinking we should set the genesis block number in the genesis block header too. Not sure though how doable it is.
LE: maybe that means we'll not need to reimplement the genesis block builder. On the plus side the info shown in polkadotjs will be in accordance with how the node was started.

use anvil_polkadot::config::{AnvilNodeConfig, SubstrateNodeConfig};

#[tokio::test(flavor = "multi_thread")]
async fn test_genesis() {
Copy link

Choose a reason for hiding this comment

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

we should also add a test for configuring via json file, but this can come later, in the next PR if you want

Copy link
Author

Choose a reason for hiding this comment

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

I can do it in the next PR for genesis accounts

Comment on lines +275 to +276
let latest_block_hash = self.backend.blockchain().info().best_hash;
Ok(self.chain_id(latest_block_hash))

Choose a reason for hiding this comment

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

nit: use eth_chain_id()

Copy link
Author

Choose a reason for hiding this comment

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

This is not working right now when we override the chain id in genesis config.

let Ok(supported_metadata_versions) =
substrate_service.client.runtime_api().metadata_versions(genesis_hash)
else {
return Err(Error::InvalidParams("Unable to fetch metadata versions".to_string()));

Choose a reason for hiding this comment

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

This and the subsequent errors feel more like an InternalError

Copy link
Author

Choose a reason for hiding this comment

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

Changed in 8915d00

@re-gius re-gius enabled auto-merge (squash) October 10, 2025 16:19
@re-gius re-gius merged commit cdc9c0e into master Oct 10, 2025
59 of 61 checks passed
@re-gius re-gius deleted the re-gius/chainspec-wrapper branch October 10, 2025 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Anvil] Genesis customisation

5 participants