mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
feat(core): add optional isForcedInclusion and Signature to L1Origin (#434)
* add isForcedInclusion to L1Origin * test * update file fash * add signature * use [65]byte * add helper method * build * comment * fix legacy, add test * return nil if empty
This commit is contained in:
parent
17fbc6b74c
commit
a1fe1d8309
5 changed files with 142 additions and 22 deletions
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
|
@ -2,7 +2,7 @@ name: "Push multi-arch docker image to GAR"
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [taiko]
|
||||
branches: [taiko, is_forced_inclusion]
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# version:spec-tests pectra-devnet-6@v1.0.0
|
||||
# https://github.com/ethereum/execution-spec-tests/releases
|
||||
# https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-6%40v1.0.0/fixtures_pectra-devnet-6.tar.gz
|
||||
b69211752a3029083c020dc635fe12156ca1a6725a08559da540a0337586a77e fixtures_pectra-devnet-6.tar.gz
|
||||
5ed3bec40a02776a4096c17b84b59fb20fd99fbabba8101fdac3d35a001cf82a fixtures_pectra-devnet-6.tar.gz
|
||||
|
||||
# version:golang 1.24.1
|
||||
# https://go.dev/dl/
|
||||
|
|
|
|||
|
|
@ -29,6 +29,17 @@ func l1OriginKey(blockID *big.Int) []byte {
|
|||
|
||||
// L1Origin represents a L1Origin of a L2 block.
|
||||
type L1Origin struct {
|
||||
BlockID *big.Int `json:"blockID" gencodec:"required"`
|
||||
L2BlockHash common.Hash `json:"l2BlockHash"`
|
||||
L1BlockHeight *big.Int `json:"l1BlockHeight" rlp:"optional"`
|
||||
L1BlockHash common.Hash `json:"l1BlockHash" rlp:"optional"`
|
||||
IsForcedInclusion bool `json:"isForcedInclusion" rlp:"optional"`
|
||||
Signature [65]byte `json:"signature" rlp:"optional"` // signature of the envelope via p2p
|
||||
BuildPayloadArgsID [8]byte `json:"buildPayloadArgsID" rlp:"optional"`
|
||||
}
|
||||
|
||||
// L1OriginLegacyTwo represents a second legacy L1Origin of a L2 block.
|
||||
type L1OriginLegacyTwo struct {
|
||||
BlockID *big.Int `json:"blockID" gencodec:"required"`
|
||||
L2BlockHash common.Hash `json:"l2BlockHash"`
|
||||
L1BlockHeight *big.Int `json:"l1BlockHeight" rlp:"optional"`
|
||||
|
|
@ -70,32 +81,49 @@ func WriteL1Origin(db ethdb.KeyValueWriter, blockID *big.Int, l1Origin *L1Origin
|
|||
// ReadL1Origin retrieves the given L2 block's L1Origin from database.
|
||||
func ReadL1Origin(db ethdb.KeyValueReader, blockID *big.Int) (*L1Origin, error) {
|
||||
data, _ := db.Get(l1OriginKey(blockID))
|
||||
|
||||
if len(data) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// First try to decode the new version (with new fields).
|
||||
l1Origin := new(L1Origin)
|
||||
if err := rlp.Decode(bytes.NewReader(data), l1Origin); err != nil {
|
||||
// If decoding the new version fails, try to decode the legacy version (without new fields).
|
||||
l1OriginLegacy := new(L1OriginLegacy)
|
||||
if err := rlp.Decode(bytes.NewReader(data), &l1OriginLegacy); err != nil {
|
||||
return nil, fmt.Errorf("invalid legacy L1Origin RLP bytes: %w", err)
|
||||
}
|
||||
|
||||
// If decoding legacy version succeeds, manually
|
||||
// construct the new L1Origin with default values for the new fields.
|
||||
l1Origin = &L1Origin{
|
||||
BlockID: l1OriginLegacy.BlockID,
|
||||
L2BlockHash: l1OriginLegacy.L2BlockHash,
|
||||
L1BlockHeight: l1OriginLegacy.L1BlockHeight,
|
||||
L1BlockHash: l1OriginLegacy.L1BlockHash,
|
||||
// Set BuildPayloadArgsID to an empty hash as the intended default for legacy L1Origin conversions.
|
||||
BuildPayloadArgsID: [8]byte{},
|
||||
}
|
||||
// try to decode standard L1Origin first
|
||||
var o L1Origin
|
||||
if err := rlp.Decode(bytes.NewReader(data), &o); err == nil {
|
||||
return &o, nil
|
||||
}
|
||||
|
||||
return l1Origin, nil
|
||||
// 3) try second legacy version, which includes BuildPayloadArgsID
|
||||
var o2 L1OriginLegacyTwo
|
||||
if err := rlp.Decode(bytes.NewReader(data), &o2); err == nil {
|
||||
return &L1Origin{
|
||||
BlockID: o2.BlockID,
|
||||
L2BlockHash: o2.L2BlockHash,
|
||||
L1BlockHeight: o2.L1BlockHeight,
|
||||
L1BlockHash: o2.L1BlockHash,
|
||||
BuildPayloadArgsID: o2.BuildPayloadArgsID,
|
||||
// new fields default to zero/false:
|
||||
IsForcedInclusion: false,
|
||||
Signature: [65]byte{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 4) try original legacy version (no BuildPayloadArgsID, IsForcedInclusio nor Signature)
|
||||
var o1 L1OriginLegacy
|
||||
if err := rlp.Decode(bytes.NewReader(data), &o1); err == nil {
|
||||
return &L1Origin{
|
||||
BlockID: o1.BlockID,
|
||||
L2BlockHash: o1.L2BlockHash,
|
||||
L1BlockHeight: o1.L1BlockHeight,
|
||||
L1BlockHash: o1.L1BlockHash,
|
||||
// new fields default to zero/false:
|
||||
IsForcedInclusion: false,
|
||||
Signature: [65]byte{},
|
||||
BuildPayloadArgsID: [8]byte{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 5) nothing worked
|
||||
return nil, fmt.Errorf("invalid L1Origin RLP bytes: failed new, legacyTwo and legacyOne decodes")
|
||||
}
|
||||
|
||||
// WriteHeadL1Origin stores the given L1Origin as the last L1Origin.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -39,6 +40,8 @@ func TestL1Origin(t *testing.T) {
|
|||
L1BlockHeight: nil,
|
||||
L1BlockHash: randomHash(),
|
||||
BuildPayloadArgsID: [8]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
IsForcedInclusion: true,
|
||||
Signature: [65]byte{0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10},
|
||||
}
|
||||
WriteL1Origin(db, testL1Origin.BlockID, testL1Origin)
|
||||
l1Origin, err := ReadL1Origin(db, testL1Origin.BlockID)
|
||||
|
|
@ -49,6 +52,8 @@ func TestL1Origin(t *testing.T) {
|
|||
assert.True(t, l1Origin.L1BlockHeight.Cmp(common.Big0) == 0)
|
||||
assert.Equal(t, testL1Origin.L1BlockHash, l1Origin.L1BlockHash)
|
||||
assert.Equal(t, testL1Origin.BuildPayloadArgsID, l1Origin.BuildPayloadArgsID)
|
||||
assert.Equal(t, testL1Origin.IsForcedInclusion, l1Origin.IsForcedInclusion)
|
||||
assert.Equal(t, testL1Origin.Signature, l1Origin.Signature)
|
||||
}
|
||||
|
||||
func TestHeadL1Origin(t *testing.T) {
|
||||
|
|
@ -60,3 +65,78 @@ func TestHeadL1Origin(t *testing.T) {
|
|||
require.NotNil(t, blockID)
|
||||
assert.Equal(t, testBlockID, blockID)
|
||||
}
|
||||
|
||||
func TestReadL1OriginFallbacks(t *testing.T) {
|
||||
db := NewMemoryDatabase()
|
||||
|
||||
t.Run("LegacyTwo → L1Origin", func(t *testing.T) {
|
||||
// prepare a second‐legacy L1Origin
|
||||
blockID := randomBigInt()
|
||||
height := randomBigInt()
|
||||
l2Hash := randomHash()
|
||||
l1Hash := randomHash()
|
||||
buildID := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
legacyTwo := &L1OriginLegacyTwo{
|
||||
BlockID: blockID,
|
||||
L2BlockHash: l2Hash,
|
||||
L1BlockHeight: height,
|
||||
L1BlockHash: l1Hash,
|
||||
BuildPayloadArgsID: buildID,
|
||||
}
|
||||
|
||||
// encode & write raw RLP
|
||||
data, err := rlp.EncodeToBytes(legacyTwo)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.Put(l1OriginKey(blockID), data))
|
||||
|
||||
// read back via our helper
|
||||
got, err := ReadL1Origin(db, blockID)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, got)
|
||||
|
||||
// verify fields
|
||||
assert.Equal(t, blockID, got.BlockID)
|
||||
assert.Equal(t, l2Hash, got.L2BlockHash)
|
||||
assert.True(t, got.L1BlockHeight.Cmp(height) == 0)
|
||||
assert.Equal(t, l1Hash, got.L1BlockHash)
|
||||
assert.Equal(t, buildID, got.BuildPayloadArgsID)
|
||||
assert.False(t, got.IsForcedInclusion)
|
||||
assert.Equal(t, [65]byte{}, got.Signature)
|
||||
})
|
||||
|
||||
t.Run("LegacyOne → L1Origin", func(t *testing.T) {
|
||||
// prepare the original legacy L1Origin
|
||||
blockID := randomBigInt()
|
||||
height := randomBigInt()
|
||||
l2Hash := randomHash()
|
||||
l1Hash := randomHash()
|
||||
|
||||
legacyOne := &L1OriginLegacy{
|
||||
BlockID: blockID,
|
||||
L2BlockHash: l2Hash,
|
||||
L1BlockHeight: height,
|
||||
L1BlockHash: l1Hash,
|
||||
}
|
||||
|
||||
// encode & write raw RLP
|
||||
data, err := rlp.EncodeToBytes(legacyOne)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.Put(l1OriginKey(blockID), data))
|
||||
|
||||
// read back via our helper
|
||||
got, err := ReadL1Origin(db, blockID)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, got)
|
||||
|
||||
// verify fields
|
||||
assert.Equal(t, blockID, got.BlockID)
|
||||
assert.Equal(t, l2Hash, got.L2BlockHash)
|
||||
assert.True(t, got.L1BlockHeight.Cmp(height) == 0)
|
||||
assert.Equal(t, l1Hash, got.L1BlockHash)
|
||||
// new fields should be zero-default
|
||||
assert.Equal(t, [8]byte{}, got.BuildPayloadArgsID)
|
||||
assert.False(t, got.IsForcedInclusion)
|
||||
assert.Equal(t, [65]byte{}, got.Signature)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,18 @@ func (a *TaikoAuthAPIBackend) UpdateL1Origin(l1Origin *rawdb.L1Origin) *rawdb.L1
|
|||
return l1Origin
|
||||
}
|
||||
|
||||
func (a *TaikoAuthAPIBackend) SetL1OriginSignature(blockID *big.Int, signature [65]byte) (*rawdb.L1Origin, error) {
|
||||
l1Origin, err := rawdb.ReadL1Origin(a.eth.ChainDb(), blockID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l1Origin.Signature = signature
|
||||
rawdb.WriteL1Origin(a.eth.ChainDb(), blockID, l1Origin)
|
||||
|
||||
return l1Origin, nil
|
||||
}
|
||||
|
||||
// TxPoolContent retrieves the transaction pool content with the given upper limits.
|
||||
func (a *TaikoAuthAPIBackend) TxPoolContent(
|
||||
beneficiary common.Address,
|
||||
|
|
|
|||
Loading…
Reference in a new issue