Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions cmd/integration/commands/stages.go
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,7 @@ func newSync(ctx context.Context, db kv.TemporalRwDB, miningConfig *buildercfg.M
maxBlockBroadcastPeers,
false, /* disableBlockDownload */
false, /* enableWitProtocol */
nil, /* bridgeReader */
logger,
)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ func ExecuteBlockEphemerally(
logs = append(logs, receipt.Logs...)
}

// PIP-74 state-sync receipt handling.
stateSyncReceipt := &types.Receipt{}
if chainConfig.Consensus == chain.BorConsensus && len(blockLogs) > 0 {
slices.SortStableFunc(blockLogs, func(i, j *types.Log) int { return cmp.Compare(i.Index, j.Index) })
Expand Down
9 changes: 9 additions & 0 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,14 @@ func New(ctx context.Context, stack *node.Node, config *ethconfig.Config, logger
}
}

// Create bridge.Reader for P2P state sync receipts.
// When Erigon nodes serve receipts to peers via P2P, they need bridge.Reader
// to include state sync transaction receipts in the response.
var bridgeReaderForP2P *bridge.Reader
if bridgeStore != nil && chainConfig.Bor != nil {
bridgeReaderForP2P = bridge.NewReader(bridgeStore, logger, chainConfig.Bor.StateReceiverContractAddress())
}

sentryMcDisableBlockDownload := chainConfig.Bor != nil || config.ElBlockDownloaderV2
backend.sentriesClient, err = sentry_multi_client.NewMultiClient(
backend.chainDB,
Expand All @@ -723,6 +731,7 @@ func New(ctx context.Context, stack *node.Node, config *ethconfig.Config, logger
maxBlockBroadcastPeers,
sentryMcDisableBlockDownload,
stack.Config().P2P.EnableWitProtocol,
bridgeReaderForP2P,
logger,
)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion execution/stages/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,9 @@ func testReorgLong(t *testing.T) {

// Tests that reorganising a short difficult chain after a long easy one
// overwrites the canonical numbers and links in the database.
func TestReorgShortBlocks(t *testing.T) { testReorgShort(t) }
func TestReorgShortBlocks(t *testing.T) {
testReorgShort(t)
}

func testReorgShort(t *testing.T) {
t.Parallel()
Expand Down
3 changes: 2 additions & 1 deletion execution/stages/mock/mock_sentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ func MockWithEverything(tb testing.TB, gspec *types.Genesis, key *ecdsa.PrivateK
PeerId: gointerfaces.ConvertHashToH512([64]byte{0x12, 0x34, 0x50}), // "12345"
BlockSnapshots: allSnapshots,
BlockReader: br,
ReceiptsReader: receipts.NewGenerator(br, engine, 5*time.Second),
ReceiptsReader: receipts.NewGenerator(br, engine, 5*time.Second, nil),
HistoryV3: true,
cfg: cfg,
}
Expand Down Expand Up @@ -441,6 +441,7 @@ func MockWithEverything(tb testing.TB, gspec *types.Genesis, key *ecdsa.PrivateK
maxBlockBroadcastPeers,
false, /* disableBlockDownload */
false, /* enableWitProtocol */
nil, /* bridgeReader */
logger,
)
if err != nil {
Expand Down
18 changes: 17 additions & 1 deletion execution/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,9 +575,25 @@ func (e receiptEncoder69) EncodeRLP(w io.Writer) error { return e.r.EncodeRLP69(

func (rs Receipts) EncodeRLP69(w io.Writer) error {
encs := make([]receiptEncoder69, len(rs))
n := len(rs)

for i := range rs {
encs[i] = receiptEncoder69{r: rs[i]}
// Copy the receipt reference.
r := rs[i]

// Only the last receipt can be a state-sync tx.
if i == n-1 {
// Match the ReadStateSyncReceiptByHash logic:
// It's a state-sync transaction if the cumulative gas is zero, or
// the equal cumulative gas is equal to the previous one (zero gas usage)
if r.CumulativeGasUsed == 0 || (n >= 2 && r.CumulativeGasUsed == rs[n-2].CumulativeGasUsed) {
r.Type = 0
}
}

encs[i] = receiptEncoder69{r: r}
}

return rlp.Encode(w, encs)
}

Expand Down
1 change: 1 addition & 0 deletions p2p/protocols/eth/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ type StatusPacket struct {
type StatusPacket69 struct {
ProtocolVersion uint32
NetworkID uint64
TD *big.Int
Genesis common.Hash
ForkID forkid.ID
MinimumBlock, LatestBlock uint64
Expand Down
2 changes: 2 additions & 0 deletions p2p/sentry/eth_handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,12 @@ func encodeStatusPacket(status *sentryproto.StatusData, version uint) eth.Status
}

func encodeStatusPacket69(status *sentryproto.StatusData, version uint) eth.StatusPacket69 {
ourTD := gointerfaces.ConvertH256ToUint256Int(status.TotalDifficulty)
genesisHash := gointerfaces.ConvertH256ToHash(status.ForkData.Genesis)
return eth.StatusPacket69{
ProtocolVersion: uint32(version),
NetworkID: status.NetworkId,
TD: ourTD.ToBig(),
Genesis: genesisHash,
ForkID: forkid.NewIDFromForks(status.ForkData.HeightForks, status.ForkData.TimeForks, genesisHash, status.MaxBlockHeight, status.MaxBlockTime),
MinimumBlock: status.MinimumBlockHeight,
Expand Down
16 changes: 15 additions & 1 deletion p2p/sentry/sentry_multi_client/sentry_multi_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ type MultiClient struct {

var _ eth.ReceiptsGetter = new(receipts.Generator) // compile-time interface-check

// bridgeReader interface for reading bridge events (state sync).
type bridgeReader interface {
Events(ctx context.Context, blockHash common.Hash, blockNum uint64) ([]*types.Message, error)
EventTxnLookup(ctx context.Context, borTxHash common.Hash) (uint64, bool, error)
}

func NewMultiClient(
db kv.TemporalRoDB,
chainConfig *chain.Config,
Expand All @@ -297,6 +303,7 @@ func NewMultiClient(
maxBlockBroadcastPeers func(*types.Header) uint,
disableBlockDownload bool,
enableWitProtocol bool,
bridgeReader bridgeReader,
logger log.Logger,
) (*MultiClient, error) {
// header downloader
Expand Down Expand Up @@ -338,6 +345,13 @@ func NewMultiClient(
witnessBuffer = stagedsync.NewWitnessBuffer()
}

// Create BorGenerator for state sync receipts if bridgeReader is provided.
// This is required for Erigon to include state sync transaction receipts in P2P GetReceipts responses.
var borGenerator *receipts.BorGenerator
if bridgeReader != nil {
borGenerator = receipts.NewBorGenerator(blockReader, engine, bridgeReader)
}

cs := &MultiClient{
Hd: hd,
Bd: bd,
Expand All @@ -354,7 +368,7 @@ func NewMultiClient(
disableBlockDownload: disableBlockDownload,
logger: logger,
getReceiptsActiveGoroutineNumber: semaphore.NewWeighted(1),
ethApiWrapper: receipts.NewGenerator(blockReader, engine, 5*time.Minute),
ethApiWrapper: receipts.NewGenerator(blockReader, engine, 5*time.Minute, borGenerator),
}

return cs, nil
Expand Down
6 changes: 4 additions & 2 deletions rpc/jsonrpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ func NewBaseApi(f *rpchelper.Filters, stateCache kvcache.Cache, blockReader serv
panic(err)
}

borReceiptGenerator := receipts.NewBorGenerator(blockReader, engine, bridgeReader)

return &BaseAPI{
filters: f,
stateCache: stateCache,
Expand All @@ -166,8 +168,8 @@ func NewBaseApi(f *rpchelper.Filters, stateCache kvcache.Cache, blockReader serv
_txNumReader: blockReader.TxnumReader(context.Background()),
evmCallTimeout: evmCallTimeout,
_engine: engine,
receiptsGenerator: receipts.NewGenerator(blockReader, engine, evmCallTimeout),
borReceiptGenerator: receipts.NewBorGenerator(blockReader, engine),
receiptsGenerator: receipts.NewGenerator(blockReader, engine, evmCallTimeout, borReceiptGenerator),
borReceiptGenerator: borReceiptGenerator,
dirs: dirs,
bridgeReader: bridgeReader,
}
Expand Down
20 changes: 17 additions & 3 deletions rpc/jsonrpc/eth_receipts.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,13 +527,27 @@ func (api *APIImpl) GetBlockReceipts(ctx context.Context, numberOrHash rpc.Block
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
}

numTxs := len(block.Transactions())
result := make([]map[string]interface{}, 0, len(receipts))

for _, receipt := range receipts {
txn := block.Transactions()[receipt.TransactionIndex]
result = append(result, ethutils.MarshalReceipt(receipt, txn, chainConfig, block.HeaderNoCopy(), txn.Hash(), true, true))
// State-sync receipts' TransactionIndex is equal to numTxs.
if int(receipt.TransactionIndex) == numTxs {
// This is a state-sync transaction receipt.
result = append(result, ethutils.MarshalReceipt(receipt, bortypes.NewBorTransaction(), chainConfig, block.HeaderNoCopy(), receipt.TxHash, false, true))
} else {
// This is a normal transaction receipt.
txn := block.Transactions()[receipt.TransactionIndex]
result = append(result, ethutils.MarshalReceipt(receipt, txn, chainConfig, block.HeaderNoCopy(), txn.Hash(), true, true))
}
}

if chainConfig.Bor != nil {
// TODO: Change Rio to the actual hard fork.
// Rio fork (or later) includes state-sync receipts in block execution.
// For blocks >= Rio: receipts already include the state-sync receipts.
// For blocks < Rio: old cached data doesn't include the state-sync receipts, generate on-the-fly.
if chainConfig.Bor != nil && !chainConfig.Bor.IsRio(blockNum) && len(receipts) == numTxs {
events, err := api.bridgeReader.Events(ctx, block.Hash(), blockNum)
if err != nil {
return nil, err
Expand Down
10 changes: 8 additions & 2 deletions rpc/jsonrpc/receipts/bor_receipts_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,19 @@ import (
"github.com/erigontech/erigon/turbo/transactions"
)

type bridgeReader interface {
Events(ctx context.Context, blockHash common.Hash, blockNum uint64) ([]*types.Message, error)
EventTxnLookup(ctx context.Context, borTxHash common.Hash) (uint64, bool, error)
}

type BorGenerator struct {
receiptCache *lru.Cache[common.Hash, *types.Receipt]
blockReader services.FullBlockReader
engine consensus.EngineReader
bridgeReader bridgeReader
}

func NewBorGenerator(blockReader services.FullBlockReader,
engine consensus.EngineReader) *BorGenerator {
func NewBorGenerator(blockReader services.FullBlockReader, engine consensus.EngineReader, bridgeReader bridgeReader) *BorGenerator {
receiptCache, err := lru.New[common.Hash, *types.Receipt](receiptsCacheLimit)
if err != nil {
panic(err)
Expand All @@ -38,6 +43,7 @@ func NewBorGenerator(blockReader services.FullBlockReader,
receiptCache: receiptCache,
blockReader: blockReader,
engine: engine,
bridgeReader: bridgeReader,
}
}

Expand Down
Loading
Loading