Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

transaction-exclusion-api: update besu dependency #659

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
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
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,22 @@ start-env: L1_CONTRACT_VERSION:=6
start-env: SKIP_CONTRACTS_DEPLOYMENT:=false
start-env: LINEA_PROTOCOL_CONTRACTS_ONLY:=false
start-env:
if [ "$(CLEAN_PREVIOUS_ENV)" = "true" ]; then \
make clean-environment; \
@if [ "$(CLEAN_PREVIOUS_ENV)" = "true" ]; then \
$(MAKE) clean-environment; \
else \
echo "Starting stack reusing previous state"; \
fi; \
mkdir -p tmp/local; \
L1_GENESIS_TIME=$(get_future_time) COMPOSE_PROFILES=$(COMPOSE_PROFILES) docker compose -f $(COMPOSE_FILE) up -d; \
while [ "$$(docker compose -f $(COMPOSE_FILE) ps -q l1-el-node | xargs docker inspect -f '{{.State.Health.Status}}')" != "healthy" ] || \
[ "$$(docker compose -f $(COMPOSE_FILE) ps -q sequencer | xargs docker inspect -f '{{.State.Health.Status}}')" != "healthy" ]; do \
sleep 2; \
echo "Checking health status of l1-el-node and sequencer..."; \
done
if [ "$(SKIP_CONTRACTS_DEPLOYMENT)" = "true" ]; then \
echo "Skipping contracts deployment"; \
else \
make deploy-contracts L1_CONTRACT_VERSION=$(L1_CONTRACT_VERSION) LINEA_PROTOCOL_CONTRACTS_ONLY=$(LINEA_PROTOCOL_CONTRACTS_ONLY); \
$(MAKE) deploy-contracts L1_CONTRACT_VERSION=$(L1_CONTRACT_VERSION) LINEA_PROTOCOL_CONTRACTS_ONLY=$(LINEA_PROTOCOL_CONTRACTS_ONLY); \
fi

start-l1:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,14 @@ plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}

tasks.distTar {
// we don't use the tar distribution
onlyIf { false }
}

tasks.distZip {
// we only need the zip distribution to build the docker image
// we explicitly call distZip to build the zip distribution
enabled = false
}
5 changes: 0 additions & 5 deletions coordinator/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ distributions {
}
}

tasks.distTar {
// we don't need the tar distribution
onlyIf { false }
}

run {
workingDir = rootProject.projectDir
jvmArgs = [
Expand Down
6 changes: 2 additions & 4 deletions docker/compose-spec-l2-services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -513,13 +513,13 @@ services:
blobscan-api:
container_name: blobscan-api
hostname: blobscan-api
image: blossomlabs/blobscan-api:1.1.0
image: blossomlabs/blobscan-api:1.3.1
platform: linux/amd64 # only linux available
profiles: [ "staterecovery" ]
ports:
- "4001:4001"
env_file: "./config/blobscan/env"
restart: no
restart: always
# healthcheck:
# test: [ "CMD", "curl", "-f", "http://localhost:4001/healthcheck" ]
# disable: true
Expand All @@ -528,7 +528,6 @@ services:
# retries: 20
# start_period: 5s
networks:
linea:
l1network:
ipv4_address: 10.10.10.203
depends_on:
Expand All @@ -549,7 +548,6 @@ services:
profiles: [ "staterecovery" ]
env_file: "./config/blobscan/env"
networks:
linea:
l1network:
ipv4_address: 10.10.10.204
restart: always
Expand Down
2 changes: 1 addition & 1 deletion docker/config/blobscan/env
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ BLOBSCAN_API_PORT=4001
EXTERNAL_API_PORT=4001
CHAIN_ID=31648428
DENCUN_FORK_SLOT=0
LOG_LEVEL=debug
LOG_LEVEL=warn
REDIS_URI=redis://redis:6379/1
# SENTRY_DSN_API=
BLOB_PROPAGATOR_ENABLED=false
Expand Down
1 change: 0 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ restassured = "5.3.0"
wiremock = "3.0.1"

# Runtime
besu = "24.12.2"
blobCompressor = "0.0.4"
blobShnarfCalculator = "0.0.4"
bouncycastle = "1.79"
Expand Down
4 changes: 1 addition & 3 deletions jvm-libs/linea/besu-libs/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ plugins {
id 'java-library'
}

//def besuArtifactGroup="org.hyperledger.besu"
//def besuVersion=libs.versions.besu.get()
def besuArtifactGroup="io.consensys.linea-besu"
def besuVersion="25.2-delivery46"
def besuVersion="25.2-delivery48"

dependencies {
api("${besuArtifactGroup}:besu-datatypes:${besuVersion}") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.web3j.protocol.Web3j
import tech.pegasys.teku.infrastructure.async.SafeFuture
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds

fun assertTxSuccess(
txHash: String,
Expand All @@ -24,6 +25,7 @@ fun assertTxSuccess(
txHash = txHash,
timeout = timeout
).also { txReceipt ->
println("txHash=$txHash, receiptStatus=${txReceipt.status}")
assertThat(txReceipt.status)
.withFailMessage(
"submission of $submissionType=${interval.intervalString()}" +
Expand All @@ -37,11 +39,14 @@ fun assertTxsSuccess(
txsAndInterval: List<Pair<String, BlockInterval>>,
submissionType: String,
l1Web3jClient: Web3j,
timeout: Duration = 1.minutes
timeout: Duration = 1.minutes,
log: Logger = LogManager.getLogger("linea.testing.submission")
) {
SafeFuture.supplyAsync {
txsAndInterval.forEach { (txHash, interval) ->
log.info("waiting for tx={} to be mined", txHash)
assertTxSuccess(txHash, interval, submissionType, l1Web3jClient, timeout)
log.info("waiting for tx={} to be mined", txHash)
}
}
.get(timeout.inWholeMilliseconds, java.util.concurrent.TimeUnit.MILLISECONDS)
Expand All @@ -55,6 +60,8 @@ fun submitBlobs(
contractClient: LineaRollupSmartContractClient,
aggregationsAndBlobs: List<AggregationAndBlobs>,
blobChunksSize: Int = 6,
awaitForPreviousTxBeforeSubmittingNext: Boolean = false,
l1Web3jClient: Web3j,
log: Logger
): List<Pair<String, List<BlobRecord>>> {
require(blobChunksSize in 1..6) { "blobChunksSize must be between 1..6" }
Expand All @@ -64,12 +71,18 @@ fun submitBlobs(
val blobChunks = aggBlobs.chunked(blobChunksSize)
blobChunks.map { blobs ->
val txHash = contractClient.submitBlobs(blobs, gasPriceCaps = null).get()
val blobsLogInfo = blobs.map(BlockInterval::intervalString)
log.info(
"submitting blobs: aggregation={} blobsChunk={} txHash={}",
agg?.intervalString(),
blobs.map { it.intervalString() },
blobsLogInfo,
txHash
)
if (awaitForPreviousTxBeforeSubmittingNext) {
log.debug("waiting for blobsChunk={} txHash={} to be mined", blobsLogInfo, txHash)
assertTxSuccess(txHash, blobs.first(), "blobs", l1Web3jClient, 20.seconds)
log.info(" blobsChunk={} txHash={} mined", blobsLogInfo, txHash)
}

txHash to blobs
}
Expand All @@ -86,35 +99,44 @@ fun submitBlobsAndAggregationsAndWaitExecution(
waitTimeout: Duration = 2.minutes,
log: Logger = LogManager.getLogger("linea.testing.submission")
) {
val blobSubmissionTxHashes = submitBlobs(
val blobSubmissions = submitBlobs(
contractClientForBlobSubmission,
aggregationsAndBlobs,
blobChunksMaxSize,
log
awaitForPreviousTxBeforeSubmittingNext = false,
l1Web3jClient = l1Web3jClient,
log = log
)

assertTxsSuccess(
txsAndInterval = blobSubmissionTxHashes.map { (txHash, blobs) ->
txsAndInterval = blobSubmissions.map { (txHash, blobs) ->
txHash to BlockInterval(blobs.first().startBlockNumber, blobs.last().endBlockNumber)
},
submissionType = "blobs",
l1Web3jClient = l1Web3jClient,
timeout = waitTimeout
)
log.info("blob={} txHash={} executed on L1", blobSubmissions.last().second, blobSubmissions.last().first)

val submissions = aggregationsAndBlobs
.filter { it.aggregation != null }
.mapIndexed { index, (aggregation, aggBlobs) ->
aggregation as Aggregation
val parentAgg = aggregationsAndBlobs.getOrNull(index - 1)?.aggregation
contractClientForAggregationSubmission.finalizeBlocks(
val txHash = contractClientForAggregationSubmission.finalizeBlocks(
aggregation = aggregation.aggregationProof!!,
aggregationLastBlob = aggBlobs.last(),
parentShnarf = aggBlobs.first().blobCompressionProof!!.prevShnarf,
parentL1RollingHash = parentAgg?.aggregationProof?.l1RollingHash ?: ByteArray(32),
parentL1RollingHashMessageNumber = parentAgg?.aggregationProof?.l1RollingHashMessageNumber ?: 0L,
gasPriceCaps = null
).get() to aggregation
).get()
log.info(
"submitting aggregation={} txHash={}",
aggregation.intervalString(),
txHash
)
txHash to aggregation
}

assertTxsSuccess(
Expand All @@ -123,4 +145,10 @@ fun submitBlobsAndAggregationsAndWaitExecution(
l1Web3jClient = l1Web3jClient,
timeout = waitTimeout
)

log.info(
"aggregation={} txHash={} executed on L1",
submissions.last().second.intervalString(),
submissions.last().first
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import org.web3j.protocol.core.methods.request.EthFilter
import org.web3j.protocol.core.methods.response.EthLog
import org.web3j.protocol.core.methods.response.Log
import tech.pegasys.teku.infrastructure.async.SafeFuture
import java.util.concurrent.atomic.AtomicReference
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds

Expand Down Expand Up @@ -73,22 +74,32 @@ class Web3JLogsSearcher(
val cursor = SearchCursor(fromBlock, toBlock, chunkSize)
log.trace("searching between blocks={}", CommonDomainFunctions.blockIntervalString(fromBlock, toBlock))

var nextChunkToSearch: Pair<ULong, ULong>? = cursor.next(searchDirection = SearchDirection.FORWARD)
val nextChunkToSearchRef: AtomicReference<Pair<ULong, ULong>?> =
AtomicReference(cursor.next(searchDirection = SearchDirection.FORWARD))
return AsyncRetryer.retry(
vertx,
backoffDelay = config.backoffDelay,
stopRetriesPredicate = { it is SearchResult.ItemFound || nextChunkToSearch == null }
stopRetriesPredicate = {
it is SearchResult.ItemFound || nextChunkToSearchRef.get() == null
}
) {
val (chunkStart, chunkEnd) = nextChunkToSearch!!
log.trace("searching in chunk={}", CommonDomainFunctions.blockIntervalString(chunkStart, chunkEnd))
log.trace("searching in chunk={}", nextChunkToSearchRef.get())
val (chunkStart, chunkEnd) = nextChunkToSearchRef.get()!!
val chunkInterval = CommonDomainFunctions.blockIntervalString(chunkStart, chunkEnd)
findLogInInterval(chunkStart, chunkEnd, address, topics, shallContinueToSearchPredicate)
.thenPeek { result ->
if (result is SearchResult.NoResultsInInterval) {
nextChunkToSearch = cursor.next(searchDirection = null)
nextChunkToSearchRef.set(cursor.next(searchDirection = null))
} else if (result is SearchResult.KeepSearching) {
// need to search in the same chunk
nextChunkToSearch = cursor.next(searchDirection = result.direction)
nextChunkToSearchRef.set(cursor.next(searchDirection = result.direction))
}
log.trace(
"search result chunk={} searchResult={} nextChunkToSearch={}",
chunkInterval,
result,
nextChunkToSearchRef.get()
)
}
}.thenApply { either ->
when (either) {
Expand Down Expand Up @@ -195,27 +206,32 @@ class Web3JLogsSearcher(
fromBlock: BlockParameter,
toBlock: BlockParameter
): SafeFuture<Pair<ULong, ULong>> {
return if (fromBlock is BlockParameter.BlockNumber && toBlock is BlockParameter.BlockNumber) {
return SafeFuture.completedFuture(Pair(fromBlock.getNumber(), toBlock.getNumber()))
return SafeFuture.collectAll(
getBlockParameterNumber(fromBlock),
getBlockParameterNumber(toBlock)
).thenApply { (start, end) ->
start to end
}
}

private fun getBlockParameterNumber(blockParameter: BlockParameter): SafeFuture<ULong> {
return if (blockParameter is BlockParameter.BlockNumber) {
SafeFuture.completedFuture(blockParameter.getNumber())
} else if (blockParameter == BlockParameter.Tag.EARLIEST) {
SafeFuture.completedFuture(0UL)
} else {
AsyncRetryer.retry(
vertx = vertx,
backoffDelay = config.backoffDelay,
stopRetriesPredicate = { (fromBlockResponse, toBlockResponse) ->
fromBlockResponse?.block?.number != null && toBlockResponse?.block?.number != null
stopRetriesPredicate = { response ->
response?.block?.number != null
},
action = {
SafeFuture.collectAll(
web3jClient.ethGetBlockByNumber(fromBlock.toWeb3j(), false).sendAsync().toSafeFuture(),
web3jClient.ethGetBlockByNumber(toBlock.toWeb3j(), false).sendAsync().toSafeFuture()
)
web3jClient.ethGetBlockByNumber(blockParameter.toWeb3j(), false).sendAsync().toSafeFuture()
}
)
.thenApply { (fromBlockResponse, toBlockResponse) ->
Pair(
fromBlockResponse.block.number.toULong(),
toBlockResponse.block.number.toULong()
)
.thenApply { response ->
response.block.number.toULong()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class StateRecoveryApp(
"contract address mismatch: config=${config.smartContractAddress} client=${lineaContractClient.getAddress()}"
}
}

private val l1EventsClient = LineaSubmissionEventsClientImpl(
logsSearcher = ethLogsSearcher,
smartContractAddress = config.smartContractAddress,
Expand Down Expand Up @@ -166,16 +167,25 @@ class StateRecoveryApp(
vertx = vertx,
backoffDelay = config.executionClientPollingInterval,
stopRetriesPredicate = { recoveryStatus ->
log.debug(
"waiting for node to sync until stateRecoverStartBlockNumber={} headBlockNumber={}",
recoveryStatus.stateRecoverStartBlockNumber,
recoveryStatus.headBlockNumber
)
// headBlockNumber shall be at least 1 block behind of stateRecoverStartBlockNumber
// if it is after it means it was already enabled
recoveryStatus.stateRecoverStartBlockNumber?.let { startBlockNumber ->
val hasReachedTargetBlock = recoveryStatus.stateRecoverStartBlockNumber?.let { startBlockNumber ->
recoveryStatus.headBlockNumber + 1u >= startBlockNumber
} ?: false
if (hasReachedTargetBlock) {
log.info(
"node reached recovery target block: stateRecoverStartBlockNumber={} headBlockNumber={}",
recoveryStatus.stateRecoverStartBlockNumber,
recoveryStatus.headBlockNumber
)
} else {
log.info(
"waiting for node to sync until stateRecoverStartBlockNumber={} - 1, headBlockNumber={}",
recoveryStatus.stateRecoverStartBlockNumber,
recoveryStatus.headBlockNumber
)
}
hasReachedTargetBlock
}
) {
elClient.lineaGetStateRecoveryStatus()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,16 @@ class StateSynchronizerService(
}

return findNextFinalization()
.thenPeek { nextFinalization ->
log.debug(
"sync state loop: lastSuccessfullyProcessedFinalization={} nextFinalization={}",
lastSuccessfullyProcessedFinalization?.event?.intervalString(),
nextFinalization?.event?.intervalString()
)
}
.thenCompose { nextFinalization ->
if (nextFinalization == null) {
// nothing to do for now
SafeFuture.completedFuture(null)
} else {
log.debug(
"sync state loop: lastSuccessfullyProcessedFinalization={} nextFinalization={}",
lastSuccessfullyProcessedFinalization?.event?.intervalString(),
nextFinalization.event.intervalString()
)
submissionEventsClient
.findDataSubmittedV3EventsUntilNextFinalization(
l2StartBlockNumberInclusive = nextFinalization.event.startBlockNumber
Expand Down
Loading
Loading