diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index 9990df04a7d1..1f4239639c35 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -92,11 +92,13 @@ func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Heade if header.BaseFee == nil { return fmt.Errorf("header is missing baseFee") } - // note: we do not verify L2 base fee, the sequencer has the - // right to set any base fee below the maximum. L2 base fee - // is not subject to L2 consensus or zk verification. - if header.BaseFee.Cmp(big.NewInt(MaximumL2BaseFee)) > 0 { - return fmt.Errorf("invalid baseFee: have %s, maximum %d", header.BaseFee, MaximumL2BaseFee) + scalar, overhead := ReadL2BaseFeeCoefficients() + + expectedEIP1559 := calcBaseFeeEIP1559(config, parent, scalar, overhead) + expectedHeaderBaseFee := calcBaseFee(scalar, overhead, expectedEIP1559) + + if header.BaseFee.Cmp(expectedHeaderBaseFee) != 0 { + return fmt.Errorf("invalid baseFee: got %s, want %s", header.BaseFee, expectedHeaderBaseFee) } return nil } @@ -108,7 +110,66 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header, parentL1BaseF } scalar, overhead := ReadL2BaseFeeCoefficients() - return calcBaseFee(scalar, overhead, parentL1BaseFee) + if !config.IsFeynman(big.NewInt(0).Add(parent.Number, common.Big1)) { + return calcBaseFee(scalar, overhead, parentL1BaseFee) + } + baseFeeEIP1559 := calcBaseFeeEIP1559(config, parent, scalar, overhead) + return calcBaseFee(scalar, overhead, baseFeeEIP1559) +} + +// CalcBaseFee calculates the basefee of the header. +func calcBaseFeeEIP1559(config *params.ChainConfig, parent *types.Header, scalar *big.Int, overhead *big.Int) *big.Int { + // If the current block is the first EIP-1559 block, return the InitialBaseFee. + if !config.IsFeynman(parent.Number) { + return new(big.Int).SetUint64(params.InitialBaseFee) + } + + parentBaseFeeEIP1559 := extractBaseFeeEIP1559(parent.BaseFee, scalar, overhead) + parentGasTarget := parent.GasLimit / config.ElasticityMultiplier() + // If the parent gasUsed is the same as the target, the baseFee remains unchanged. + if parent.GasUsed == parentGasTarget { + return new(big.Int).Set(parentBaseFeeEIP1559) + } + + var ( + num = new(big.Int) + denom = new(big.Int) + ) + + if parent.GasUsed > parentGasTarget { + // If the parent block used more gas than its target, the baseFee should increase. + // max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator) + num.SetUint64(parent.GasUsed - parentGasTarget) + num.Mul(num, parentBaseFeeEIP1559) + num.Div(num, denom.SetUint64(parentGasTarget)) + num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator())) + if num.Cmp(common.Big1) < 0 { + return num.Add(parentBaseFeeEIP1559, common.Big1) + } + return num.Add(parentBaseFeeEIP1559, num) + } else { + // Otherwise if the parent block used less gas than its target, the baseFee should decrease. + // max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator) + num.SetUint64(parentGasTarget - parent.GasUsed) + num.Mul(num, parentBaseFeeEIP1559) + num.Div(num, denom.SetUint64(parentGasTarget)) + num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator())) + + baseFee := num.Sub(parentBaseFeeEIP1559, num) + if baseFee.Cmp(common.Big0) < 0 { + baseFee = common.Big0 + } + return baseFee + } +} + +func extractBaseFeeEIP1559(baseFee *big.Int, scalar *big.Int, overhead *big.Int) *big.Int { + baseFeeEIP := new(big.Int).Set(baseFee) + baseFeeEIP.Sub(baseFeeEIP, overhead) + baseFeeEIP.Mul(baseFeeEIP, BaseFeePrecision) + baseFeeEIP.Div(baseFeeEIP, scalar) + + return baseFeeEIP } // MinBaseFee calculates the minimum L2 base fee based on the current coefficients. @@ -117,8 +178,8 @@ func MinBaseFee() *big.Int { return calcBaseFee(scalar, overhead, big.NewInt(0)) } -func calcBaseFee(scalar, overhead, parentL1BaseFee *big.Int) *big.Int { - baseFee := new(big.Int).Set(parentL1BaseFee) +func calcBaseFee(scalar, overhead, l2BaseFee *big.Int) *big.Int { + baseFee := new(big.Int).Set(l2BaseFee) baseFee.Mul(baseFee, scalar) baseFee.Div(baseFee, BaseFeePrecision) baseFee.Add(baseFee, overhead) diff --git a/params/config.go b/params/config.go index 96b77e04a7f4..31b1ab1eb7cd 100644 --- a/params/config.go +++ b/params/config.go @@ -988,6 +988,11 @@ func (c *ChainConfig) IsEuclidV2(now uint64) bool { return isForkedTime(now, c.EuclidV2Time) } +// IsFeynman returns whether time is either equal to the Feyman fork time or greater. +func (c *ChainConfig) IsFeynman(num *big.Int) bool { + return false // placeholder +} + // IsTerminalPoWBlock returns whether the given block is the last block of PoW stage. func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool { if c.TerminalTotalDifficulty == nil { @@ -1014,6 +1019,16 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *Confi return lasterr } +// BaseFeeChangeDenominator bounds the amount the base fee can change between blocks. +func (c *ChainConfig) BaseFeeChangeDenominator() uint64 { + return DefaultBaseFeeChangeDenominator +} + +// ElasticityMultiplier bounds the maximum gas limit an EIP-1559 block may have. +func (c *ChainConfig) ElasticityMultiplier() uint64 { + return DefaultElasticityMultiplier +} + // CheckConfigForkOrder checks that we don't "skip" any forks, geth isn't pluggable enough // to guarantee that forks can be implemented in a different order than on official networks func (c *ChainConfig) CheckConfigForkOrder() error { diff --git a/params/protocol_params.go b/params/protocol_params.go index a541c86a0f43..de52d615bc2e 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -121,9 +121,9 @@ const ( // Introduced in Tangerine Whistle (Eip 150) CreateBySelfdestructGas uint64 = 25000 - BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. - ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. - InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. + DefaultBaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. + DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. + InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. MaxCodeSize = 24576 // Maximum bytecode to permit for a contract MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions diff --git a/params/version.go b/params/version.go index dd5c54baa4e8..7a5726b9fd67 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 5 // Major version component of the current release VersionMinor = 8 // Minor version component of the current release - VersionPatch = 51 // Patch version component of the current release + VersionPatch = 52 // Patch version component of the current release VersionMeta = "mainnet" // Version metadata to append to the version string ) diff --git a/rollup/da_syncer/blob_client/blob_scan_client.go b/rollup/da_syncer/blob_client/blob_scan_client.go index 75fe4fdfbdce..c4756ed695a8 100644 --- a/rollup/da_syncer/blob_client/blob_scan_client.go +++ b/rollup/da_syncer/blob_client/blob_scan_client.go @@ -64,6 +64,12 @@ func (c *BlobScanClient) GetBlobByVersionedHashAndBlockTime(ctx context.Context, if err != nil { return nil, fmt.Errorf("failed to decode result into struct, err: %w", err) } + + // check that blob data is not empty + if len(result.Data) < 2 { + return nil, fmt.Errorf("blob data is too short to be valid, expected at least 2 characters, got: %s, versioned hash: %s", result.Data, versionedHash.String()) + } + blobBytes, err := hex.DecodeString(result.Data[2:]) if err != nil { return nil, fmt.Errorf("failed to decode data to bytes, err: %w", err) diff --git a/rollup/da_syncer/blob_client/block_native_client.go b/rollup/da_syncer/blob_client/block_native_client.go index d96f54a3cfa4..b3ec31ba62fb 100644 --- a/rollup/da_syncer/blob_client/block_native_client.go +++ b/rollup/da_syncer/blob_client/block_native_client.go @@ -59,6 +59,12 @@ func (c *BlockNativeClient) GetBlobByVersionedHashAndBlockTime(ctx context.Conte if err != nil { return nil, fmt.Errorf("failed to decode result into struct, err: %w", err) } + + // check that blob data is not empty + if len(result.Blob.Data) < 2 { + return nil, fmt.Errorf("blob data is too short to be valid, expected at least 2 characters, got: %s, versioned hash: %s", result.Blob.Data, versionedHash.String()) + } + blobBytes, err := hex.DecodeString(result.Blob.Data[2:]) if err != nil { return nil, fmt.Errorf("failed to decode data to bytes, err: %w", err)