From 311afc9f4d704af7393a76433b589cb103fa1751 Mon Sep 17 00:00:00 2001 From: Dusan Nosovic <118283942+dusannosovic-ethernal@users.noreply.github.com> Date: Mon, 11 Sep 2023 08:08:03 +0200 Subject: [PATCH] Fixed tests and new e2e test for `baseFeeChangeDenom` network parameter (#1901) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed tests and new e2e test for baseFeeDenom * comment fix * fix test `TestGovernanceManager_PostEpoch` * Fix unit tests * Fix unit test * fix governance e2e test * Minor updates --------- Co-authored-by: Stefan Negovanović --- blockchain/blockchain.go | 3 +- blockchain/blockchain_test.go | 7 ++ consensus/polybft/common/polybft_config.go | 4 - consensus/polybft/consensus_runtime_test.go | 20 ++-- consensus/polybft/contracts_initializer.go | 5 +- .../polybft/contractsapi/bindings-gen/main.go | 1 + .../polybft/contractsapi/contractsapi.go | 16 ++++ consensus/polybft/governance_manager.go | 12 ++- consensus/polybft/governance_manager_test.go | 93 ++++++++++--------- consensus/polybft/polybft.go | 2 +- consensus/polybft/sc_integration_test.go | 5 +- .../polybft/state_store_governance_test.go | 63 +++++++------ e2e-polybft/e2e/governance_test.go | 78 ++++++++++++++++ 13 files changed, 219 insertions(+), 90 deletions(-) diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index ff4803966d..cd7abdf321 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -12,7 +12,6 @@ import ( "github.com/0xPolygon/polygon-edge/blockchain/storage" "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/forkmanager" "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/types" @@ -1393,7 +1392,7 @@ func (b *Blockchain) CalculateBaseFee(parent *types.Header) uint64 { func (b *Blockchain) calcBaseFeeDelta(gasUsedDelta, parentGasTarget, baseFee uint64) uint64 { baseFeeChangeDenom := chain.BaseFeeChangeDenom - if forkmanager.GetInstance().IsForkEnabled(chain.Governance, b.Header().Number) { + if b.config.Params.Forks.IsActive(chain.Governance, b.Header().Number) { baseFeeChangeDenom = b.Config().BaseFeeChangeDenom } diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go index 94b1079f87..5fca0476ae 100644 --- a/blockchain/blockchain_test.go +++ b/blockchain/blockchain_test.go @@ -1403,6 +1403,13 @@ func TestBlockchain_CalculateBaseFee(t *testing.T) { }, } + blockchain.setCurrentHeader(&types.Header{ + Number: test.blockNumber + 1, + GasLimit: test.parentGasLimit, + GasUsed: test.parentGasUsed, + BaseFee: test.parentBaseFee, + }, big.NewInt(1)) + parent := &types.Header{ Number: test.blockNumber, GasLimit: test.parentGasLimit, diff --git a/consensus/polybft/common/polybft_config.go b/consensus/polybft/common/polybft_config.go index ae71539cb3..38b855d3f0 100644 --- a/consensus/polybft/common/polybft_config.go +++ b/consensus/polybft/common/polybft_config.go @@ -56,10 +56,6 @@ type PolyBFTConfig struct { // WithdrawalWaitPeriod indicates a number of epochs after which withdrawal can be done from child chain WithdrawalWaitPeriod uint64 `json:"withdrawalWaitPeriod,omitempty"` - // TODO: @Stefan-Ethernal REMOVE! - // BaseFeeChangeDenom is the value to bound the amount the base fee can change between blocks - BaseFeeChangeDenom uint64 `json:"baseFeeChangeDenom,omitempty"` - // RewardConfig defines rewards configuration RewardConfig *RewardsConfig `json:"rewardConfig"` diff --git a/consensus/polybft/consensus_runtime_test.go b/consensus/polybft/consensus_runtime_test.go index 0aa25adf8b..67d131bc8d 100644 --- a/consensus/polybft/consensus_runtime_test.go +++ b/consensus/polybft/consensus_runtime_test.go @@ -215,10 +215,10 @@ func TestConsensusRuntime_OnBlockInserted_EndOfEpoch(t *testing.T) { txPool.On("ResetWithHeaders", mock.Anything).Once() snapshot := NewProposerSnapshot(epochSize-1, validatorSet) + polybftCfg := &polyCommon.PolyBFTConfig{EpochSize: epochSize} config := &runtimeConfig{ - GenesisConfig: &polyCommon.PolyBFTConfig{ - EpochSize: epochSize, - }, + GenesisConfig: polybftCfg, + genesisParams: &chain.Params{Engine: map[string]interface{}{polyCommon.ConsensusName: polybftCfg}}, blockchain: blockchainMock, polybftBackend: polybftBackendMock, txPool: txPool, @@ -238,11 +238,14 @@ func TestConsensusRuntime_OnBlockInserted_EndOfEpoch(t *testing.T) { FirstBlockInEpoch: header.Number - epochSize + 1, CurrentClientConfig: config.GenesisConfig, }, - lastBuiltBlock: &types.Header{Number: header.Number - 1}, - stateSyncManager: &dummyStateSyncManager{}, - checkpointManager: &dummyCheckpointManager{}, - stakeManager: &dummyStakeManager{}, - governanceManager: &dummyGovernanceManager{}, + lastBuiltBlock: &types.Header{Number: header.Number - 1}, + stateSyncManager: &dummyStateSyncManager{}, + checkpointManager: &dummyCheckpointManager{}, + stakeManager: &dummyStakeManager{}, + governanceManager: &dummyGovernanceManager{ + getClientConfigFn: func() (*chain.Params, error) { + return config.genesisParams, nil + }}, doubleSigningTracker: tracker, } runtime.OnBlockInserted(&types.FullBlock{Block: builtBlock}) @@ -490,6 +493,7 @@ func Test_NewConsensusRuntime(t *testing.T) { config := &runtimeConfig{ polybftBackend: polybftBackendMock, State: newTestState(t), + genesisParams: &chain.Params{Engine: map[string]interface{}{polyCommon.ConsensusName: polyBftConfig}}, GenesisConfig: polyBftConfig, DataDir: tmpDir, Key: createTestKey(t), diff --git a/consensus/polybft/contracts_initializer.go b/consensus/polybft/contracts_initializer.go index 2222bd1fc8..518fe9758d 100644 --- a/consensus/polybft/contracts_initializer.go +++ b/consensus/polybft/contracts_initializer.go @@ -280,7 +280,8 @@ func isNativeRewardToken(cfg common.PolyBFTConfig) bool { } // initNetworkParamsContract initializes NetworkParams contract on child chain -func initNetworkParamsContract(cfg common.PolyBFTConfig, transition *state.Transition) error { +func initNetworkParamsContract(baseFeeChangeDenom uint64, cfg common.PolyBFTConfig, + transition *state.Transition) error { initFn := &contractsapi.InitializeNetworkParamsFn{ InitParams: &contractsapi.InitParams{ // only timelock controller can execute transactions on network params @@ -293,12 +294,12 @@ func initNetworkParamsContract(cfg common.PolyBFTConfig, transition *state.Trans NewMinValidatorSetSize: new(big.Int).SetUint64(cfg.MinValidatorSetSize), NewMaxValidatorSetSize: new(big.Int).SetUint64(cfg.MaxValidatorSetSize), NewWithdrawalWaitPeriod: new(big.Int).SetUint64(cfg.WithdrawalWaitPeriod), - NewBaseFeeChangeDenom: new(big.Int).SetUint64(cfg.BaseFeeChangeDenom), NewBlockTime: new(big.Int).SetUint64(uint64(cfg.BlockTime.Duration)), NewBlockTimeDrift: new(big.Int).SetUint64(cfg.BlockTimeDrift), NewVotingDelay: new(big.Int).Set(cfg.GovernanceConfig.VotingDelay), NewVotingPeriod: new(big.Int).Set(cfg.GovernanceConfig.VotingPeriod), NewProposalThreshold: new(big.Int).Set(cfg.GovernanceConfig.ProposalThreshold), + NewBaseFeeChangeDenom: new(big.Int).SetUint64(baseFeeChangeDenom), }, } diff --git a/consensus/polybft/contractsapi/bindings-gen/main.go b/consensus/polybft/contractsapi/bindings-gen/main.go index d7ebfb7078..8bc388c119 100644 --- a/consensus/polybft/contractsapi/bindings-gen/main.go +++ b/consensus/polybft/contractsapi/bindings-gen/main.go @@ -419,6 +419,7 @@ func main() { "initialize", "setNewEpochSize", "setNewSprintSize", + "setNewBaseFeeChangeDenom", }, []string{ "NewCheckpointBlockInterval", diff --git a/consensus/polybft/contractsapi/contractsapi.go b/consensus/polybft/contractsapi/contractsapi.go index 894bfc62c1..56f483e43b 100644 --- a/consensus/polybft/contractsapi/contractsapi.go +++ b/consensus/polybft/contractsapi/contractsapi.go @@ -1767,6 +1767,22 @@ func (s *SetNewSprintSizeNetworkParamsFn) DecodeAbi(buf []byte) error { return decodeMethod(NetworkParams.Abi.Methods["setNewSprintSize"], buf, s) } +type SetNewBaseFeeChangeDenomNetworkParamsFn struct { + NewBaseFeeChangeDenom *big.Int `abi:"newBaseFeeChangeDenom"` +} + +func (s *SetNewBaseFeeChangeDenomNetworkParamsFn) Sig() []byte { + return NetworkParams.Abi.Methods["setNewBaseFeeChangeDenom"].ID() +} + +func (s *SetNewBaseFeeChangeDenomNetworkParamsFn) EncodeAbi() ([]byte, error) { + return NetworkParams.Abi.Methods["setNewBaseFeeChangeDenom"].Encode(s) +} + +func (s *SetNewBaseFeeChangeDenomNetworkParamsFn) DecodeAbi(buf []byte) error { + return decodeMethod(NetworkParams.Abi.Methods["setNewBaseFeeChangeDenom"], buf, s) +} + type NewCheckpointBlockIntervalEvent struct { CheckpointInterval *big.Int `abi:"checkpointInterval"` } diff --git a/consensus/polybft/governance_manager.go b/consensus/polybft/governance_manager.go index a202c78a7b..bfef5abd11 100644 --- a/consensus/polybft/governance_manager.go +++ b/consensus/polybft/governance_manager.go @@ -66,11 +66,17 @@ var _ GovernanceManager = (*dummyGovernanceManager)(nil) // dummyStakeManager is a dummy implementation of GovernanceManager interface // used only for unit testing -type dummyGovernanceManager struct{} +type dummyGovernanceManager struct { + getClientConfigFn func() (*chain.Params, error) +} func (d *dummyGovernanceManager) PostBlock(req *polyCommon.PostBlockRequest) error { return nil } func (d *dummyGovernanceManager) PostEpoch(req *polyCommon.PostEpochRequest) error { return nil } func (d *dummyGovernanceManager) GetClientConfig() (*chain.Params, error) { + if d.getClientConfigFn != nil { + return d.getClientConfigFn() + } + return nil, nil } @@ -369,6 +375,10 @@ func (g *governanceManager) PostEpoch(req *polyCommon.PostEpochRequest) error { } } + if len(eventsRaw) > 0 { + latestChainParams.Engine[polyCommon.ConsensusName] = latestPolybftConfig + } + // save updated config to db return g.state.GovernanceStore.insertClientConfig(latestChainParams) } diff --git a/consensus/polybft/governance_manager_test.go b/consensus/polybft/governance_manager_test.go index 9a960ec7c2..c310ccc7fe 100644 --- a/consensus/polybft/governance_manager_test.go +++ b/consensus/polybft/governance_manager_test.go @@ -15,44 +15,55 @@ import ( "github.com/umbracle/ethgo/abi" ) -// TODO: @Stefan-Ethernal FIXME -// func TestGovernanceManager_PostEpoch(t *testing.T) { -// t.Parallel() - -// state := newTestState(t) -// governanceManager := &governanceManager{ -// state: state, -// logger: hclog.NewNullLogger(), -// } - -// // insert some governance event -// epochRewardEvent := &contractsapi.NewEpochRewardEvent{Reward: big.NewInt(10_000)} -// require.NoError(t, state.GovernanceStore.insertGovernanceEvents(1, 7, []contractsapi.EventAbi{epochRewardEvent})) -// // insert last processed block -// require.NoError(t, state.GovernanceStore.insertLastProcessed(20)) - -// // no initial config was saved, so we expect an error -// require.ErrorIs(t, governanceManager.PostEpoch(&common.PostEpochRequest{ -// NewEpochID: 2, -// FirstBlockOfEpoch: 21, -// Forks: &chain.Forks{chain.Governance: chain.NewFork(0)}, -// }), -// errClientConfigNotFound) - -// // insert initial config -// require.NoError(t, state.GovernanceStore.insertClientConfig(createTestPolybftConfig())) - -// // PostEpoch will now update config with new epoch reward value -// require.NoError(t, governanceManager.PostEpoch(&common.PostEpochRequest{ -// NewEpochID: 2, -// FirstBlockOfEpoch: 21, -// Forks: &chain.Forks{chain.Governance: chain.NewFork(0)}, -// })) - -// updatedConfig, err := state.GovernanceStore.getClientConfig() -// require.NoError(t, err) -// require.Equal(t, epochRewardEvent.Reward.Uint64(), updatedConfig.EpochReward) -// } +func TestGovernanceManager_PostEpoch(t *testing.T) { + t.Parallel() + + state := newTestState(t) + governanceManager := &governanceManager{ + state: state, + logger: hclog.NewNullLogger(), + } + + // insert some governance event + baseFeeChangeDenomEvent := &contractsapi.NewBaseFeeChangeDenomEvent{BaseFeeChangeDenom: big.NewInt(100)} + epochRewardEvent := &contractsapi.NewEpochRewardEvent{Reward: big.NewInt(10000)} + + require.NoError(t, state.GovernanceStore.insertGovernanceEvents(1, 7, []contractsapi.EventAbi{baseFeeChangeDenomEvent, epochRewardEvent})) + // insert last processed block + require.NoError(t, state.GovernanceStore.insertLastProcessed(20)) + + // no initial config was saved, so we expect an error + require.ErrorIs(t, governanceManager.PostEpoch(&common.PostEpochRequest{ + NewEpochID: 2, + FirstBlockOfEpoch: 21, + Forks: &chain.Forks{chain.Governance: chain.NewFork(0)}, + }), + errClientConfigNotFound) + + params := &chain.Params{ + BaseFeeChangeDenom: 8, + Engine: map[string]interface{}{common.ConsensusName: createTestPolybftConfig()}, + } + + // insert initial config + require.NoError(t, state.GovernanceStore.insertClientConfig(params)) + + // PostEpoch will now update config with new epoch reward value + require.NoError(t, governanceManager.PostEpoch(&common.PostEpochRequest{ + NewEpochID: 2, + FirstBlockOfEpoch: 21, + Forks: &chain.Forks{chain.Governance: chain.NewFork(0)}, + })) + + updatedConfig, err := state.GovernanceStore.getClientConfig() + require.NoError(t, err) + require.Equal(t, baseFeeChangeDenomEvent.BaseFeeChangeDenom.Uint64(), updatedConfig.BaseFeeChangeDenom) + + pbftConfig, err := common.GetPolyBFTConfig(updatedConfig) + require.NoError(t, err) + + require.Equal(t, epochRewardEvent.Reward.Uint64(), pbftConfig.EpochReward) +} func TestGovernanceManager_PostBlock(t *testing.T) { t.Parallel() @@ -79,8 +90,7 @@ func TestGovernanceManager_PostBlock(t *testing.T) { Number: 0, }) - chainParams := &chain.Params{} - chainParams.Engine[common.ConsensusName] = genesisPolybftConfig + chainParams := &chain.Params{Engine: map[string]interface{}{common.ConsensusName: genesisPolybftConfig}} governanceManager, err := newGovernanceManager(chainParams, genesisPolybftConfig, hclog.NewNullLogger(), state, blockchainMock) require.NoError(t, err) @@ -126,8 +136,7 @@ func TestGovernanceManager_PostBlock(t *testing.T) { Number: 4, }) - chainParams := &chain.Params{} - chainParams.Engine[common.ConsensusName] = genesisPolybftConfig + chainParams := &chain.Params{Engine: map[string]interface{}{common.ConsensusName: genesisPolybftConfig}} governanceManager, err := newGovernanceManager(chainParams, genesisPolybftConfig, hclog.NewNullLogger(), state, blockchainMock) require.NoError(t, err) diff --git a/consensus/polybft/polybft.go b/consensus/polybft/polybft.go index 2938aa74bc..4ec6b1e192 100644 --- a/consensus/polybft/polybft.go +++ b/consensus/polybft/polybft.go @@ -151,7 +151,7 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st } // initialize NetworkParams SC - if err = initNetworkParamsContract(polyBFTConfig, transition); err != nil { + if err = initNetworkParamsContract(config.Params.BaseFeeChangeDenom, polyBFTConfig, transition); err != nil { return err } diff --git a/consensus/polybft/sc_integration_test.go b/consensus/polybft/sc_integration_test.go index ff85342d5f..45682a2917 100644 --- a/consensus/polybft/sc_integration_test.go +++ b/consensus/polybft/sc_integration_test.go @@ -264,6 +264,8 @@ func TestIntegratoin_PerformExit(t *testing.T) { func TestIntegration_CommitEpoch(t *testing.T) { t.Parallel() + baseFeeChangeDenom := uint64(25) + // init validator sets validatorSetSize := []int{5, 10, 50, 100} @@ -335,7 +337,6 @@ func TestIntegration_CommitEpoch(t *testing.T) { MaxValidatorSetSize: 100, CheckpointInterval: 900, WithdrawalWaitPeriod: 1, - BaseFeeChangeDenom: 20, BlockTimeDrift: 10, // use 1st account as governance address Governance: currentValidators.ToValidatorSet().Accounts().GetAddresses()[0], @@ -367,7 +368,7 @@ func TestIntegration_CommitEpoch(t *testing.T) { require.NoError(t, err) // init NetworkParams - err = initNetworkParamsContract(polyBFTConfig, transition) + err = initNetworkParamsContract(baseFeeChangeDenom, polyBFTConfig, transition) require.NoError(t, err) // create input for commit epoch diff --git a/consensus/polybft/state_store_governance_test.go b/consensus/polybft/state_store_governance_test.go index f433111241..1fcced6ab1 100644 --- a/consensus/polybft/state_store_governance_test.go +++ b/consensus/polybft/state_store_governance_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/0xPolygon/polygon-edge/chain" polyCommon "github.com/0xPolygon/polygon-edge/consensus/polybft/common" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" @@ -104,33 +105,40 @@ func TestGovernanceStore_InsertAndGetEvents(t *testing.T) { require.Equal(t, block+1, lastProcessedBlock) } -// TODO: FIX -// func TestGovernanceStore_InsertAndGetClientConfig(t *testing.T) { -// t.Parallel() - -// initialConfig := createTestPolybftConfig() -// state := newTestState(t) - -// // try get config when there is none -// _, err := state.GovernanceStore.getClientConfig() -// require.ErrorIs(t, err, errClientConfigNotFound) - -// // insert config -// require.NoError(t, state.GovernanceStore.insertClientConfig(initialConfig)) - -// // now config should exist -// configFromDB, err := state.GovernanceStore.getClientConfig() -// require.NoError(t, err) -// // check some fields to make sure they are as expected -// require.Len(t, configFromDB.InitialValidatorSet, len(initialConfig.InitialValidatorSet)) -// require.Equal(t, configFromDB.BlockTime, initialConfig.BlockTime) -// require.Equal(t, configFromDB.BlockTimeDrift, initialConfig.BlockTimeDrift) -// require.Equal(t, configFromDB.CheckpointInterval, initialConfig.CheckpointInterval) -// require.Equal(t, configFromDB.EpochReward, initialConfig.EpochReward) -// require.Equal(t, configFromDB.EpochSize, initialConfig.EpochSize) -// require.Equal(t, configFromDB.Governance, initialConfig.Governance) -// require.Equal(t, configFromDB.BaseFeeChangeDenom, initialConfig.BaseFeeChangeDenom) -// } +func TestGovernanceStore_InsertAndGetClientConfig(t *testing.T) { + t.Parallel() + + initialPolyConfig := createTestPolybftConfig() + initialConfig := &chain.Params{ + Engine: map[string]interface{}{polyCommon.ConsensusName: initialPolyConfig}, + BaseFeeChangeDenom: 16, + } + state := newTestState(t) + + // try get config when there is none + _, err := state.GovernanceStore.getClientConfig() + require.ErrorIs(t, err, errClientConfigNotFound) + + // insert config + require.NoError(t, state.GovernanceStore.insertClientConfig(initialConfig)) + + // now config should exist + configFromDB, err := state.GovernanceStore.getClientConfig() + require.NoError(t, err) + + polyConfigFromDB, err := polyCommon.GetPolyBFTConfig(configFromDB) + require.NoError(t, err) + + // check some fields to make sure they are as expected + require.Len(t, polyConfigFromDB.InitialValidatorSet, len(initialPolyConfig.InitialValidatorSet)) + require.Equal(t, polyConfigFromDB.BlockTime, initialPolyConfig.BlockTime) + require.Equal(t, polyConfigFromDB.BlockTimeDrift, initialPolyConfig.BlockTimeDrift) + require.Equal(t, polyConfigFromDB.CheckpointInterval, initialPolyConfig.CheckpointInterval) + require.Equal(t, polyConfigFromDB.EpochReward, initialPolyConfig.EpochReward) + require.Equal(t, polyConfigFromDB.EpochSize, initialPolyConfig.EpochSize) + require.Equal(t, polyConfigFromDB.Governance, initialPolyConfig.Governance) + require.Equal(t, configFromDB.BaseFeeChangeDenom, initialConfig.BaseFeeChangeDenom) +} func createTestPolybftConfig() *polyCommon.PolyBFTConfig { return &polyCommon.PolyBFTConfig{ @@ -195,7 +203,6 @@ func createTestPolybftConfig() *polyCommon.PolyBFTConfig { }, InitialTrieRoot: types.ZeroHash, WithdrawalWaitPeriod: 1, - BaseFeeChangeDenom: 20, RewardConfig: &polyCommon.RewardsConfig{ TokenAddress: types.StringToAddress("0xRewardTokenAddr"), WalletAddress: types.StringToAddress("0xRewardWalletAddr"), diff --git a/e2e-polybft/e2e/governance_test.go b/e2e-polybft/e2e/governance_test.go index e4c66b55c3..dfdd09351f 100644 --- a/e2e-polybft/e2e/governance_test.go +++ b/e2e-polybft/e2e/governance_test.go @@ -221,6 +221,84 @@ func TestE2E_Governance_ProposeAndExecuteSimpleProposal(t *testing.T) { polybftCfg.GovernanceConfig.ChildGovernorAddr, l2Relayer) require.Equal(t, Defeated, proposalState) }) + + t.Run("successful change of base fee denom", func(t *testing.T) { + var baseFee = uint64(215) + // propose a new base fee change denom + setNewBaseFeeDenomFn := &contractsapi.SetNewBaseFeeChangeDenomNetworkParamsFn{ + NewBaseFeeChangeDenom: big.NewInt(int64(baseFee)), + } + + proposalInput, err := setNewBaseFeeDenomFn.EncodeAbi() + require.NoError(t, err) + + proposalDescription := fmt.Sprintf("Change epoch size from %d to %d", oldEpochSize, newEpochSize) + + proposalID := sendProposalTransaction(t, l2Relayer, proposerAcc.Ecdsa, + polybftCfg.GovernanceConfig.ChildGovernorAddr, + polybftCfg.GovernanceConfig.NetworkParamsAddr, + proposalInput, proposalDescription) + + // check that proposal delay finishes, and porposal becomes active (ready to for voting) + require.NoError(t, cluster.WaitUntil(3*time.Minute, 2*time.Second, func() bool { + proposalState := getProposalState(t, proposalID, + polybftCfg.GovernanceConfig.ChildGovernorAddr, l2Relayer) + + return proposalState == Active + })) + + // vote for the proposal + for _, s := range cluster.Servers { + voterAcc, err := sidechain.GetAccountFromDir(s.DataDir()) + require.NoError(t, err) + + sendVoteTransaction(t, proposalID, For, polybftCfg.GovernanceConfig.ChildGovernorAddr, + l2Relayer, voterAcc.Ecdsa) + } + + // check if proposal has quorum (if it was accepted) + require.NoError(t, cluster.WaitUntil(3*time.Minute, 2*time.Second, func() bool { + proposalState := getProposalState(t, proposalID, + polybftCfg.GovernanceConfig.ChildGovernorAddr, l2Relayer) + + return proposalState == Succeeded + })) + + // queue proposal for execution + sendQueueProposalTransaction(t, l2Relayer, proposerAcc.Ecdsa, + polybftCfg.GovernanceConfig.ChildGovernorAddr, + polybftCfg.GovernanceConfig.NetworkParamsAddr, + proposalInput, proposalDescription) + + // check if proposal has quorum (if it was accepted) + require.NoError(t, cluster.WaitUntil(3*time.Minute, 2*time.Second, func() bool { + proposalState := getProposalState(t, proposalID, + polybftCfg.GovernanceConfig.ChildGovernorAddr, l2Relayer) + + return proposalState == Queued + })) + + currentBlockNumber, err := l2Relayer.Client().Eth().BlockNumber() + require.NoError(t, err) + + // wait for couple of more blocks because of execution delay + require.NoError(t, cluster.WaitForBlock(currentBlockNumber+2, 10*time.Second)) + + // execute proposal + sendExecuteProposalTransaction(t, l2Relayer, proposerAcc.Ecdsa, + polybftCfg.GovernanceConfig.ChildGovernorAddr, + polybftCfg.GovernanceConfig.NetworkParamsAddr, + proposalInput, proposalDescription) + + // check if base fee change denom changed on NetworkParams + networkParamsResponse, err := ABICall(l2Relayer, contractsapi.NetworkParams, + ethgo.Address(polybftCfg.GovernanceConfig.NetworkParamsAddr), ethgo.ZeroAddress, "baseFeeChangeDenom") + require.NoError(t, err) + + baseFeeDenomOnNetworkParams, err := common.ParseUint256orHex(&networkParamsResponse) + require.NoError(t, err) + require.Equal(t, baseFee, baseFeeDenomOnNetworkParams.Uint64()) + }) } func getProposalState(t *testing.T, proposalID *big.Int, childGovernorAddr types.Address,