Commit 603d231a authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into add_cancel_payload

parents d64365a8 27546118
......@@ -649,9 +649,8 @@ func TestSystemMockP2P(t *testing.T) {
require.Contains(t, received, receiptVerif.BlockHash)
}
// TestSystemMockPeerScoring sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that
// the nodes can sync L2 blocks before they are confirmed on L1.
func TestSystemMockPeerScoring(t *testing.T) {
// TestSystemDenseTopology sets up a dense p2p topology with 3 verifier nodes and 1 sequencer node.
func TestSystemDenseTopology(t *testing.T) {
parallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
......@@ -682,31 +681,11 @@ func TestSystemMockPeerScoring(t *testing.T) {
cfg.Loggers["verifier2"] = testlog.Logger(t, log.LvlInfo).New("role", "verifier")
cfg.Loggers["verifier3"] = testlog.Logger(t, log.LvlInfo).New("role", "verifier")
// Construct a new sequencer with an invalid privkey to produce invalid gossip
// We can then test that the peer scoring system will ban the node
sequencer2PrivateKey := cfg.Secrets.Mallory
cfg.Nodes["sequencer2"] = &rollupNode.Config{
Driver: driver.Config{
VerifierConfDepth: 0,
SequencerConfDepth: 0,
SequencerEnabled: true,
},
// Submitter PrivKey is set in system start for rollup nodes where sequencer = true
RPC: rollupNode.RPCConfig{
ListenAddr: "127.0.0.1",
ListenPort: 0,
EnableAdmin: true,
},
L1EpochPollInterval: time.Second * 4,
P2PSigner: &p2p.PreparedSigner{Signer: p2p.NewLocalSigner(sequencer2PrivateKey)},
}
cfg.Loggers["sequencer2"] = testlog.Logger(t, log.LvlInfo).New("role", "sequencer")
// connect the nodes
cfg.P2PTopology = map[string][]string{
"verifier": {"sequencer", "sequencer2", "verifier2", "verifier3"},
"verifier2": {"sequencer", "sequencer2", "verifier", "verifier3"},
"verifier3": {"sequencer", "sequencer2", "verifier", "verifier2"},
"verifier": {"sequencer", "verifier2", "verifier3"},
"verifier2": {"sequencer", "verifier", "verifier3"},
"verifier3": {"sequencer", "verifier", "verifier2"},
}
// Set peer scoring for each node, but without banning
......@@ -719,15 +698,11 @@ func TestSystemMockPeerScoring(t *testing.T) {
}
}
var published, published2, received1, received2, received3 []common.Hash
var published, received1, received2, received3 []common.Hash
seqTracer, verifTracer, verifTracer2, verifTracer3 := new(FnTracer), new(FnTracer), new(FnTracer), new(FnTracer)
seq2Tracer := new(FnTracer)
seqTracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *eth.ExecutionPayload) {
published = append(published, payload.BlockHash)
}
seq2Tracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *eth.ExecutionPayload) {
published2 = append(published2, payload.BlockHash)
}
verifTracer.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload) {
received1 = append(received1, payload.BlockHash)
}
......@@ -738,7 +713,6 @@ func TestSystemMockPeerScoring(t *testing.T) {
received3 = append(received3, payload.BlockHash)
}
cfg.Nodes["sequencer"].Tracer = seqTracer
cfg.Nodes["sequencer2"].Tracer = seq2Tracer
cfg.Nodes["verifier"].Tracer = verifTracer
cfg.Nodes["verifier2"].Tracer = verifTracer2
cfg.Nodes["verifier3"].Tracer = verifTracer3
......@@ -748,7 +722,6 @@ func TestSystemMockPeerScoring(t *testing.T) {
defer sys.Close()
l2Seq := sys.Clients["sequencer"]
// l2Seq2 := sys.Clients["sequencer2"]
l2Verif := sys.Clients["verifier"]
l2Verif2 := sys.Clients["verifier2"]
l2Verif3 := sys.Clients["verifier3"]
......@@ -768,23 +741,23 @@ func TestSystemMockPeerScoring(t *testing.T) {
Gas: 21000,
})
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
require.NoError(t, err, "Sending L2 tx to sequencer")
// Wait for tx to be mined on the L2 sequencer chain
receiptSeq, err := waitForTransaction(tx.Hash(), l2Seq, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
receiptSeq, err := waitForTransaction(tx.Hash(), l2Seq, 10*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.NoError(t, err, "Waiting for L2 tx on sequencer")
// Wait until the block it was first included in shows up in the safe chain on the verifier
receiptVerif, err := waitForTransaction(tx.Hash(), l2Verif, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier")
receiptVerif, err := waitForTransaction(tx.Hash(), l2Verif, 10*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.NoError(t, err, "Waiting for L2 tx on verifier")
require.Equal(t, receiptSeq, receiptVerif)
receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif2, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier2")
receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif2, 10*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.NoError(t, err, "Waiting for L2 tx on verifier2")
require.Equal(t, receiptSeq, receiptVerif)
receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif3, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier3")
receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif3, 10*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.NoError(t, err, "Waiting for L2 tx on verifier3")
require.Equal(t, receiptSeq, receiptVerif)
// Verify that everything that was received was published
......@@ -799,37 +772,6 @@ func TestSystemMockPeerScoring(t *testing.T) {
require.Contains(t, received1, receiptVerif.BlockHash)
require.Contains(t, received2, receiptVerif.BlockHash)
require.Contains(t, received3, receiptVerif.BlockHash)
// Submit TX to the second (malicious) sequencer node
// toAddr = common.Address{0xff, 0xff}
// maliciousTx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{
// ChainID: cfg.L2ChainIDBig(),
// Nonce: 1,
// To: &toAddr,
// Value: big.NewInt(1_000_000_000),
// GasTipCap: big.NewInt(10),
// GasFeeCap: big.NewInt(200),
// Gas: 21000,
// })
// err = l2Seq2.SendTransaction(context.Background(), maliciousTx)
// require.Nil(t, err, "Sending L2 tx to sequencer")
// Wait for tx to be mined on the L2 sequencer chain
// receiptSeq, err = waitForTransaction(maliciousTx.Hash(), l2Seq2, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
// require.Nil(t, err, "Waiting for L2 tx on sequencer")
// Wait until the block it was first included in shows up in the safe chain on the verifier
// receiptVerif, err = waitForTransaction(maliciousTx.Hash(), l2Verif, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
// require.Nil(t, err, "Waiting for L2 tx on verifier")
// require.Equal(t, receiptSeq, receiptVerif)
// receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif2, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
// require.Nil(t, err, "Waiting for L2 tx on verifier2")
// require.Equal(t, receiptSeq, receiptVerif)
// receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif3, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
// require.Nil(t, err, "Waiting for L2 tx on verifier3")
// require.Equal(t, receiptSeq, receiptVerif)
}
func TestL1InfoContract(t *testing.T) {
......
......@@ -928,10 +928,11 @@ follows:
- `timestamp` is set to the batch's timestamp.
- `random` is set to the `prev_randao` L1 block attribute.
- `suggestedFeeRecipient` is set to an address determined by the sequencer.
- `suggestedFeeRecipient` is set to the Sequencer Fee Vault address. See [Fee Vaults] specification.
- `transactions` is the array of the derived transactions: deposited transactions and sequenced transactions, all
encoded with [EIP-2718].
- `noTxPool` is set to `true`, to use the exact above `transactions` list when constructing the block.
- `gasLimit` is set to the current `gasLimit` value in the [system configuration][g-system-config] of this payload.
[extended-attributes]: exec-engine.md#extended-payloadattributesv1
[Fee Vaults]: exec-engine.md#fee-vaults
......@@ -6,6 +6,11 @@
- [Deposited transaction processing](#deposited-transaction-processing)
- [Deposited transaction boundaries](#deposited-transaction-boundaries)
- [Fees](#fees)
- [Fee Vaults](#fee-vaults)
- [Priority fees (Sequencer Fee Vault)](#priority-fees-sequencer-fee-vault)
- [Base fees (Base Fee Vault)](#base-fees-base-fee-vault)
- [L1-Cost fees (L1 Fee Vault)](#l1-cost-fees-l1-fee-vault)
- [Engine API](#engine-api)
- [`engine_forkchoiceUpdatedV1`](#engine_forkchoiceupdatedv1)
- [Extended PayloadAttributesV1](#extended-payloadattributesv1)
......@@ -46,6 +51,74 @@ To process deposited transactions safely, the deposits MUST be authenticated fir
Deposited transactions MUST never be consumed from the transaction pool.
*The transaction pool can be disabled in a deposits-only rollup*
## Fees
Sequenced transactions (i.e. not applicable to deposits) are charged with 3 types of fees:
priority fees, base fees, and L1-cost fees.
### Fee Vaults
The three types of fees are collected in 3 distinct L2 fee-vault deployments for accounting purposes:
fee payments are not registered as internal EVM calls, and thus distinguished better this way.
These are hardcoded addresses, pointing at pre-deployed proxy contracts.
The proxies are backed by vault contract deployments, based on `FeeVault`, to route vault funds to L1 securely.
| Vault Name | Predeploy |
|---------------------|----------------------------------------------------------|
| Sequencer Fee Vault | [`SequencerFeeVault`](./predeploys.md#SequencerFeeVault) |
| Base Fee Vault | [`BaseFeeVault`](./predeploys.md#BaseFeeVault) |
| L1 Fee Vault | [`L1FeeVault`](./predeploys.md#L1FeeVault) |
### Priority fees (Sequencer Fee Vault)
Priority fees follow the [eip-1559] specification, and are collected by the fee-recipient of the L2 block.
The block fee-recipient (a.k.a. coinbase address) is set to the Sequencer Fee Vault address.
### Base fees (Base Fee Vault)
Base fees largely follow the [eip-1559] specification, with the exception that base fees are not burned,
but add up to the Base Fee Vault ETH account balance.
### L1-Cost fees (L1 Fee Vault)
The protocol funds batch-submission of sequenced L2 transactions by charging L2 users an additional fee
based on the estimated batch-submission costs.
This fee is charged from the L2 transaction-sender ETH balance, and collected into the L1 Fee Vault.
The exact L1 cost function to determine the L1-cost fee component of a L2 transaction is calculated as:
`(rollupDataGas + l1FeeOverhead) * l1Basefee * l1FeeScalar / 1000000`
(big-int computation, result in Wei and `uint256` range)
Where:
- `rollupDataGas` is determined from the *full* encoded transaction
(standard EIP-2718 transaction encoding, including signature fields):
- Before Regolith fork: `rollupDataGas = zeroes * 4 + (ones + 68) * 16`
- The addition of `68` non-zero bytes is a remnant of a pre-Bedrock L1-cost accounting function,
which accounted for the worst-case non-zero bytes addition to complement unsigned transactions, unlike Bedrock.
- With Regolith fork: `rollupDataGas = zeroes * 4 + ones * 16`
- `l1FeeOverhead` is the Gas Price Oracle `overhead` value.
- `l1FeeScalar` is the Gas Price Oracle `scalar` value.
- `l1Basefee` is the L1 Base fee of the latest L1 origin registered in the L2 chain.
Note that the `rollupDataGas` uses the same byte cost accounting as defined in [eip-2028],
except the full L2 transaction now counts towards the bytes charged in the L1 calldata.
This behavior matches pre-Bedrock L1-cost estimation of L2 transactions.
Compression, batching, and intrinsic gas costs of the batch transactions are accounted for by the protocol
with the Gas Price Oracle `overhead` and `scalar` parameters.
The Gas Price Oracle `l1FeeOverhead` and `l1FeeScalar`, as well as the `l1Basefee` of the L1 origin,
can be accessed in two interchangeable ways:
- read from the deposited L1 attributes (`l1FeeOverhead`, `l1FeeScalar`, `basefee`) of the current L2 block
- read from the L1 Block Info contract (`0x4200000000000000000000000000000000000015`)
- using the respective solidity `uint256`-getter functions (`l1FeeOverhead`, `l1FeeScalar`, `basefee`)
- using direct storage-reads:
- L1 basefee as big-endian `uint256` in slot `1`
- Overhead as big-endian `uint256` in slot `5`
- Scalar as big-endian `uint256` in slot `6`
## Engine API
<!--
......@@ -190,6 +263,8 @@ the operation within the engine is the exact same as with L1 (although with an E
[rollup node spec]: rollup-node.md
[eip-1559]: https://eips.ethereum.org/EIPS/eip-1559
[eip-2028]: https://eips.ethereum.org/EIPS/eip-2028
[eip-2718]: https://eips.ethereum.org/EIPS/eip-2718
[eip-2718-transactions]: https://eips.ethereum.org/EIPS/eip-2718#transactions
[exec-api-data]: https://github.com/ethereum/execution-apis/blob/769c53c94c4e487337ad0edea9ee0dce49c79bfa/src/engine/specification.md#structures
......
......@@ -80,8 +80,10 @@ Summary of changes:
including the `contractAddress` field of deposits that deploy contracts.
- The `gas` and `depositNonce` data is committed to as part of the consensus-representation of the receipt,
enabling the data to be safely synced between independent L2 nodes.
- The L1-cost function was corrected to more closely match pre-Bedrock behavior.
The [deposit specification](./deposits.md) specifies the changes of the Regolith upgrade in more detail.
The [deposit specification](./deposits.md) specifies the deposit changes of the Regolith upgrade in more detail.
The [execution engine specification](./exec-engine.md) specifies the L1 cost function difference.
The Regolith upgrade uses a *L2 block-timestamp* activation-rule, and is specified in both the
rollup-node (`regolith_time`) and execution engine (`config.regolithTime`).
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment