github.com/ethereum/go-ethereum@v1.16.1/consensus/misc/eip4844/eip4844.go (about) 1 // Copyright 2023 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package eip4844 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 24 "github.com/ethereum/go-ethereum/core/types" 25 "github.com/ethereum/go-ethereum/params" 26 "github.com/ethereum/go-ethereum/params/forks" 27 ) 28 29 var ( 30 minBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice) 31 ) 32 33 // VerifyEIP4844Header verifies the presence of the excessBlobGas field and that 34 // if the current block contains no transactions, the excessBlobGas is updated 35 // accordingly. 36 func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Header) error { 37 if header.Number.Uint64() != parent.Number.Uint64()+1 { 38 panic("bad header pair") 39 } 40 // Verify the header is not malformed 41 if header.ExcessBlobGas == nil { 42 return errors.New("header is missing excessBlobGas") 43 } 44 if header.BlobGasUsed == nil { 45 return errors.New("header is missing blobGasUsed") 46 } 47 // Verify that the blob gas used remains within reasonable limits. 48 maxBlobGas := MaxBlobGasPerBlock(config, header.Time) 49 if *header.BlobGasUsed > maxBlobGas { 50 return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, maxBlobGas) 51 } 52 if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 { 53 return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob) 54 } 55 // Verify the excessBlobGas is correct based on the parent header 56 expectedExcessBlobGas := CalcExcessBlobGas(config, parent, header.Time) 57 if *header.ExcessBlobGas != expectedExcessBlobGas { 58 return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas) 59 } 60 return nil 61 } 62 63 // CalcExcessBlobGas calculates the excess blob gas after applying the set of 64 // blobs on top of the excess blob gas. 65 func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTimestamp uint64) uint64 { 66 var ( 67 parentExcessBlobGas uint64 68 parentBlobGasUsed uint64 69 ) 70 if parent.ExcessBlobGas != nil { 71 parentExcessBlobGas = *parent.ExcessBlobGas 72 parentBlobGasUsed = *parent.BlobGasUsed 73 } 74 excessBlobGas := parentExcessBlobGas + parentBlobGasUsed 75 targetGas := uint64(targetBlobsPerBlock(config, headTimestamp)) * params.BlobTxBlobGasPerBlob 76 if excessBlobGas < targetGas { 77 return 0 78 } 79 return excessBlobGas - targetGas 80 } 81 82 // CalcBlobFee calculates the blobfee from the header's excess blob gas field. 83 func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int { 84 var frac uint64 85 switch config.LatestFork(header.Time) { 86 case forks.Osaka: 87 frac = config.BlobScheduleConfig.Osaka.UpdateFraction 88 case forks.Prague: 89 frac = config.BlobScheduleConfig.Prague.UpdateFraction 90 case forks.Cancun: 91 frac = config.BlobScheduleConfig.Cancun.UpdateFraction 92 default: 93 panic("calculating blob fee on unsupported fork") 94 } 95 return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(frac)) 96 } 97 98 // MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp. 99 func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { 100 if cfg.BlobScheduleConfig == nil { 101 return 0 102 } 103 var ( 104 london = cfg.LondonBlock 105 s = cfg.BlobScheduleConfig 106 ) 107 switch { 108 case cfg.IsOsaka(london, time) && s.Osaka != nil: 109 return s.Osaka.Max 110 case cfg.IsPrague(london, time) && s.Prague != nil: 111 return s.Prague.Max 112 case cfg.IsCancun(london, time) && s.Cancun != nil: 113 return s.Cancun.Max 114 default: 115 return 0 116 } 117 } 118 119 // MaxBlobsPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp. 120 func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 { 121 return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob 122 } 123 124 // LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the 125 // configuration, regardless of the currently active fork. 126 func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int { 127 s := cfg.BlobScheduleConfig 128 if s == nil { 129 return 0 130 } 131 switch { 132 case s.Osaka != nil: 133 return s.Osaka.Max 134 case s.Prague != nil: 135 return s.Prague.Max 136 case s.Cancun != nil: 137 return s.Cancun.Max 138 default: 139 return 0 140 } 141 } 142 143 // targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp. 144 func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { 145 if cfg.BlobScheduleConfig == nil { 146 return 0 147 } 148 var ( 149 london = cfg.LondonBlock 150 s = cfg.BlobScheduleConfig 151 ) 152 switch { 153 case cfg.IsOsaka(london, time) && s.Osaka != nil: 154 return s.Osaka.Target 155 case cfg.IsPrague(london, time) && s.Prague != nil: 156 return s.Prague.Target 157 case cfg.IsCancun(london, time) && s.Cancun != nil: 158 return s.Cancun.Target 159 default: 160 return 0 161 } 162 } 163 164 // fakeExponential approximates factor * e ** (numerator / denominator) using 165 // Taylor expansion. 166 func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { 167 var ( 168 output = new(big.Int) 169 accum = new(big.Int).Mul(factor, denominator) 170 ) 171 for i := 1; accum.Sign() > 0; i++ { 172 output.Add(output, accum) 173 174 accum.Mul(accum, numerator) 175 accum.Div(accum, denominator) 176 accum.Div(accum, big.NewInt(int64(i))) 177 } 178 return output.Div(output, denominator) 179 }