@@ -2510,7 +2510,6 @@ func TestFeeManagerChangeFee(t *testing.T) {
25102510
25112511 block := blk .(* chain.BlockWrapper ).Block .(* Block ).ethBlock
25122512
2513- // Contract is initialized but no state is given, reader should return genesis fee config
25142513 feeConfig , lastChangedAt , err = vm .blockChain .GetFeeConfigAt (block .Header ())
25152514 require .NoError (t , err )
25162515 require .EqualValues (t , testHighFeeConfig , feeConfig )
@@ -3161,3 +3160,163 @@ func TestStandaloneDB(t *testing.T) {
31613160 assert .False (t , isDBEmpty (vm .db ))
31623161 assert .False (t , isDBEmpty (vm .acceptedBlockDB ))
31633162}
3163+
3164+ func TestFeeManagerRegressionMempoolMinFeeAfterRestart (t * testing.T ) {
3165+ // Setup chain params
3166+ genesis := & core.Genesis {}
3167+ if err := genesis .UnmarshalJSON ([]byte (genesisJSONSubnetEVM )); err != nil {
3168+ t .Fatal (err )
3169+ }
3170+ precompileActivationTime := utils .NewUint64 (genesis .Timestamp + 5 ) // 5 seconds after genesis
3171+ configExtra := params .GetExtra (genesis .Config )
3172+ configExtra .GenesisPrecompiles = extras.Precompiles {
3173+ feemanager .ConfigKey : feemanager .NewConfig (precompileActivationTime , testEthAddrs [0 :1 ], nil , nil , nil ),
3174+ }
3175+
3176+ // set a higher fee config now
3177+ testHighFeeConfig := commontype.FeeConfig {
3178+ GasLimit : big .NewInt (8_000_000 ),
3179+ TargetBlockRate : 5 , // in seconds
3180+
3181+ MinBaseFee : big .NewInt (50_000_000 ),
3182+ TargetGas : big .NewInt (18_000_000 ),
3183+ BaseFeeChangeDenominator : big .NewInt (3396 ),
3184+
3185+ MinBlockGasCost : big .NewInt (0 ),
3186+ MaxBlockGasCost : big .NewInt (4_000_000 ),
3187+ BlockGasCostStep : big .NewInt (500_000 ),
3188+ }
3189+
3190+ configExtra .FeeConfig = testHighFeeConfig
3191+ genesisJSON , err := genesis .MarshalJSON ()
3192+ if err != nil {
3193+ t .Fatal (err )
3194+ }
3195+ issuer , vm , sharedDB , appSender := GenesisVM (t , true , string (genesisJSON ), "" , "" )
3196+
3197+ // tx pool min base fee should be the high fee config
3198+ tx := types .NewTx (& types.DynamicFeeTx {
3199+ ChainID : genesis .Config .ChainID ,
3200+ Nonce : uint64 (0 ),
3201+ To : & feemanager .ContractAddress ,
3202+ Gas : 21_000 ,
3203+ Value : common .Big0 ,
3204+ GasFeeCap : big .NewInt (5_000_000 ), // give a lower base fee
3205+ GasTipCap : common .Big0 ,
3206+ Data : nil ,
3207+ })
3208+ signedTx , err := types .SignTx (tx , types .LatestSigner (genesis .Config ), testKeys [0 ])
3209+ require .NoError (t , err )
3210+
3211+ errs := vm .txPool .AddRemotesSync ([]* types.Transaction {signedTx })
3212+ require .Len (t , errs , 1 )
3213+ require .ErrorIs (t , errs [0 ], txpool .ErrUnderpriced ) // should fail because mempool expects higher fee
3214+
3215+ // restart vm and try again
3216+ genesisBytes := buildGenesisTest (t , string (genesisJSON ))
3217+ restartedVM , err := restartVM (vm , sharedDB , genesisBytes , issuer , appSender , true )
3218+ require .NoError (t , err )
3219+
3220+ // it still should fail
3221+ errs = restartedVM .txPool .AddRemotesSync ([]* types.Transaction {signedTx })
3222+ require .Len (t , errs , 1 )
3223+ require .ErrorIs (t , errs [0 ], txpool .ErrUnderpriced )
3224+
3225+ // send a tx to activate the precompile
3226+ newTxPoolHeadChan := make (chan core.NewTxPoolReorgEvent , 1 )
3227+ restartedVM .txPool .SubscribeNewReorgEvent (newTxPoolHeadChan )
3228+ restartedVM .clock .Set (utils .Uint64ToTime (precompileActivationTime ).Add (time .Second * 10 ))
3229+ tx = types .NewTransaction (uint64 (0 ), testEthAddrs [0 ], common .Big0 , 21000 , big .NewInt (testHighFeeConfig .MinBaseFee .Int64 ()), nil )
3230+ signedTx , err = types .SignTx (tx , types .LatestSigner (genesis .Config ), testKeys [0 ])
3231+ require .NoError (t , err )
3232+ errs = restartedVM .txPool .AddRemotesSync ([]* types.Transaction {signedTx })
3233+ require .NoError (t , errs [0 ])
3234+ blk := issueAndAccept (t , issuer , restartedVM )
3235+ newHead := <- newTxPoolHeadChan
3236+ require .Equal (t , newHead .Head .Hash (), common .Hash (blk .ID ()))
3237+ // Contract is initialized but no preconfig is given, reader should return genesis fee config
3238+ feeConfig , lastChangedAt , err := vm .blockChain .GetFeeConfigAt (vm .blockChain .Genesis ().Header ())
3239+ require .NoError (t , err )
3240+ require .EqualValues (t , feeConfig , testHighFeeConfig )
3241+ require .Zero (t , vm .blockChain .CurrentBlock ().Number .Cmp (lastChangedAt ))
3242+
3243+ // set a lower fee config now through feemanager
3244+ testLowFeeConfig := testHighFeeConfig
3245+ testLowFeeConfig .MinBaseFee = big .NewInt (25_000_000 )
3246+ data , err := feemanager .PackSetFeeConfig (testLowFeeConfig )
3247+ require .NoError (t , err )
3248+ tx = types .NewTx (& types.DynamicFeeTx {
3249+ ChainID : genesis .Config .ChainID ,
3250+ Nonce : uint64 (1 ),
3251+ To : & feemanager .ContractAddress ,
3252+ Gas : 1_000_000 ,
3253+ Value : common .Big0 ,
3254+ GasFeeCap : testHighFeeConfig .MinBaseFee , // the blockchain state still expects high fee
3255+ Data : data ,
3256+ })
3257+ // let some time pass for block gas cost
3258+ restartedVM .clock .Set (restartedVM .clock .Time ().Add (time .Second * 10 ))
3259+ signedTx , err = types .SignTx (tx , types .LatestSigner (genesis .Config ), testKeys [0 ])
3260+ require .NoError (t , err )
3261+ errs = restartedVM .txPool .AddRemotesSync ([]* types.Transaction {signedTx })
3262+ require .NoError (t , errs [0 ])
3263+ blk = issueAndAccept (t , issuer , restartedVM )
3264+ newHead = <- newTxPoolHeadChan
3265+ require .Equal (t , newHead .Head .Hash (), common .Hash (blk .ID ()))
3266+
3267+ // check that the fee config is updated
3268+ block := blk .(* chain.BlockWrapper ).Block .(* Block ).ethBlock
3269+ feeConfig , lastChangedAt , err = restartedVM .blockChain .GetFeeConfigAt (block .Header ())
3270+ require .NoError (t , err )
3271+ require .EqualValues (t , restartedVM .blockChain .CurrentBlock ().Number , lastChangedAt )
3272+ require .EqualValues (t , testLowFeeConfig , feeConfig )
3273+
3274+ // send another tx with low fee
3275+ tx = types .NewTransaction (uint64 (2 ), testEthAddrs [0 ], common .Big0 , 21000 , big .NewInt (testLowFeeConfig .MinBaseFee .Int64 ()), nil )
3276+ signedTx , err = types .SignTx (tx , types .LatestSigner (genesis .Config ), testKeys [0 ])
3277+ require .NoError (t , err )
3278+ errs = restartedVM .txPool .AddRemotesSync ([]* types.Transaction {signedTx })
3279+ require .NoError (t , errs [0 ])
3280+ // let some time pass for block gas cost and fees to be updated
3281+ restartedVM .clock .Set (restartedVM .clock .Time ().Add (time .Hour * 10 ))
3282+ blk = issueAndAccept (t , issuer , restartedVM )
3283+ newHead = <- newTxPoolHeadChan
3284+ require .Equal (t , newHead .Head .Hash (), common .Hash (blk .ID ()))
3285+
3286+ // Regression: Mempool should see the new config after restart
3287+ restartedVM , err = restartVM (restartedVM , sharedDB , genesisBytes , issuer , appSender , true )
3288+ require .NoError (t , err )
3289+ newTxPoolHeadChan = make (chan core.NewTxPoolReorgEvent , 1 )
3290+ restartedVM .txPool .SubscribeNewReorgEvent (newTxPoolHeadChan )
3291+ // send a tx with low fee
3292+ tx = types .NewTransaction (uint64 (3 ), testEthAddrs [0 ], common .Big0 , 21000 , big .NewInt (testLowFeeConfig .MinBaseFee .Int64 ()), nil )
3293+ signedTx , err = types .SignTx (tx , types .LatestSigner (genesis .Config ), testKeys [0 ])
3294+ require .NoError (t , err )
3295+ errs = restartedVM .txPool .AddRemotesSync ([]* types.Transaction {signedTx })
3296+ require .NoError (t , errs [0 ])
3297+ blk = issueAndAccept (t , issuer , restartedVM )
3298+ newHead = <- newTxPoolHeadChan
3299+ require .Equal (t , newHead .Head .Hash (), common .Hash (blk .ID ()))
3300+ }
3301+
3302+ func restartVM (vm * VM , sharedDB database.Database , genesisBytes []byte , issuer chan commonEng.Message , appSender commonEng.AppSender , finishBootstrapping bool ) (* VM , error ) {
3303+ vm .Shutdown (context .Background ())
3304+ restartedVM := & VM {}
3305+ vm .ctx .Metrics = metrics .NewPrefixGatherer ()
3306+ err := restartedVM .Initialize (context .Background (), vm .ctx , sharedDB , genesisBytes , nil , nil , issuer , []* commonEng.Fx {}, appSender )
3307+ if err != nil {
3308+ return nil , err
3309+ }
3310+
3311+ if finishBootstrapping {
3312+ err = restartedVM .SetState (context .Background (), snow .Bootstrapping )
3313+ if err != nil {
3314+ return nil , err
3315+ }
3316+ err = restartedVM .SetState (context .Background (), snow .NormalOp )
3317+ if err != nil {
3318+ return nil , err
3319+ }
3320+ }
3321+ return restartedVM , nil
3322+ }
0 commit comments