Skip to content

Commit 935680c

Browse files
JonathanOppenheimerceyonurpowerslideralarso16StephenButtolph
authored
sync: coreth PR #1127: feat(plugin/evm): ACP-226 - set expected block gas cost to 0 in Granite (#1765)
Signed-off-by: Tsvetan Dimitrov <[email protected]> Signed-off-by: Jonathan Oppenheimer <[email protected]> Co-authored-by: Ceyhun Onur <[email protected]> Co-authored-by: Tsvetan Dimitrov <[email protected]> Co-authored-by: Austin Larson <[email protected]> Co-authored-by: Stephen Buttolph <[email protected]>
1 parent 9029b29 commit 935680c

File tree

6 files changed

+80
-120
lines changed

6 files changed

+80
-120
lines changed

RELEASES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Add pending releases here
66
- Upgrade to Go version 1.24
7+
- Implement ACP-226: Set expected block gas cost to 0 in Granite network upgrade, removing block gas cost requirements for block building.
78
- Implement ACP-226: Add timeMilliseconds (Unix uint64) timestamp to block header for Granite upgrade.
89

910
## [v0.7.9](https://github.com/ava-labs/subnet-evm/releases/tag/v0.7.9)

core/blockchain_ext_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,7 +1395,7 @@ func GenerateChainInvalidBlockFee(t *testing.T, create createFunc) {
13951395
// Ensure that key1 has some funds in the genesis block.
13961396
genesisBalance := new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.Ether))
13971397
gspec := &Genesis{
1398-
Config: params.TestChainConfig,
1398+
Config: params.TestFortunaChainConfig,
13991399
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
14001400
}
14011401

@@ -1404,10 +1404,10 @@ func GenerateChainInvalidBlockFee(t *testing.T, create createFunc) {
14041404
t.Cleanup(blockchain.Stop)
14051405

14061406
// This call generates a chain of 3 blocks.
1407-
signer := types.LatestSigner(params.TestChainConfig)
1407+
signer := types.LatestSigner(params.TestFortunaChainConfig)
14081408
_, _, _, err = GenerateChainWithGenesis(gspec, blockchain.engine, 3, extras.TestChainConfig.FeeConfig.TargetBlockRate-1, func(_ int, gen *BlockGen) {
14091409
tx := types.NewTx(&types.DynamicFeeTx{
1410-
ChainID: params.TestChainConfig.ChainID,
1410+
ChainID: params.TestFortunaChainConfig.ChainID,
14111411
Nonce: gen.TxNonce(addr1),
14121412
To: &addr2,
14131413
Gas: ethparams.TxGas,
@@ -1436,7 +1436,7 @@ func InsertChainInvalidBlockFee(t *testing.T, create createFunc) {
14361436
// Ensure that key1 has some funds in the genesis block.
14371437
genesisBalance := new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.Ether))
14381438
gspec := &Genesis{
1439-
Config: params.TestChainConfig,
1439+
Config: params.TestFortunaChainConfig,
14401440
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
14411441
}
14421442

@@ -1445,11 +1445,11 @@ func InsertChainInvalidBlockFee(t *testing.T, create createFunc) {
14451445
t.Cleanup(blockchain.Stop)
14461446

14471447
// This call generates a chain of 3 blocks.
1448-
signer := types.LatestSigner(params.TestChainConfig)
1448+
signer := types.LatestSigner(params.TestFortunaChainConfig)
14491449
eng := dummy.NewFakerWithMode(dummy.Mode{ModeSkipBlockFee: true, ModeSkipCoinbase: true})
14501450
_, chain, _, err := GenerateChainWithGenesis(gspec, eng, 3, extras.TestChainConfig.FeeConfig.TargetBlockRate-1, func(_ int, gen *BlockGen) {
14511451
tx := types.NewTx(&types.DynamicFeeTx{
1452-
ChainID: params.TestChainConfig.ChainID,
1452+
ChainID: params.TestFortunaChainConfig.ChainID,
14531453
Nonce: gen.TxNonce(addr1),
14541454
To: &addr2,
14551455
Gas: ethparams.TxGas,

eth/gasprice/gasprice_test.go

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,12 @@ func testGenBlock(t *testing.T, tip int64, numTx int) func(int, *core.BlockGen)
237237
b.SetCoinbase(common.Address{1})
238238

239239
txTip := big.NewInt(tip * params.GWei)
240-
signer := types.LatestSigner(params.TestChainConfig)
240+
signer := types.LatestSigner(params.TestFortunaChainConfig)
241241
baseFee := b.BaseFee()
242242
feeCap := new(big.Int).Add(baseFee, txTip)
243243
for j := 0; j < numTx; j++ {
244244
tx := types.NewTx(&types.DynamicFeeTx{
245-
ChainID: params.TestChainConfig.ChainID,
245+
ChainID: params.TestFortunaChainConfig.ChainID,
246246
Nonce: b.TxNonce(addr),
247247
To: &common.Address{},
248248
Gas: ethparams.TxGas,
@@ -274,7 +274,7 @@ func TestSuggestTipCapNetworkUpgrades(t *testing.T) {
274274

275275
func TestSuggestTipCapSimple(t *testing.T) {
276276
applyGasPriceTest(t, suggestTipCapTest{
277-
chainConfig: params.TestChainConfig,
277+
chainConfig: params.TestFortunaChainConfig,
278278
numBlocks: 3,
279279
genBlock: testGenBlock(t, 55, 370),
280280
expectedTip: big.NewInt(1_287_001_288),
@@ -283,7 +283,7 @@ func TestSuggestTipCapSimple(t *testing.T) {
283283

284284
func TestSuggestTipCapSimpleFloor(t *testing.T) {
285285
applyGasPriceTest(t, suggestTipCapTest{
286-
chainConfig: params.TestChainConfig,
286+
chainConfig: params.TestFortunaChainConfig,
287287
numBlocks: 1,
288288
genBlock: testGenBlock(t, 55, 370),
289289
expectedTip: big.NewInt(643_500_644),
@@ -293,17 +293,17 @@ func TestSuggestTipCapSimpleFloor(t *testing.T) {
293293
func TestSuggestTipCapSmallTips(t *testing.T) {
294294
tip := big.NewInt(550 * params.GWei)
295295
applyGasPriceTest(t, suggestTipCapTest{
296-
chainConfig: params.TestChainConfig,
296+
chainConfig: params.TestFortunaChainConfig,
297297
numBlocks: 3,
298298
genBlock: func(i int, b *core.BlockGen) {
299299
b.SetCoinbase(common.Address{1})
300300

301-
signer := types.LatestSigner(params.TestChainConfig)
301+
signer := types.LatestSigner(params.TestFortunaChainConfig)
302302
baseFee := b.BaseFee()
303303
feeCap := new(big.Int).Add(baseFee, tip)
304304
for j := 0; j < 185; j++ {
305305
tx := types.NewTx(&types.DynamicFeeTx{
306-
ChainID: params.TestChainConfig.ChainID,
306+
ChainID: params.TestFortunaChainConfig.ChainID,
307307
Nonce: b.TxNonce(addr),
308308
To: &common.Address{},
309309
Gas: ethparams.TxGas,
@@ -317,7 +317,7 @@ func TestSuggestTipCapSmallTips(t *testing.T) {
317317
}
318318
b.AddTx(tx)
319319
tx = types.NewTx(&types.DynamicFeeTx{
320-
ChainID: params.TestChainConfig.ChainID,
320+
ChainID: params.TestFortunaChainConfig.ChainID,
321321
Nonce: b.TxNonce(addr),
322322
To: &common.Address{},
323323
Gas: ethparams.TxGas,
@@ -336,7 +336,7 @@ func TestSuggestTipCapSmallTips(t *testing.T) {
336336

337337
func TestSuggestTipCapMinGas(t *testing.T) {
338338
applyGasPriceTest(t, suggestTipCapTest{
339-
chainConfig: params.TestChainConfig,
339+
chainConfig: params.TestFortunaChainConfig,
340340
numBlocks: 3,
341341
genBlock: testGenBlock(t, 500, 50),
342342
expectedTip: DefaultMinPrice,
@@ -352,10 +352,10 @@ func TestSuggestGasPriceSubnetEVM(t *testing.T) {
352352
Percentile: 60,
353353
}
354354

355-
backend := newTestBackend(t, params.TestChainConfig, 3, func(i int, b *core.BlockGen) {
355+
backend := newTestBackend(t, params.TestFortunaChainConfig, 3, func(i int, b *core.BlockGen) {
356356
b.SetCoinbase(common.Address{1})
357357

358-
signer := types.LatestSigner(params.TestChainConfig)
358+
signer := types.LatestSigner(params.TestFortunaChainConfig)
359359
gasPrice := big.NewInt(legacy.BaseFee)
360360
for j := 0; j < 50; j++ {
361361
tx := types.NewTx(&types.LegacyTx{
@@ -379,18 +379,57 @@ func TestSuggestGasPriceSubnetEVM(t *testing.T) {
379379
require.NoError(t, err)
380380
}
381381

382+
// NOTE: [Oracle.SuggestTipCap] does NOT simply return the "required" (minimum) tip.
383+
// The oracle computes a percentile of recent required tips (not observed on-chain tips)
384+
// within a time/blocks lookback window and applies a small floor (e.g., 1 wei in tests):
385+
//
386+
// suggested = max(floor, recent-required-percentile)
387+
//
388+
// After Granite, BlockGasCost is 0 and per-block required tips are 0, so the oracle
389+
// suggestion equals the floor (1 wei) in steady state, regardless of high on-chain tips.
390+
// The cases below exercise behavior across forks using the same percentile logic and floor.
382391
func TestSuggestTipCapMaxBlocksLookback(t *testing.T) {
392+
cases := []struct {
393+
chainConfig *params.ChainConfig
394+
expectedTip *big.Int
395+
}{
396+
// TODO: remove Fortuna case when we activate Granite
397+
{
398+
chainConfig: params.TestFortunaChainConfig,
399+
expectedTip: big.NewInt(1),
400+
},
401+
{
402+
chainConfig: params.TestChainConfig,
403+
expectedTip: big.NewInt(1),
404+
},
405+
}
406+
for _, c := range cases {
407+
applyGasPriceTest(t, suggestTipCapTest{
408+
chainConfig: c.chainConfig,
409+
numBlocks: 200,
410+
genBlock: testGenBlock(t, 550, 80),
411+
expectedTip: c.expectedTip,
412+
}, defaultOracleConfig())
413+
}
414+
}
415+
416+
// Post-Granite, even very high observed tx tips should not affect SuggestTipCap, which
417+
// is computed from required tips. Since required tips are 0 in Granite, the returned
418+
// suggestion should be the floor (1 wei).
419+
func TestSuggestTipCapIgnoresObservedTipsPostGranite(t *testing.T) {
383420
applyGasPriceTest(t, suggestTipCapTest{
384-
chainConfig: params.TestChainConfig,
421+
chainConfig: params.TestChainConfig, // Granite active in TestChainConfig
385422
numBlocks: 20,
386-
genBlock: testGenBlock(t, 550, 370),
387-
expectedTip: big.NewInt(5_807_226_111),
423+
// Generate blocks with very high on-chain tips to ensure they wouldn't bias the result
424+
// if the oracle looked at observed tips. Expectation remains 1 wei.
425+
genBlock: testGenBlock(t, 100_000, 80),
426+
expectedTip: big.NewInt(1),
388427
}, defaultOracleConfig())
389428
}
390429

391430
func TestSuggestTipCapMaxBlocksSecondsLookback(t *testing.T) {
392431
applyGasPriceTest(t, suggestTipCapTest{
393-
chainConfig: params.TestChainConfig,
432+
chainConfig: params.TestFortunaChainConfig,
394433
numBlocks: 20,
395434
genBlock: testGenBlock(t, 550, 370),
396435
expectedTip: big.NewInt(10_384_877_852),
@@ -407,14 +446,14 @@ func TestEstimateBaseFeeAfterFeeConfigUpdate(t *testing.T) {
407446
}
408447

409448
// create a chain config with fee manager enabled at genesis with [addr] as the admin
410-
chainConfig := params.Copy(params.TestChainConfig)
449+
chainConfig := params.Copy(params.TestFortunaChainConfig)
411450
chainConfigExtra := params.GetExtra(&chainConfig)
412451
chainConfigExtra.GenesisPrecompiles = extras.Precompiles{
413452
feemanager.ConfigKey: feemanager.NewConfig(utils.NewUint64(0), []common.Address{addr}, nil, nil, nil),
414453
}
415454

416455
// create a fee config with higher MinBaseFee and prepare it for inclusion in a tx
417-
signer := types.LatestSigner(params.TestChainConfig)
456+
signer := types.LatestSigner(params.TestFortunaChainConfig)
418457
highFeeConfig := chainConfigExtra.FeeConfig
419458
highFeeConfig.MinBaseFee = big.NewInt(28_000_000_000)
420459
data, err := feemanager.PackSetFeeConfig(highFeeConfig)

plugin/evm/customheader/block_gas_cost.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var (
2828
// BlockGasCost calculates the required block gas cost based on the parent
2929
// header and the timestamp of the new block.
3030
// Prior to Subnet-EVM, the returned block gas cost will be nil.
31+
// In Granite, the returned block gas cost will be 0.
3132
func BlockGasCost(
3233
config *extras.ChainConfig,
3334
feeConfig commontype.FeeConfig,
@@ -37,7 +38,12 @@ func BlockGasCost(
3738
if !config.IsSubnetEVM(timestamp) {
3839
return nil
3940
}
41+
42+
if config.IsGranite(timestamp) {
43+
return big.NewInt(0)
44+
}
4045
step := feeConfig.BlockGasCostStep.Uint64()
46+
4147
// Treat an invalid parent/current time combination as 0 elapsed time.
4248
//
4349
// TODO: Does it even make sense to handle this? The timestamp should be

plugin/evm/customheader/block_gas_cost_test.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,29 @@ func BlockGasCostTest(t *testing.T, feeConfig commontype.FeeConfig) {
7676
expected: nil,
7777
},
7878
{
79-
name: "normal",
80-
upgrades: extras.TestChainConfig.NetworkUpgrades,
79+
name: "normal_pre_granite",
80+
upgrades: extras.TestFortunaChainConfig.NetworkUpgrades,
8181
parentTime: 10,
8282
parentCost: maxBlockGasCostBig,
8383
timestamp: 10 + targetBlockRate + 1,
8484
expected: new(big.Int).SetUint64(maxBlockGasCost - blockGasCostStep),
8585
},
8686
{
8787
name: "negative_time_elapsed",
88-
upgrades: extras.TestChainConfig.NetworkUpgrades,
88+
upgrades: extras.TestFortunaChainConfig.NetworkUpgrades,
8989
parentTime: 10,
9090
parentCost: feeConfig.MinBlockGasCost,
9191
timestamp: 9,
9292
expected: new(big.Int).SetUint64(minBlockGasCost + blockGasCostStep*targetBlockRate),
9393
},
94+
{
95+
name: "granite_returns_zero",
96+
upgrades: extras.TestGraniteChainConfig.NetworkUpgrades,
97+
parentTime: 10,
98+
parentCost: big.NewInt(int64(maxBlockGasCost)),
99+
timestamp: 10 + targetBlockRate + 1,
100+
expected: big.NewInt(0),
101+
},
94102
}
95103

96104
for _, test := range tests {

plugin/evm/vm_test.go

Lines changed: 0 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,100 +2179,6 @@ func testLastAcceptedBlockNumberAllow(t *testing.T, scheme string) {
21792179
}
21802180
}
21812181

2182-
// Regression test to ensure we can build blocks if we are starting with the
2183-
// Subnet EVM ruleset in genesis.
2184-
func TestBuildSubnetEVMBlock(t *testing.T) {
2185-
for _, scheme := range schemes {
2186-
t.Run(scheme, func(t *testing.T) {
2187-
testBuildSubnetEVMBlock(t, scheme)
2188-
})
2189-
}
2190-
}
2191-
2192-
func testBuildSubnetEVMBlock(t *testing.T, scheme string) {
2193-
tvm := newVM(t, testVMConfig{
2194-
genesisJSON: genesisJSONSubnetEVM,
2195-
configJSON: getConfig(scheme, ""),
2196-
})
2197-
2198-
defer func() {
2199-
if err := tvm.vm.Shutdown(context.Background()); err != nil {
2200-
t.Fatal(err)
2201-
}
2202-
}()
2203-
2204-
newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
2205-
tvm.vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
2206-
2207-
tx := types.NewTransaction(uint64(0), testEthAddrs[1], new(big.Int).Mul(firstTxAmount, big.NewInt(4)), 21000, big.NewInt(testMinGasPrice*3), nil)
2208-
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(tvm.vm.chainConfig.ChainID), testKeys[0].ToECDSA())
2209-
if err != nil {
2210-
t.Fatal(err)
2211-
}
2212-
2213-
txErrors := tvm.vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
2214-
for i, err := range txErrors {
2215-
if err != nil {
2216-
t.Fatalf("Failed to add tx at index %d: %s", i, err)
2217-
}
2218-
}
2219-
2220-
blk := issueAndAccept(t, tvm.vm)
2221-
newHead := <-newTxPoolHeadChan
2222-
if newHead.Head.Hash() != common.Hash(blk.ID()) {
2223-
t.Fatalf("Expected new block to match")
2224-
}
2225-
2226-
txs := make([]*types.Transaction, 10)
2227-
for i := 0; i < 10; i++ {
2228-
tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(testMinGasPrice*3), nil)
2229-
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(tvm.vm.chainConfig.ChainID), testKeys[1].ToECDSA())
2230-
if err != nil {
2231-
t.Fatal(err)
2232-
}
2233-
txs[i] = signedTx
2234-
}
2235-
errs := tvm.vm.txPool.AddRemotesSync(txs)
2236-
for i, err := range errs {
2237-
if err != nil {
2238-
t.Fatalf("Failed to add tx at index %d: %s", i, err)
2239-
}
2240-
}
2241-
2242-
blk = issueAndAccept(t, tvm.vm)
2243-
ethBlk := blk.(*chain.BlockWrapper).Block.(*wrappedBlock).ethBlock
2244-
if customtypes.BlockGasCost(ethBlk) == nil || customtypes.BlockGasCost(ethBlk).Cmp(big.NewInt(100)) < 0 {
2245-
t.Fatalf("expected blockGasCost to be at least 100 but got %d", customtypes.BlockGasCost(ethBlk))
2246-
}
2247-
chainConfig := params.GetExtra(tvm.vm.chainConfig)
2248-
minRequiredTip, err := customheader.EstimateRequiredTip(chainConfig, ethBlk.Header())
2249-
if err != nil {
2250-
t.Fatal(err)
2251-
}
2252-
if minRequiredTip == nil || minRequiredTip.Cmp(big.NewInt(0.05*utils.GWei)) < 0 {
2253-
t.Fatalf("expected minRequiredTip to be at least 0.05 gwei but got %d", minRequiredTip)
2254-
}
2255-
2256-
lastAcceptedID, err := tvm.vm.LastAccepted(context.Background())
2257-
if err != nil {
2258-
t.Fatal(err)
2259-
}
2260-
if lastAcceptedID != blk.ID() {
2261-
t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID)
2262-
}
2263-
2264-
// Confirm all txs are present
2265-
ethBlkTxs := tvm.vm.blockChain.GetBlockByNumber(2).Transactions()
2266-
for i, tx := range txs {
2267-
if len(ethBlkTxs) <= i {
2268-
t.Fatalf("missing transactions expected: %d but found: %d", len(txs), len(ethBlkTxs))
2269-
}
2270-
if ethBlkTxs[i].Hash() != tx.Hash() {
2271-
t.Fatalf("expected tx at index %d to have hash: %x but has: %x", i, txs[i].Hash(), tx.Hash())
2272-
}
2273-
}
2274-
}
2275-
22762182
func TestBuildAllowListActivationBlock(t *testing.T) {
22772183
for _, scheme := range schemes {
22782184
t.Run(scheme, func(t *testing.T) {

0 commit comments

Comments
 (0)