diff --git a/internal/adapters/execution/execution_adapter.go b/internal/adapters/execution/execution_adapter.go index b814b2c..189c1a4 100644 --- a/internal/adapters/execution/execution_adapter.go +++ b/internal/adapters/execution/execution_adapter.go @@ -63,3 +63,53 @@ func (e *ExecutionAdapter) GetMostRecentBlockNumber() (uint64, error) { return blockNumber, nil } + +// GetBlockTimestampByNumber retrieves the timestamp of the block with the specified number from the Ethereum execution client. +func (e *ExecutionAdapter) GetBlockTimestampByNumber(blockNumber uint64) (uint64, error) { + // Convert block number to hexadecimal + blockNumberHex := fmt.Sprintf("0x%x", blockNumber) + + // Create the request payload for eth_getBlockByNumber + payload := map[string]interface{}{ + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": []interface{}{blockNumberHex, false}, // `false` indicates we don't need full transaction objects + "id": 1, + } + + // Marshal the payload to JSON + jsonPayload, err := json.Marshal(payload) + if err != nil { + return 0, fmt.Errorf("failed to marshal request payload for eth_getBlockByNumber: %w", err) + } + + // Send the request to the execution client + resp, err := http.Post(e.rpcURL, "application/json", bytes.NewBuffer(jsonPayload)) + if err != nil { + return 0, fmt.Errorf("failed to send request to execution client at %s: %w", e.rpcURL, err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return 0, fmt.Errorf("unexpected status code %d received from execution client", resp.StatusCode) + } + + // Parse the response + var result struct { + Result struct { + Timestamp string `json:"timestamp"` + } `json:"result"` + } + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return 0, fmt.Errorf("failed to decode response from execution client: %w", err) + } + + // Convert the hexadecimal timestamp to uint64 + var timestamp uint64 + _, err = fmt.Sscanf(result.Result.Timestamp, "0x%x", ×tamp) + if err != nil { + return 0, fmt.Errorf("failed to parse timestamp from result %s: %w", result.Result.Timestamp, err) + } + + return timestamp, nil +} diff --git a/internal/adapters/execution/execution_adapter_integration_test.go b/internal/adapters/execution/execution_adapter_integration_test.go index f61f032..aa41776 100644 --- a/internal/adapters/execution/execution_adapter_integration_test.go +++ b/internal/adapters/execution/execution_adapter_integration_test.go @@ -38,3 +38,25 @@ func TestGetMostRecentBlockNumberIntegration(t *testing.T) { // Log the block number for debugging t.Logf("Most recent block number: %d", blockNumber) } + +// TestGetBlockTimestampByNumberIntegration tests fetching the timestamp of a specific block +func TestGetBlockTimestampByNumberIntegration(t *testing.T) { + adapter, err := setupExecutionAdapter(t) + assert.NoError(t, err) + + // Specify the block number to test + blockNumber := uint64(2876079) + + // Call the GetBlockTimestampByNumber method + timestamp, err := adapter.GetBlockTimestampByNumber(blockNumber) + assert.NoError(t, err) + + // Ensure timestamp is greater than 0, indicating a valid response + assert.Greater(t, timestamp, uint64(0), "Expected a non-zero timestamp") + + // ensure timestamp is 1733395440 + assert.Equal(t, uint64(1733395440), timestamp, "Expected timestamp to be 1733395440") + + // Log the timestamp for debugging + t.Logf("Timestamp for block %d: %d (Unix)", blockNumber, timestamp) +} diff --git a/internal/application/ports/execution_port.go b/internal/application/ports/execution_port.go index e1f68a4..eedf4f7 100644 --- a/internal/application/ports/execution_port.go +++ b/internal/application/ports/execution_port.go @@ -2,4 +2,5 @@ package ports type ExecutionPort interface { GetMostRecentBlockNumber() (uint64, error) + GetBlockTimestampByNumber(blockNumber uint64) (uint64, error) } diff --git a/internal/application/services/distributionLogUpdatedEventScanner.go b/internal/application/services/distributionLogUpdatedEventScanner.go index b397123..8d277c3 100644 --- a/internal/application/services/distributionLogUpdatedEventScanner.go +++ b/internal/application/services/distributionLogUpdatedEventScanner.go @@ -99,11 +99,21 @@ func (ds *DistributionLogUpdatedEventScanner) HandleDistributionLogUpdatedEvent( return err } - message := fmt.Sprintf("- 📦 New distribution log updated: %s", distributionLogUpdated.LogCid) - if err := ds.notifierPort.SendNotification(message); err != nil { - logger.ErrorWithPrefix(ds.servicePrefix, "Error sending distributionLogUpdated notification: %v", err) + blockTimestamp, err := ds.executionPort.GetBlockTimestampByNumber(distributionLogUpdated.Raw.BlockNumber) + if err != nil { + logger.ErrorWithPrefix(ds.servicePrefix, "Error getting block timestamp for block number %d: %v", distributionLogUpdated.Raw.BlockNumber, err) return err } + // If the block timestamp is within the last 24 hours, send a notification + if time.Now().Unix()-int64(blockTimestamp) < 24*60*60 { + message := fmt.Sprintf("- 📦 New distribution log updated: %s", distributionLogUpdated.LogCid) + if err := ds.notifierPort.SendNotification(message); err != nil { + logger.ErrorWithPrefix(ds.servicePrefix, "Error sending distributionLogUpdated notification: %v", err) + return err + } + + } + return nil }