Through my investigation into why the new code base wasn't properly syncing with the Songbird network, I discovered that the Apricot Phase 3 hard fork has not been activated on the Songbird network, and will indeed never activate because it is disabled.
A timestamp of zero means that the fork is enabled from the start of the network.
However, the genesis file can not be modified after the initial network start, so newer forks were not included in the configuration of the C-Chain genesis file. In fact, Avalanche itself doesn't include any Apricot forks in the genesis file.
Unfortunately, in our previous repository, we did not update the chain ID in the Coreth repository. You would think that this would decode the value of the fork timestamp as zero, and thus enable the hard fork by default, but not so, see: https://github.com/ava-labs/coreth/blob/master/params/config.go#L158
// Apricot Phase 3 introduces dynamic fees and a modified version of the London Hard Fork from Ethereum (nil = no fork, 0 = already activated)
ApricotPhase3BlockTimestamp *big.Int `json:"apricotPhase3BlockTimestamp,omitempty"`
Pointers default to decoding as nil with the default Go JSON decoder, which disabled the hard fork. Hence, we are running on Apricot Phase 2 on the EVM of the Songbird network currently.
Through my investigation into why the new code base wasn't properly syncing with the Songbird network, I discovered that the Apricot Phase 3 hard fork has not been activated on the Songbird network, and will indeed never activate because it is disabled.
For past hard forks, their timing was defined in the configuration of the C-Chain genesis file, see: https://gitlab.com/flarenetwork/flare/-/blob/master/src/genesis/genesis_songbird.go#L23
A timestamp of zero means that the fork is enabled from the start of the network.
However, the genesis file can not be modified after the initial network start, so newer forks were not included in the configuration of the C-Chain genesis file. In fact, Avalanche itself doesn't include any Apricot forks in the genesis file.
Instead, they keep a separate instance of hard-coded fork configurations for each network in the Coreth repository, see: https://github.com/ava-labs/coreth/blob/master/params/config.go#L90
This chain configuration overwrites the configuration in the C-Chain genesis block if the network has one of the hard-coded chain IDs, see: https://github.com/ava-labs/coreth/blob/master/plugin/evm/vm.go#L300
However, the chain IDs are also redundantly defined in the Coreth repository, see: https://github.com/ava-labs/coreth/blob/master/params/config.go#L43
Unfortunately, in our previous repository, we did not update the chain ID in the Coreth repository. You would think that this would decode the value of the fork timestamp as zero, and thus enable the hard fork by default, but not so, see: https://github.com/ava-labs/coreth/blob/master/params/config.go#L158
Pointers default to decoding as
nil
with the default Go JSON decoder, which disabled the hard fork. Hence, we are running on Apricot Phase 2 on the EVM of the Songbird network currently.However, Apricot Phase 3 is activated from the point of view of the Avalanche repository, which is defined here: https://github.com/ava-labs/avalanchego/blob/master/version/constants.go#L48
Because on the Avalanche repository, the hard-coded fork configurations use the network IDs and are actually correctly defined, see: https://github.com/ava-labs/avalanchego/blob/master/utils/constants/network_ids.go#L20
My recommendation would be to plan for a full Apricot Phase 3 rollout as soon as possible.