Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,18 +501,19 @@ func (b *Block) GetTxDependency() [][]uint64 {
}

// GetValidatorBytes extracts validator bytes from the header's Extra field.
// Returns nil if len(h.Extra) is shorter than ExtraVanityLength+ExtraSealLength.
// If you need multiple fields from BlockExtraData, prefer DecodeBlockExtraData
// to avoid redundant RLP decodes.
func (h *Header) GetValidatorBytes(chainConfig *params.ChainConfig) []byte {
if !chainConfig.IsCancun(h.Number) {
return h.Extra[ExtraVanityLength : len(h.Extra)-ExtraSealLength]
}

if len(h.Extra) < ExtraVanityLength+ExtraSealLength {
log.Error("length of extra less is than vanity and seal")
Comment thread
kajaaz marked this conversation as resolved.
Outdated
return nil
}
Comment thread
kajaaz marked this conversation as resolved.

if !chainConfig.IsCancun(h.Number) {
return h.Extra[ExtraVanityLength : len(h.Extra)-ExtraSealLength]
}

var blockExtraData BlockExtraData
if err := rlp.DecodeBytes(h.Extra[ExtraVanityLength:len(h.Extra)-ExtraSealLength], &blockExtraData); err != nil {
log.Debug("error while decoding block extra data", "err", err)
Expand Down
72 changes: 72 additions & 0 deletions core/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -931,3 +931,75 @@ func TestDecodeBlockExtraData(t *testing.T) {
t.Errorf("TxDependency mismatch: got %v, want %v", result.TxDependency, txDep)
}
}

// TestGetValidatorBytesShortExtra is a regression test for the pre-Cancun
// branch of (*Header).GetValidatorBytes panicking with
// `runtime error: slice bounds out of range` when len(Extra) < 97.
Comment thread
kajaaz marked this conversation as resolved.
Outdated
//
// Prior to the fix the pre-Cancun branch performed
//
// return h.Extra[ExtraVanityLength : len(h.Extra)-ExtraSealLength]
//
// without any length guard. The post-Cancun branch already guarded this
// path; this test exercises both branches across a range of short Extra
// lengths plus a happy-path case.
Comment thread
kajaaz marked this conversation as resolved.
func TestGetValidatorBytesShortExtra(t *testing.T) {
t.Parallel()

preCancunCfg := &params.ChainConfig{
ChainID: big.NewInt(137),
}
postCancunCfg := &params.ChainConfig{
ChainID: big.NewInt(137),
CancunBlock: big.NewInt(100),
}

cases := []struct {
name string
cfg *params.ChainConfig
blockNumber *big.Int
}{
{"pre-cancun", preCancunCfg, big.NewInt(50)},
{"post-cancun", postCancunCfg, big.NewInt(200)},
}

Comment thread
kajaaz marked this conversation as resolved.
shortLens := []int{0, 1, 32, 64, 65, 80, 96}

for _, c := range cases {
for _, n := range shortLens {
h := &Header{
Number: c.blockNumber,
Extra: make([]byte, n),
}
var got []byte
func() {
defer func() {
if r := recover(); r != nil {
t.Errorf("%s len(Extra)=%d: unexpected panic: %v", c.name, n, r)
}
}()
got = h.GetValidatorBytes(c.cfg)
}()
if got != nil {
t.Errorf("%s len(Extra)=%d: expected nil, got %x (len %d)",
c.name, n, got, len(got))
}
}
}

// Happy path (pre-Cancun): vanity + 40-byte validator entry + seal.
// Confirms the existing slice operation is preserved for valid input.
extra := make([]byte, ExtraVanityLength+40+ExtraSealLength)
for i := 0; i < 40; i++ {
extra[ExtraVanityLength+i] = byte(i + 1)
}
h := &Header{Number: big.NewInt(50), Extra: extra}
got := h.GetValidatorBytes(preCancunCfg)
if len(got) != 40 {
t.Fatalf("happy path: expected 40 bytes, got %d", len(got))
}
if !bytes.Equal(got, extra[ExtraVanityLength:ExtraVanityLength+40]) {
t.Errorf("happy path: validator bytes mismatch: got %x, want %x",
got, extra[ExtraVanityLength:ExtraVanityLength+40])
}
}
Loading