|
| 1 | +//go:build simulated |
| 2 | + |
| 3 | +// SPDX-License-Identifier: BUSL-1.1 |
| 4 | +// |
| 5 | +// Copyright (C) 2025, Berachain Foundation. All rights reserved. |
| 6 | +// Use of this software is governed by the Business Source License included |
| 7 | +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. |
| 8 | +// |
| 9 | +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY |
| 10 | +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER |
| 11 | +// VERSIONS OF THE LICENSED WORK. |
| 12 | +// |
| 13 | +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF |
| 14 | +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF |
| 15 | +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). |
| 16 | +// |
| 17 | +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON |
| 18 | +// AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, |
| 19 | +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF |
| 20 | +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND |
| 21 | +// TITLE. |
| 22 | + |
| 23 | +package simulated_test |
| 24 | + |
| 25 | +import ( |
| 26 | + "time" |
| 27 | + |
| 28 | + ctypes "github.com/berachain/beacon-kit/consensus-types/types" |
| 29 | + "github.com/berachain/beacon-kit/da/kzg" |
| 30 | + datypes "github.com/berachain/beacon-kit/da/types" |
| 31 | + "github.com/berachain/beacon-kit/primitives/common" |
| 32 | + "github.com/berachain/beacon-kit/primitives/crypto" |
| 33 | + "github.com/berachain/beacon-kit/primitives/eip4844" |
| 34 | + "github.com/berachain/beacon-kit/primitives/math" |
| 35 | + "github.com/berachain/beacon-kit/testing/simulated" |
| 36 | + "github.com/stretchr/testify/require" |
| 37 | +) |
| 38 | + |
| 39 | +// TestOrphanedBlobCleanup tests that orphaned blob sidecars are properly cleaned up on node restart. |
| 40 | +// This simulates the scenario where sidecars are saved to disk but the block finalization fails. |
| 41 | +func (s *SimulatedSuite) TestOrphanedBlobCleanup() { |
| 42 | + // Initialize chain and move forward two blocks. |
| 43 | + s.InitializeChain(s.T()) |
| 44 | + nodeAddress, err := s.SimComet.GetNodeAddress() |
| 45 | + s.Require().NoError(err) |
| 46 | + s.SimComet.Comet.SetNodeAddress(nodeAddress) |
| 47 | + |
| 48 | + _, _, proposalTime := s.MoveChainToHeight(s.T(), 1, 2, nodeAddress, time.Now()) |
| 49 | + |
| 50 | + // Get the last committed block height. |
| 51 | + lastBlockHeight := s.SimComet.Comet.CommitMultiStore().LastCommitID().Version |
| 52 | + orphanedSlot := math.Slot(lastBlockHeight + 1) |
| 53 | + |
| 54 | + // Create and persist orphaned blob sidecars. |
| 55 | + // This simulates FinalizeSidecars succeeding but finalizeBeaconBlock failing. |
| 56 | + orphanedSidecars := createOrphanedSidecars(s.T(), orphanedSlot, s.TestNode.KZGVerifier) |
| 57 | + err = s.TestNode.StorageBackend.AvailabilityStore().Persist(orphanedSidecars) |
| 58 | + s.Require().NoError(err) |
| 59 | + |
| 60 | + // Verify orphaned blobs exist. |
| 61 | + sidecars, err := s.TestNode.StorageBackend.AvailabilityStore().GetBlobSidecars(orphanedSlot) |
| 62 | + s.Require().NoError(err) |
| 63 | + s.Require().Len(sidecars, 1) |
| 64 | + |
| 65 | + // Simulate node restart by calling PruneOrphanedBlobs. |
| 66 | + err = s.TestNode.Blockchain.PruneOrphanedBlobs(lastBlockHeight) |
| 67 | + s.Require().NoError(err) |
| 68 | + |
| 69 | + // Verify orphaned blobs were cleaned up. |
| 70 | + sidecars, err = s.TestNode.StorageBackend.AvailabilityStore().GetBlobSidecars(orphanedSlot) |
| 71 | + s.Require().NoError(err) |
| 72 | + s.Require().Empty(sidecars) |
| 73 | + |
| 74 | + // Verify chain continues normally. |
| 75 | + proposals, _, _ := s.MoveChainToHeight(s.T(), 3, 1, nodeAddress, proposalTime) |
| 76 | + s.Require().Len(proposals, 1) |
| 77 | +} |
| 78 | + |
| 79 | +// createOrphanedSidecars creates fake blob sidecars for testing orphaned blob cleanup. |
| 80 | +func createOrphanedSidecars( |
| 81 | + t require.TestingT, |
| 82 | + slot math.Slot, |
| 83 | + verifier kzg.BlobProofVerifier, |
| 84 | +) datypes.BlobSidecars { |
| 85 | + blobs := []*eip4844.Blob{{1, 2, 3}} |
| 86 | + proofs, commitments := simulated.GetProofAndCommitmentsForBlobs(require.New(t), blobs, verifier) |
| 87 | + |
| 88 | + sidecars := make(datypes.BlobSidecars, len(blobs)) |
| 89 | + for i := range blobs { |
| 90 | + sidecars[i] = datypes.BuildBlobSidecar( |
| 91 | + math.U64(i), |
| 92 | + &ctypes.SignedBeaconBlockHeader{ |
| 93 | + Header: &ctypes.BeaconBlockHeader{Slot: slot}, |
| 94 | + Signature: crypto.BLSSignature{}, |
| 95 | + }, |
| 96 | + blobs[i], |
| 97 | + commitments[i], |
| 98 | + proofs[i], |
| 99 | + make([]common.Root, ctypes.KZGInclusionProofDepth), |
| 100 | + ) |
| 101 | + } |
| 102 | + return sidecars |
| 103 | +} |
0 commit comments