mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
Merge branch 'ethereum:master' into master
This commit is contained in:
commit
9beb86b4b9
28 changed files with 5861 additions and 59 deletions
36
.github/workflows/go.yml
vendored
36
.github/workflows/go.yml
vendored
|
|
@ -1,18 +1,20 @@
|
||||||
name: i386 linux tests
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches:
|
||||||
|
- master
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches:
|
||||||
|
- master
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
name: Lint
|
name: Lint
|
||||||
runs-on: self-hosted
|
runs-on: self-hosted-ghr
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: false
|
||||||
|
|
||||||
# Cache build tools to avoid downloading them each time
|
# Cache build tools to avoid downloading them each time
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
|
|
@ -23,7 +25,7 @@ jobs:
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.23.0
|
go-version: 1.24
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: Run linters
|
- name: Run linters
|
||||||
|
|
@ -32,17 +34,25 @@ jobs:
|
||||||
go run build/ci.go check_generate
|
go run build/ci.go check_generate
|
||||||
go run build/ci.go check_baddeps
|
go run build/ci.go check_baddeps
|
||||||
|
|
||||||
build:
|
test:
|
||||||
runs-on: self-hosted
|
name: Test
|
||||||
|
needs: lint
|
||||||
|
runs-on: self-hosted-ghr
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go:
|
||||||
|
- '1.24'
|
||||||
|
- '1.23'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.24.0
|
go-version: ${{ matrix.go }}
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: go test -short ./...
|
run: go test ./...
|
||||||
env:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: 386
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ The API-method `account_signGnosisSafeTx` was added. This method takes two param
|
||||||
```
|
```
|
||||||
|
|
||||||
Not all fields are required, though. This method is really just a UX helper, which massages the
|
Not all fields are required, though. This method is really just a UX helper, which massages the
|
||||||
input to conform to the `EIP-712` [specification](https://docs.gnosis.io/safe/docs/contracts_tx_execution/#transaction-hash)
|
input to conform to the `EIP-712` [specification](https://docs.safe.global/core-api/transaction-service-reference/gnosis)
|
||||||
for the Gnosis Safe, and making the output be directly importable to by a relay service.
|
for the Gnosis Safe, and making the output be directly importable to by a relay service.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,9 @@ func Transaction(ctx *cli.Context) error {
|
||||||
if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
||||||
r.Error = errors.New("max initcode size exceeded")
|
r.Error = errors.New("max initcode size exceeded")
|
||||||
}
|
}
|
||||||
|
if chainConfig.IsOsaka(new(big.Int), 0) && tx.Gas() > params.MaxTxGas {
|
||||||
|
r.Error = errors.New("gas limit exceeds maximum")
|
||||||
|
}
|
||||||
results = append(results, r)
|
results = append(results, r)
|
||||||
}
|
}
|
||||||
out, err := json.MarshalIndent(results, "", " ")
|
out, err := json.MarshalIndent(results, "", " ")
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
if len(hex) != common.HashLength {
|
if len(hex) != common.HashLength {
|
||||||
utils.Fatalf("invalid sync target length: have %d, want %d", len(hex), common.HashLength)
|
utils.Fatalf("invalid sync target length: have %d, want %d", len(hex), common.HashLength)
|
||||||
}
|
}
|
||||||
utils.RegisterFullSyncTester(stack, eth, common.BytesToHash(hex))
|
utils.RegisterFullSyncTester(stack, eth, common.BytesToHash(hex), ctx.Bool(utils.ExitWhenSyncedFlag.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.IsSet(utils.DeveloperFlag.Name) {
|
if ctx.IsSet(utils.DeveloperFlag.Name) {
|
||||||
|
|
|
||||||
|
|
@ -1859,7 +1859,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig {
|
func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig {
|
||||||
var config bparams.ClientConfig
|
var config bparams.ClientConfig
|
||||||
customConfig := ctx.IsSet(BeaconConfigFlag.Name)
|
customConfig := ctx.IsSet(BeaconConfigFlag.Name)
|
||||||
flags.CheckExclusive(ctx, MainnetFlag, SepoliaFlag, HoleskyFlag, BeaconConfigFlag)
|
flags.CheckExclusive(ctx, MainnetFlag, SepoliaFlag, HoleskyFlag, HoodiFlag, BeaconConfigFlag)
|
||||||
switch {
|
switch {
|
||||||
case ctx.Bool(MainnetFlag.Name):
|
case ctx.Bool(MainnetFlag.Name):
|
||||||
config.ChainConfig = *bparams.MainnetLightConfig
|
config.ChainConfig = *bparams.MainnetLightConfig
|
||||||
|
|
@ -1998,9 +1998,9 @@ func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconf
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterFullSyncTester adds the full-sync tester service into node.
|
// RegisterFullSyncTester adds the full-sync tester service into node.
|
||||||
func RegisterFullSyncTester(stack *node.Node, eth *eth.Ethereum, target common.Hash) {
|
func RegisterFullSyncTester(stack *node.Node, eth *eth.Ethereum, target common.Hash, exitWhenSynced bool) {
|
||||||
catalyst.RegisterFullSyncTester(stack, eth, target)
|
catalyst.RegisterFullSyncTester(stack, eth, target, exitWhenSynced)
|
||||||
log.Info("Registered full-sync tester", "hash", target)
|
log.Info("Registered full-sync tester", "hash", target, "exitWhenSynced", exitWhenSynced)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupMetrics configures the metrics system.
|
// SetupMetrics configures the metrics system.
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,30 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim
|
||||||
parentExcessBlobGas = *parent.ExcessBlobGas
|
parentExcessBlobGas = *parent.ExcessBlobGas
|
||||||
parentBlobGasUsed = *parent.BlobGasUsed
|
parentBlobGasUsed = *parent.BlobGasUsed
|
||||||
}
|
}
|
||||||
excessBlobGas := parentExcessBlobGas + parentBlobGasUsed
|
var (
|
||||||
targetGas := uint64(targetBlobsPerBlock(config, headTimestamp)) * params.BlobTxBlobGasPerBlob
|
excessBlobGas = parentExcessBlobGas + parentBlobGasUsed
|
||||||
|
target = targetBlobsPerBlock(config, headTimestamp)
|
||||||
|
targetGas = uint64(target) * params.BlobTxBlobGasPerBlob
|
||||||
|
)
|
||||||
if excessBlobGas < targetGas {
|
if excessBlobGas < targetGas {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
if !config.IsOsaka(config.LondonBlock, headTimestamp) {
|
||||||
|
// Pre-Osaka, we use the formula defined by EIP-4844.
|
||||||
|
return excessBlobGas - targetGas
|
||||||
|
}
|
||||||
|
|
||||||
|
// EIP-7918 (post-Osaka) introduces a different formula for computing excess.
|
||||||
|
var (
|
||||||
|
baseCost = big.NewInt(params.BlobBaseCost)
|
||||||
|
reservePrice = baseCost.Mul(baseCost, parent.BaseFee)
|
||||||
|
blobPrice = calcBlobPrice(config, parent)
|
||||||
|
)
|
||||||
|
if reservePrice.Cmp(blobPrice) > 0 {
|
||||||
|
max := MaxBlobsPerBlock(config, headTimestamp)
|
||||||
|
scaledExcess := parentBlobGasUsed * uint64(max-target) / uint64(max)
|
||||||
|
return parentExcessBlobGas + scaledExcess
|
||||||
|
}
|
||||||
return excessBlobGas - targetGas
|
return excessBlobGas - targetGas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,3 +196,9 @@ func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
|
||||||
}
|
}
|
||||||
return output.Div(output, denominator)
|
return output.Div(output, denominator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calcBlobPrice calculates the blob price for a block.
|
||||||
|
func calcBlobPrice(config *params.ChainConfig, header *types.Header) *big.Int {
|
||||||
|
blobBaseFee := CalcBlobFee(config, header)
|
||||||
|
return new(big.Int).Mul(blobBaseFee, big.NewInt(params.BlobTxBlobGasPerBlob))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,3 +127,43 @@ func TestFakeExponential(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCalcExcessBlobGasEIP7918(t *testing.T) {
|
||||||
|
var (
|
||||||
|
cfg = params.MergedTestChainConfig
|
||||||
|
targetBlobs = targetBlobsPerBlock(cfg, *cfg.CancunTime)
|
||||||
|
blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
|
||||||
|
)
|
||||||
|
makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header {
|
||||||
|
blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob
|
||||||
|
return &types.Header{
|
||||||
|
BaseFee: big.NewInt(int64(parentBaseFee)),
|
||||||
|
ExcessBlobGas: &parentExcess,
|
||||||
|
BlobGasUsed: &blobGasUsed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
header *types.Header
|
||||||
|
wantExcessGas uint64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "BelowReservePrice",
|
||||||
|
header: makeHeader(0, 1_000_000_000, targetBlobs),
|
||||||
|
wantExcessGas: blobGasTarget * 3 / 9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AboveReservePrice",
|
||||||
|
header: makeHeader(0, 1, targetBlobs),
|
||||||
|
wantExcessGas: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tests {
|
||||||
|
got := CalcExcessBlobGas(cfg, tc.header, *cfg.CancunTime)
|
||||||
|
if got != tc.wantExcessGas {
|
||||||
|
t.Fatalf("%s: excess-blob-gas mismatch – have %d, want %d",
|
||||||
|
tc.name, got, tc.wantExcessGas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,10 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *Bloc
|
||||||
// header's transaction and uncle roots. The headers are assumed to be already
|
// header's transaction and uncle roots. The headers are assumed to be already
|
||||||
// validated at this point.
|
// validated at this point.
|
||||||
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
|
// check EIP 7934 RLP-encoded block size cap
|
||||||
|
if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.MaxBlockSize {
|
||||||
|
return ErrBlockOversized
|
||||||
|
}
|
||||||
// Check whether the block is already imported.
|
// Check whether the block is already imported.
|
||||||
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
||||||
return ErrKnownBlock
|
return ErrKnownBlock
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ var (
|
||||||
|
|
||||||
// ErrNoGenesis is returned when there is no Genesis Block.
|
// ErrNoGenesis is returned when there is no Genesis Block.
|
||||||
ErrNoGenesis = errors.New("genesis not found in chain")
|
ErrNoGenesis = errors.New("genesis not found in chain")
|
||||||
|
|
||||||
|
// ErrBlockOversized is returned if the size of the RLP-encoded block
|
||||||
|
// exceeds the cap established by EIP 7934
|
||||||
|
ErrBlockOversized = errors.New("block RLP-encoded size exceeds maximum")
|
||||||
)
|
)
|
||||||
|
|
||||||
// List of evm-call-message pre-checking errors. All state transition messages will
|
// List of evm-call-message pre-checking errors. All state transition messages will
|
||||||
|
|
@ -122,6 +126,9 @@ var (
|
||||||
// Message validation errors:
|
// Message validation errors:
|
||||||
ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list")
|
ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list")
|
||||||
ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract")
|
ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract")
|
||||||
|
|
||||||
|
// -- EIP-7825 errors --
|
||||||
|
ErrGasLimitTooHigh = errors.New("transaction gas limit too high")
|
||||||
)
|
)
|
||||||
|
|
||||||
// EIP-7702 state transition errors.
|
// EIP-7702 state transition errors.
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,10 @@ func (st *stateTransition) preCheck() error {
|
||||||
return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
|
return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Verify tx gas limit does not exceed EIP-7825 cap.
|
||||||
|
if st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time) && msg.GasLimit > params.MaxTxGas {
|
||||||
|
return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit)
|
||||||
|
}
|
||||||
return st.buyGas()
|
return st.buyGas()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1638,6 +1638,11 @@ func (p *BlobPool) Pending(filter txpool.PendingFilter) map[common.Address][]*tx
|
||||||
break // blobfee too low, cannot be included, discard rest of txs from the account
|
break // blobfee too low, cannot be included, discard rest of txs from the account
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if filter.GasLimitCap != 0 {
|
||||||
|
if tx.execGas > filter.GasLimitCap {
|
||||||
|
break // execution gas limit is too high
|
||||||
|
}
|
||||||
|
}
|
||||||
// Transaction was accepted according to the filter, append to the pending list
|
// Transaction was accepted according to the filter, append to the pending list
|
||||||
lazies = append(lazies, &txpool.LazyTransaction{
|
lazies = append(lazies, &txpool.LazyTransaction{
|
||||||
Pool: p,
|
Pool: p,
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ func (l *limbo) finalize(final *types.Header) {
|
||||||
// Just in case there's no final block yet (network not yet merged, weird
|
// Just in case there's no final block yet (network not yet merged, weird
|
||||||
// restart, sethead, etc), fail gracefully.
|
// restart, sethead, etc), fail gracefully.
|
||||||
if final == nil {
|
if final == nil {
|
||||||
log.Error("Nil finalized block cannot evict old blobs")
|
log.Warn("Nil finalized block cannot evict old blobs")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for block, ids := range l.groups {
|
for block, ids := range l.groups {
|
||||||
|
|
@ -139,11 +139,11 @@ func (l *limbo) push(tx *types.Transaction, block uint64) error {
|
||||||
// If the blobs are already tracked by the limbo, consider it a programming
|
// If the blobs are already tracked by the limbo, consider it a programming
|
||||||
// error. There's not much to do against it, but be loud.
|
// error. There's not much to do against it, but be loud.
|
||||||
if _, ok := l.index[tx.Hash()]; ok {
|
if _, ok := l.index[tx.Hash()]; ok {
|
||||||
log.Error("Limbo cannot push already tracked blobs", "tx", tx)
|
log.Error("Limbo cannot push already tracked blobs", "tx", tx.Hash())
|
||||||
return errors.New("already tracked blob transaction")
|
return errors.New("already tracked blob transaction")
|
||||||
}
|
}
|
||||||
if err := l.setAndIndex(tx, block); err != nil {
|
if err := l.setAndIndex(tx, block); err != nil {
|
||||||
log.Error("Failed to set and index limboed blobs", "tx", tx, "err", err)
|
log.Error("Failed to set and index limboed blobs", "tx", tx.Hash(), "err", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -530,11 +530,19 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address]
|
||||||
txs := list.Flatten()
|
txs := list.Flatten()
|
||||||
|
|
||||||
// If the miner requests tip enforcement, cap the lists now
|
// If the miner requests tip enforcement, cap the lists now
|
||||||
if minTipBig != nil {
|
if minTipBig != nil || filter.GasLimitCap != 0 {
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
|
if minTipBig != nil {
|
||||||
txs = txs[:i]
|
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
|
||||||
break
|
txs = txs[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if filter.GasLimitCap != 0 {
|
||||||
|
if tx.Gas() > filter.GasLimitCap {
|
||||||
|
txs = txs[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1255,6 +1263,21 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
|
||||||
}
|
}
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
if reset != nil {
|
if reset != nil {
|
||||||
|
if reset.newHead != nil && reset.oldHead != nil {
|
||||||
|
// Discard the transactions with the gas limit higher than the cap.
|
||||||
|
if pool.chainconfig.IsOsaka(reset.newHead.Number, reset.newHead.Time) && !pool.chainconfig.IsOsaka(reset.oldHead.Number, reset.oldHead.Time) {
|
||||||
|
var hashes []common.Hash
|
||||||
|
pool.all.Range(func(hash common.Hash, tx *types.Transaction) bool {
|
||||||
|
if tx.Gas() > params.MaxTxGas {
|
||||||
|
hashes = append(hashes, hash)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
for _, hash := range hashes {
|
||||||
|
pool.removeTx(hash, true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Reset from the old head to the new, rescheduling any reorged transactions
|
// Reset from the old head to the new, rescheduling any reorged transactions
|
||||||
pool.reset(reset.oldHead, reset.newHead)
|
pool.reset(reset.oldHead, reset.newHead)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,9 +73,10 @@ type LazyResolver interface {
|
||||||
// a very specific call site in mind and each one can be evaluated very cheaply
|
// a very specific call site in mind and each one can be evaluated very cheaply
|
||||||
// by the pool implementations. Only add new ones that satisfy those constraints.
|
// by the pool implementations. Only add new ones that satisfy those constraints.
|
||||||
type PendingFilter struct {
|
type PendingFilter struct {
|
||||||
MinTip *uint256.Int // Minimum miner tip required to include a transaction
|
MinTip *uint256.Int // Minimum miner tip required to include a transaction
|
||||||
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
|
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
|
||||||
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
|
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
|
||||||
|
GasLimitCap uint64 // Maximum gas can be used for a single transaction execution (0 means no limit)
|
||||||
|
|
||||||
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
|
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
|
||||||
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
|
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
|
||||||
if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
||||||
return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize)
|
return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize)
|
||||||
}
|
}
|
||||||
|
if rules.IsOsaka && tx.Gas() > params.MaxTxGas {
|
||||||
|
return fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas())
|
||||||
|
}
|
||||||
// Transactions can't be negative. This may never happen using RLP decoded
|
// Transactions can't be negative. This may never happen using RLP decoded
|
||||||
// transactions but may occur for transactions created using the RPC.
|
// transactions but may occur for transactions created using the RPC.
|
||||||
if tx.Value().Sign() < 0 {
|
if tx.Value().Sign() < 0 {
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/internal/blocktest"
|
"github.com/ethereum/go-ethereum/internal/blocktest"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// from bcValidBlockTest.json, "SimpleTx"
|
// from bcValidBlockTest.json, "SimpleTx"
|
||||||
|
|
@ -194,6 +196,60 @@ func TestEIP2718BlockEncoding(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEIP4844BlockEncoding(t *testing.T) {
|
||||||
|
// https://github.com/ethereum/tests/blob/develop/BlockchainTests/ValidBlocks/bcEIP4844-blobtransactions/blockWithAllTransactionTypes.json
|
||||||
|
blockEnc := common.FromHex("0xf90417f90244a05eb7f6da0f3e237c62bcae48b7fb5f4506d392616b62890429c8b76b4a1d4104a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ba5e000000000000000000000000000000000000a011639dcca0b44f2acb5b630a82c8a69cb82742b3711383ec4e111a554d27aea5a05cb644f722e31f9792a8ef6e2a762334e1a862e8b40c1612e1e9507fd7121ef9a00c82719448356ba6807d6edfcd8e5aea575a5e97f36038ffb3e395749b26d41cb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a00008301482082079e42a00000000000000000000000000000000000000000000000000000000000020000880000000000000000820314a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218302000080a00000000000000000000000000000000000000000000000000000000000000000f901cbf864808203e885e8d4a5100094100000000000000000000000000000000000000a01801ca09de4adda6288582a6700dbcd8eb70c0a4a7fc9487d965f7bf22424e0bd121095a01cdb078764cc3770d5db847e99e10333aa7c356247baaf09b03eae04d64e7926b86901f86601018203e885e8d4a5100094100000000000000000000000000000000000000a0380c080a025090740da12684493e4fb466a3979e365b194e8cf462edf3c2c3be2f130bb2ea034fa18fb4c1bff4d957d72e28535d27f1352517a942aeaca0ed944085f0cd8bbb86a02f8670102018203e885e8d4a5100094100000000000000000000000000000000000000a0580c080a0352a7be5002ce111bc5167f3addf97a75e2e0b810d826af71d2caae18aed284ea065d38f8a5c8948ce706842e8861fb21020b93a4d5e489162a0e6d419a457b735b88c03f8890103018203e885e8d4a5100094100000000000000000000000000000000000000a0780c00ae1a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8809f638144c46d5de7a9e630c0e7c5c63ae829ecfd8cc94715d9c29fe17c464de0a06c5fc54c3aa868ba35ef31a4e12431611631ab7bcdceb4214dd273d83f73b5e1c0c0")
|
||||||
|
var block Block
|
||||||
|
if err := rlp.DecodeBytes(blockEnc, &block); err != nil {
|
||||||
|
t.Fatal("decode error: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
check := func(f string, got, want interface{}) {
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("%s mismatch: got %v, want %v", f, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check("Difficulty", block.Difficulty(), big.NewInt(0))
|
||||||
|
check("GasLimit", block.GasLimit(), hexutil.MustDecodeUint64("0x16345785d8a0000"))
|
||||||
|
check("GasUsed", block.GasUsed(), hexutil.MustDecodeUint64("0x14820"))
|
||||||
|
check("Coinbase", block.Coinbase(), common.HexToAddress("0xba5e000000000000000000000000000000000000"))
|
||||||
|
check("MixDigest", block.MixDigest(), common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000020000"))
|
||||||
|
check("Root", block.Root(), common.HexToHash("0x11639dcca0b44f2acb5b630a82c8a69cb82742b3711383ec4e111a554d27aea5"))
|
||||||
|
check("WithdrawalRoot", *block.Header().WithdrawalsHash, common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"))
|
||||||
|
check("Nonce", block.Nonce(), uint64(0))
|
||||||
|
check("Time", block.Time(), hexutil.MustDecodeUint64("0x79e"))
|
||||||
|
check("Size", block.Size(), uint64(len(blockEnc)))
|
||||||
|
|
||||||
|
// Create blob tx.
|
||||||
|
tx := NewTx(&BlobTx{
|
||||||
|
ChainID: uint256.NewInt(1),
|
||||||
|
Nonce: 3,
|
||||||
|
To: common.HexToAddress("0x100000000000000000000000000000000000000a"),
|
||||||
|
Gas: hexutil.MustDecodeUint64("0xe8d4a51000"),
|
||||||
|
GasTipCap: uint256.MustFromHex("0x1"),
|
||||||
|
GasFeeCap: uint256.MustFromHex("0x3e8"),
|
||||||
|
BlobFeeCap: uint256.MustFromHex("0xa"),
|
||||||
|
BlobHashes: []common.Hash{
|
||||||
|
common.BytesToHash(hexutil.MustDecode("0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")),
|
||||||
|
},
|
||||||
|
Value: uint256.MustFromHex("0x7"),
|
||||||
|
})
|
||||||
|
sig := common.Hex2Bytes("00638144c46d5de7a9e630c0e7c5c63ae829ecfd8cc94715d9c29fe17c464de06c5fc54c3aa868ba35ef31a4e12431611631ab7bcdceb4214dd273d83f73b5e100")
|
||||||
|
tx, _ = tx.WithSignature(LatestSignerForChainID(big.NewInt(1)), sig)
|
||||||
|
|
||||||
|
check("len(Transactions)", len(block.Transactions()), 4)
|
||||||
|
check("Transactions[3].Hash", block.Transactions()[3].Hash(), tx.Hash())
|
||||||
|
check("Transactions[3].Type()", block.Transactions()[3].Type(), uint8(BlobTxType))
|
||||||
|
|
||||||
|
ourBlockEnc, err := rlp.EncodeToBytes(&block)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("encode error: ", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(ourBlockEnc, blockEnc) {
|
||||||
|
t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", ourBlockEnc, blockEnc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUncleHash(t *testing.T) {
|
func TestUncleHash(t *testing.T) {
|
||||||
uncles := make([]*Header, 0)
|
uncles := make([]*Header, 0)
|
||||||
h := CalcUncleHash(uncles)
|
h := CalcUncleHash(uncles)
|
||||||
|
|
|
||||||
|
|
@ -449,14 +449,18 @@ func (tx *Transaction) BlobGasFeeCapIntCmp(other *big.Int) int {
|
||||||
// WithoutBlobTxSidecar returns a copy of tx with the blob sidecar removed.
|
// WithoutBlobTxSidecar returns a copy of tx with the blob sidecar removed.
|
||||||
func (tx *Transaction) WithoutBlobTxSidecar() *Transaction {
|
func (tx *Transaction) WithoutBlobTxSidecar() *Transaction {
|
||||||
blobtx, ok := tx.inner.(*BlobTx)
|
blobtx, ok := tx.inner.(*BlobTx)
|
||||||
if !ok {
|
if !ok || blobtx.Sidecar == nil {
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
cpy := &Transaction{
|
cpy := &Transaction{
|
||||||
inner: blobtx.withoutSidecar(),
|
inner: blobtx.withoutSidecar(),
|
||||||
time: tx.time,
|
time: tx.time,
|
||||||
}
|
}
|
||||||
// Note: tx.size cache not carried over because the sidecar is included in size!
|
if size := tx.size.Load(); size != 0 {
|
||||||
|
// The tx had a sidecar before, so we need to subtract it from the size.
|
||||||
|
scSize := rlp.ListSize(blobtx.Sidecar.encodedSize())
|
||||||
|
cpy.size.Store(size - scSize)
|
||||||
|
}
|
||||||
if h := tx.hash.Load(); h != nil {
|
if h := tx.hash.Load(); h != nil {
|
||||||
cpy.hash.Store(h)
|
cpy.hash.Store(h)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto/blake2b"
|
"github.com/ethereum/go-ethereum/crypto/blake2b"
|
||||||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/secp256r1"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"golang.org/x/crypto/ripemd160"
|
"golang.org/x/crypto/ripemd160"
|
||||||
)
|
)
|
||||||
|
|
@ -161,6 +162,14 @@ var PrecompiledContractsOsaka = PrecompiledContracts{
|
||||||
common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{},
|
common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{},
|
||||||
common.BytesToAddress([]byte{0x10}): &bls12381MapG1{},
|
common.BytesToAddress([]byte{0x10}): &bls12381MapG1{},
|
||||||
common.BytesToAddress([]byte{0x11}): &bls12381MapG2{},
|
common.BytesToAddress([]byte{0x11}): &bls12381MapG2{},
|
||||||
|
|
||||||
|
common.BytesToAddress([]byte{0x1, 0x00}): &p256Verify{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrecompiledContractsP256Verify contains the precompiled Ethereum
|
||||||
|
// contract specified in EIP-7212. This is exported for testing purposes.
|
||||||
|
var PrecompiledContractsP256Verify = PrecompiledContracts{
|
||||||
|
common.BytesToAddress([]byte{0x1, 0x00}): &p256Verify{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -1233,3 +1242,31 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
|
||||||
|
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// P256VERIFY (secp256r1 signature verification)
|
||||||
|
// implemented as a native contract
|
||||||
|
type p256Verify struct{}
|
||||||
|
|
||||||
|
// RequiredGas returns the gas required to execute the precompiled contract
|
||||||
|
func (c *p256Verify) RequiredGas(input []byte) uint64 {
|
||||||
|
return params.P256VerifyGas
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run executes the precompiled contract with given 160 bytes of param, returning the output and the used gas
|
||||||
|
func (c *p256Verify) Run(input []byte) ([]byte, error) {
|
||||||
|
const p256VerifyInputLength = 160
|
||||||
|
if len(input) != p256VerifyInputLength {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract hash, r, s, x, y from the input.
|
||||||
|
hash := input[0:32]
|
||||||
|
r, s := new(big.Int).SetBytes(input[32:64]), new(big.Int).SetBytes(input[64:96])
|
||||||
|
x, y := new(big.Int).SetBytes(input[96:128]), new(big.Int).SetBytes(input[128:160])
|
||||||
|
|
||||||
|
// Verify the signature.
|
||||||
|
if secp256r1.Verify(hash, r, s, x, y) {
|
||||||
|
return true32Byte, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
|
||||||
common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381Pairing{},
|
common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381Pairing{},
|
||||||
common.BytesToAddress([]byte{0x0f, 0x0f}): &bls12381MapG1{},
|
common.BytesToAddress([]byte{0x0f, 0x0f}): &bls12381MapG1{},
|
||||||
common.BytesToAddress([]byte{0x0f, 0x10}): &bls12381MapG2{},
|
common.BytesToAddress([]byte{0x0f, 0x10}): &bls12381MapG2{},
|
||||||
|
|
||||||
|
common.BytesToAddress([]byte{0x0b}): &p256Verify{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// EIP-152 test vectors
|
// EIP-152 test vectors
|
||||||
|
|
@ -397,3 +399,15 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
|
||||||
}
|
}
|
||||||
benchmarkPrecompiled("f0d", testcase, b)
|
benchmarkPrecompiled("f0d", testcase, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Benchmarks the sample inputs from the P256VERIFY precompile.
|
||||||
|
func BenchmarkPrecompiledP256Verify(bench *testing.B) {
|
||||||
|
t := precompiledTest{
|
||||||
|
Input: "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e",
|
||||||
|
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
Name: "p256Verify",
|
||||||
|
}
|
||||||
|
benchmarkPrecompiled("0b", t, bench)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrecompiledP256Verify(t *testing.T) { testJson("p256Verify", "0b", t) }
|
||||||
|
|
|
||||||
|
|
@ -311,10 +311,11 @@ func enable4844(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enable7939 enables EIP-7939 (CLZ opcode)
|
||||||
func enable7939(jt *JumpTable) {
|
func enable7939(jt *JumpTable) {
|
||||||
jt[CLZ] = &operation{
|
jt[CLZ] = &operation{
|
||||||
execute: opCLZ,
|
execute: opCLZ,
|
||||||
constantGas: GasFastestStep,
|
constantGas: GasFastStep,
|
||||||
minStack: minStack(1, 1),
|
minStack: minStack(1, 1),
|
||||||
maxStack: maxStack(1, 1),
|
maxStack: maxStack(1, 1),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5476
core/vm/testdata/precompiles/p256Verify.json
vendored
Normal file
5476
core/vm/testdata/precompiles/p256Verify.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
33
crypto/secp256r1/verifier.go
Normal file
33
crypto/secp256r1/verifier.go
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Package secp256r1 implements signature verification for the P256VERIFY precompile.
|
||||||
|
package secp256r1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify checks the given signature (r, s) for the given hash and public key (x, y).
|
||||||
|
func Verify(hash []byte, r, s, x, y *big.Int) bool {
|
||||||
|
if x == nil || y == nil || !elliptic.P256().IsOnCurve(x, y) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
pk := &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}
|
||||||
|
return ecdsa.Verify(pk, hash, r, s)
|
||||||
|
}
|
||||||
|
|
@ -70,7 +70,12 @@ func (a *simulatedBeaconAPI) loop() {
|
||||||
if executable, _ := a.sim.eth.TxPool().Stats(); executable == 0 {
|
if executable, _ := a.sim.eth.TxPool().Stats(); executable == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
a.sim.Commit()
|
select {
|
||||||
|
case <-a.sim.shutdownCh:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
a.sim.Commit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
||||||
|
|
@ -34,21 +34,23 @@ import (
|
||||||
// This tester can be applied to different networks, no matter it's pre-merge or
|
// This tester can be applied to different networks, no matter it's pre-merge or
|
||||||
// post-merge, but only for full-sync.
|
// post-merge, but only for full-sync.
|
||||||
type FullSyncTester struct {
|
type FullSyncTester struct {
|
||||||
stack *node.Node
|
stack *node.Node
|
||||||
backend *eth.Ethereum
|
backend *eth.Ethereum
|
||||||
target common.Hash
|
target common.Hash
|
||||||
closed chan struct{}
|
closed chan struct{}
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
exitWhenSynced bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterFullSyncTester registers the full-sync tester service into the node
|
// RegisterFullSyncTester registers the full-sync tester service into the node
|
||||||
// stack for launching and stopping the service controlled by node.
|
// stack for launching and stopping the service controlled by node.
|
||||||
func RegisterFullSyncTester(stack *node.Node, backend *eth.Ethereum, target common.Hash) (*FullSyncTester, error) {
|
func RegisterFullSyncTester(stack *node.Node, backend *eth.Ethereum, target common.Hash, exitWhenSynced bool) (*FullSyncTester, error) {
|
||||||
cl := &FullSyncTester{
|
cl := &FullSyncTester{
|
||||||
stack: stack,
|
stack: stack,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
target: target,
|
target: target,
|
||||||
closed: make(chan struct{}),
|
closed: make(chan struct{}),
|
||||||
|
exitWhenSynced: exitWhenSynced,
|
||||||
}
|
}
|
||||||
stack.RegisterLifecycle(cl)
|
stack.RegisterLifecycle(cl)
|
||||||
return cl, nil
|
return cl, nil
|
||||||
|
|
@ -76,7 +78,11 @@ func (tester *FullSyncTester) Start() error {
|
||||||
// Stop in case the target block is already stored locally.
|
// Stop in case the target block is already stored locally.
|
||||||
if block := tester.backend.BlockChain().GetBlockByHash(tester.target); block != nil {
|
if block := tester.backend.BlockChain().GetBlockByHash(tester.target); block != nil {
|
||||||
log.Info("Full-sync target reached", "number", block.NumberU64(), "hash", block.Hash())
|
log.Info("Full-sync target reached", "number", block.NumberU64(), "hash", block.Hash())
|
||||||
go tester.stack.Close() // async since we need to close ourselves
|
|
||||||
|
if tester.exitWhenSynced {
|
||||||
|
go tester.stack.Close() // async since we need to close ourselves
|
||||||
|
log.Info("Terminating the node")
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,19 +17,18 @@
|
||||||
package flags
|
package flags
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os/user"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPathExpansion(t *testing.T) {
|
func TestPathExpansion(t *testing.T) {
|
||||||
user, _ := user.Current()
|
home := HomeDir()
|
||||||
var tests map[string]string
|
var tests map[string]string
|
||||||
|
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
tests = map[string]string{
|
tests = map[string]string{
|
||||||
`/home/someuser/tmp`: `\home\someuser\tmp`,
|
`/home/someuser/tmp`: `\home\someuser\tmp`,
|
||||||
`~/tmp`: user.HomeDir + `\tmp`,
|
`~/tmp`: home + `\tmp`,
|
||||||
`~thisOtherUser/b/`: `~thisOtherUser\b`,
|
`~thisOtherUser/b/`: `~thisOtherUser\b`,
|
||||||
`$DDDXXX/a/b`: `\tmp\a\b`,
|
`$DDDXXX/a/b`: `\tmp\a\b`,
|
||||||
`/a/b/`: `\a\b`,
|
`/a/b/`: `\a\b`,
|
||||||
|
|
@ -40,7 +39,7 @@ func TestPathExpansion(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
tests = map[string]string{
|
tests = map[string]string{
|
||||||
`/home/someuser/tmp`: `/home/someuser/tmp`,
|
`/home/someuser/tmp`: `/home/someuser/tmp`,
|
||||||
`~/tmp`: user.HomeDir + `/tmp`,
|
`~/tmp`: home + `/tmp`,
|
||||||
`~thisOtherUser/b/`: `~thisOtherUser/b`,
|
`~thisOtherUser/b/`: `~thisOtherUser/b`,
|
||||||
`$DDDXXX/a/b`: `/tmp/a/b`,
|
`$DDDXXX/a/b`: `/tmp/a/b`,
|
||||||
`/a/b/`: `/a/b`,
|
`/a/b/`: `/a/b`,
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ type environment struct {
|
||||||
signer types.Signer
|
signer types.Signer
|
||||||
state *state.StateDB // apply state changes here
|
state *state.StateDB // apply state changes here
|
||||||
tcount int // tx count in cycle
|
tcount int // tx count in cycle
|
||||||
|
size uint64 // size of the block we are building
|
||||||
gasPool *core.GasPool // available gas used to pack transactions
|
gasPool *core.GasPool // available gas used to pack transactions
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
|
|
@ -63,6 +64,11 @@ type environment struct {
|
||||||
witness *stateless.Witness
|
witness *stateless.Witness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// txFits reports whether the transaction fits into the block size limit.
|
||||||
|
func (env *environment) txFitsSize(tx *types.Transaction) bool {
|
||||||
|
return env.size+tx.Size() < params.MaxBlockSize-maxBlockSizeBufferZone
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
commitInterruptNone int32 = iota
|
commitInterruptNone int32 = iota
|
||||||
commitInterruptNewHead
|
commitInterruptNewHead
|
||||||
|
|
@ -70,6 +76,11 @@ const (
|
||||||
commitInterruptTimeout
|
commitInterruptTimeout
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Block size is capped by the protocol at params.MaxBlockSize. When producing blocks, we
|
||||||
|
// try to say below the size including a buffer zone, this is to avoid going over the
|
||||||
|
// maximum size with auxiliary data added into the block.
|
||||||
|
const maxBlockSizeBufferZone = 1_000_000
|
||||||
|
|
||||||
// newPayloadResult is the result of payload generation.
|
// newPayloadResult is the result of payload generation.
|
||||||
type newPayloadResult struct {
|
type newPayloadResult struct {
|
||||||
err error
|
err error
|
||||||
|
|
@ -95,12 +106,23 @@ type generateParams struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateWork generates a sealing block based on the given parameters.
|
// generateWork generates a sealing block based on the given parameters.
|
||||||
func (miner *Miner) generateWork(params *generateParams, witness bool) *newPayloadResult {
|
func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPayloadResult {
|
||||||
work, err := miner.prepareWork(params, witness)
|
work, err := miner.prepareWork(genParam, witness)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &newPayloadResult{err: err}
|
return &newPayloadResult{err: err}
|
||||||
}
|
}
|
||||||
if !params.noTxs {
|
|
||||||
|
// Check withdrawals fit max block size.
|
||||||
|
// Due to the cap on withdrawal count, this can actually never happen, but we still need to
|
||||||
|
// check to ensure the CL notices there's a problem if the withdrawal cap is ever lifted.
|
||||||
|
maxBlockSize := params.MaxBlockSize - maxBlockSizeBufferZone
|
||||||
|
if genParam.withdrawals.Size() > maxBlockSize {
|
||||||
|
return &newPayloadResult{err: errors.New("withdrawals exceed max block size")}
|
||||||
|
}
|
||||||
|
// Also add size of withdrawals to work block size.
|
||||||
|
work.size += uint64(genParam.withdrawals.Size())
|
||||||
|
|
||||||
|
if !genParam.noTxs {
|
||||||
interrupt := new(atomic.Int32)
|
interrupt := new(atomic.Int32)
|
||||||
timer := time.AfterFunc(miner.config.Recommit, func() {
|
timer := time.AfterFunc(miner.config.Recommit, func() {
|
||||||
interrupt.Store(commitInterruptTimeout)
|
interrupt.Store(commitInterruptTimeout)
|
||||||
|
|
@ -112,8 +134,8 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
|
||||||
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
body := types.Body{Transactions: work.txs, Withdrawals: genParam.withdrawals}
|
||||||
|
|
||||||
body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals}
|
|
||||||
allLogs := make([]*types.Log, 0)
|
allLogs := make([]*types.Log, 0)
|
||||||
for _, r := range work.receipts {
|
for _, r := range work.receipts {
|
||||||
allLogs = append(allLogs, r.Logs...)
|
allLogs = append(allLogs, r.Logs...)
|
||||||
|
|
@ -256,6 +278,7 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase
|
||||||
return &environment{
|
return &environment{
|
||||||
signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time),
|
signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time),
|
||||||
state: state,
|
state: state,
|
||||||
|
size: uint64(header.Size()),
|
||||||
coinbase: coinbase,
|
coinbase: coinbase,
|
||||||
header: header,
|
header: header,
|
||||||
witness: state.Witness(),
|
witness: state.Witness(),
|
||||||
|
|
@ -273,6 +296,7 @@ func (miner *Miner) commitTransaction(env *environment, tx *types.Transaction) e
|
||||||
}
|
}
|
||||||
env.txs = append(env.txs, tx)
|
env.txs = append(env.txs, tx)
|
||||||
env.receipts = append(env.receipts, receipt)
|
env.receipts = append(env.receipts, receipt)
|
||||||
|
env.size += tx.Size()
|
||||||
env.tcount++
|
env.tcount++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -294,10 +318,12 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
env.txs = append(env.txs, tx.WithoutBlobTxSidecar())
|
txNoBlob := tx.WithoutBlobTxSidecar()
|
||||||
|
env.txs = append(env.txs, txNoBlob)
|
||||||
env.receipts = append(env.receipts, receipt)
|
env.receipts = append(env.receipts, receipt)
|
||||||
env.sidecars = append(env.sidecars, sc)
|
env.sidecars = append(env.sidecars, sc)
|
||||||
env.blobs += len(sc.Blobs)
|
env.blobs += len(sc.Blobs)
|
||||||
|
env.size += txNoBlob.Size()
|
||||||
*env.header.BlobGasUsed += receipt.BlobGasUsed
|
*env.header.BlobGasUsed += receipt.BlobGasUsed
|
||||||
env.tcount++
|
env.tcount++
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -318,7 +344,11 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
||||||
gasLimit := env.header.GasLimit
|
var (
|
||||||
|
isOsaka = miner.chainConfig.IsOsaka(env.header.Number, env.header.Time)
|
||||||
|
isCancun = miner.chainConfig.IsCancun(env.header.Number, env.header.Time)
|
||||||
|
gasLimit = env.header.GasLimit
|
||||||
|
)
|
||||||
if env.gasPool == nil {
|
if env.gasPool == nil {
|
||||||
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +404,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
// Most of the blob gas logic here is agnostic as to if the chain supports
|
// Most of the blob gas logic here is agnostic as to if the chain supports
|
||||||
// blobs or not, however the max check panics when called on a chain without
|
// blobs or not, however the max check panics when called on a chain without
|
||||||
// a defined schedule, so we need to verify it's safe to call.
|
// a defined schedule, so we need to verify it's safe to call.
|
||||||
if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) {
|
if isCancun {
|
||||||
left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
|
left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
|
||||||
if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
|
if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
|
||||||
log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
|
log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
|
||||||
|
|
@ -391,8 +421,14 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if inclusion of the transaction would put the block size over the
|
||||||
|
// maximum we allow, don't add any more txs to the payload.
|
||||||
|
if !env.txFitsSize(tx) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure all transactions after osaka have cell proofs
|
// Make sure all transactions after osaka have cell proofs
|
||||||
if miner.chainConfig.IsOsaka(env.header.Number, env.header.Time) {
|
if isOsaka {
|
||||||
if sidecar := tx.BlobTxSidecar(); sidecar != nil {
|
if sidecar := tx.BlobTxSidecar(); sidecar != nil {
|
||||||
if sidecar.Version == 0 {
|
if sidecar.Version == 0 {
|
||||||
log.Info("Including blob tx with v0 sidecar, recomputing proofs", "hash", ltx.Hash)
|
log.Info("Including blob tx with v0 sidecar, recomputing proofs", "hash", ltx.Hash)
|
||||||
|
|
@ -462,6 +498,9 @@ func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment)
|
||||||
if env.header.ExcessBlobGas != nil {
|
if env.header.ExcessBlobGas != nil {
|
||||||
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(miner.chainConfig, env.header))
|
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(miner.chainConfig, env.header))
|
||||||
}
|
}
|
||||||
|
if miner.chainConfig.IsOsaka(env.header.Number, env.header.Time) {
|
||||||
|
filter.GasLimitCap = params.MaxTxGas
|
||||||
|
}
|
||||||
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
||||||
pendingPlainTxs := miner.txpool.Pending(filter)
|
pendingPlainTxs := miner.txpool.Pending(filter)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ func (h *httpServer) start() error {
|
||||||
}
|
}
|
||||||
// Log http endpoint.
|
// Log http endpoint.
|
||||||
h.log.Info("HTTP server started",
|
h.log.Info("HTTP server started",
|
||||||
"endpoint", listener.Addr(), "auth", (h.httpConfig.jwtSecret != nil),
|
"endpoint", listener.Addr(), "auth", h.httpConfig.jwtSecret != nil,
|
||||||
"prefix", h.httpConfig.prefix,
|
"prefix", h.httpConfig.prefix,
|
||||||
"cors", strings.Join(h.httpConfig.CorsAllowedOrigins, ","),
|
"cors", strings.Join(h.httpConfig.CorsAllowedOrigins, ","),
|
||||||
"vhosts", strings.Join(h.httpConfig.Vhosts, ","),
|
"vhosts", strings.Join(h.httpConfig.Vhosts, ","),
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ const (
|
||||||
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
||||||
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
||||||
|
|
||||||
|
MaxTxGas uint64 = 30_000_000 // Maximum transaction gas limit after eip-7825.
|
||||||
|
|
||||||
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
|
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
|
||||||
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
|
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
|
||||||
SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
|
SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
|
||||||
|
|
@ -163,6 +165,8 @@ const (
|
||||||
Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation
|
Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation
|
||||||
Bls12381MapG2Gas uint64 = 23800 // Gas price for BLS12-381 mapping field element to G2 operation
|
Bls12381MapG2Gas uint64 = 23800 // Gas price for BLS12-381 mapping field element to G2 operation
|
||||||
|
|
||||||
|
P256VerifyGas uint64 = 6900 // secp256r1 elliptic curve signature verifier gas price
|
||||||
|
|
||||||
// The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529,
|
// The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529,
|
||||||
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
|
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
|
||||||
RefundQuotient uint64 = 2
|
RefundQuotient uint64 = 2
|
||||||
|
|
@ -173,8 +177,11 @@ const (
|
||||||
BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
||||||
BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs
|
BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs
|
||||||
BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile.
|
BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile.
|
||||||
|
BlobBaseCost = 1 << 13 // Base execution gas cost for a blob.
|
||||||
|
|
||||||
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
||||||
|
|
||||||
|
MaxBlockSize = 8_388_608 // maximum size of an RLP-encoded block
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation
|
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue