From 89e6c5b8fef4aeb771fbb1d51c751433ed407534 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Tue, 30 Jan 2024 15:41:24 +0800 Subject: [PATCH 01/11] feat: span batch --- .../optimism/batcher/channel/ChannelImpl.java | 21 +- .../main/java/io/optimism/config/Config.java | 18 +- .../main/java/io/optimism/derive/State.java | 96 +++++- .../io/optimism/derive/stages/Attributes.java | 8 +- .../io/optimism/derive/stages/Batches.java | 324 ++++++++++++++++-- .../main/java/io/optimism/driver/Driver.java | 3 +- .../stages/BatcherTransactionsTest.java | 3 + .../optimism/derive/stages/BatchesTest.java | 72 +++- .../optimism/engine/EngineApiRequestTest.java | 241 +++++++++++++ .../utilities/derive/stages/Batch.java | 84 ++--- .../utilities/derive/stages/IBatch.java | 2 +- .../utilities/derive/stages/RawSpanBatch.java | 4 +- .../derive/stages/SingularBatch.java | 17 +- .../utilities/derive/stages/SpanBatch.java | 21 +- 14 files changed, 800 insertions(+), 114 deletions(-) create mode 100644 hildr-node/src/test/java/io/optimism/engine/EngineApiRequestTest.java diff --git a/hildr-batcher/src/main/java/io/optimism/batcher/channel/ChannelImpl.java b/hildr-batcher/src/main/java/io/optimism/batcher/channel/ChannelImpl.java index 6d22812d..ac54df72 100644 --- a/hildr-batcher/src/main/java/io/optimism/batcher/channel/ChannelImpl.java +++ b/hildr-batcher/src/main/java/io/optimism/batcher/channel/ChannelImpl.java @@ -6,8 +6,8 @@ import io.optimism.batcher.telemetry.BatcherMetrics; import io.optimism.type.BlockId; import io.optimism.type.L1BlockInfo; -import io.optimism.utilities.derive.stages.Batch; import io.optimism.utilities.derive.stages.Frame; +import io.optimism.utilities.derive.stages.SingularBatch; import java.io.IOException; import java.math.BigInteger; import java.security.NoSuchAlgorithmException; @@ -106,9 +106,9 @@ public L1BlockInfo addBlock(final EthBlock.Block block) { if (this.isClose) { throw new ChannelException("channel already closed"); } - final Tuple2 l1InfoAndBatch = this.blockToBatch(block); + final Tuple2 l1InfoAndBatch = this.blockToBatch(block); final L1BlockInfo l1Info = l1InfoAndBatch.component1(); - final Batch batch = l1InfoAndBatch.component2(); + final SingularBatch batch = l1InfoAndBatch.component2(); try { this.addBatch(batch); this.blocks.add(block); @@ -286,7 +286,7 @@ public void close() { } @SuppressWarnings({"rawtypes", "unchecked"}) - private Tuple2 blockToBatch(EthBlock.Block block) { + private Tuple2 blockToBatch(EthBlock.Block block) { final List blockTxs = block.getTransactions(); if (blockTxs == null || blockTxs.isEmpty()) { throw new ChannelException(String.format("block %s has no transations", block.getHash())); @@ -308,16 +308,11 @@ private Tuple2 blockToBatch(EthBlock.Block block) { } return new Tuple2( l1Info, - new Batch( - block.getParentHash(), - l1Info.number(), - l1Info.blockHash(), - block.getTimestamp(), - txDataList, - null)); + new SingularBatch( + block.getParentHash(), l1Info.number(), l1Info.blockHash(), block.getTimestamp(), txDataList)); } - private int addBatch(Batch batch) { + private int addBatch(SingularBatch batch) { if (this.isClose) { throw new ChannelException("channel already closed"); } @@ -385,7 +380,7 @@ private Frame frame(final int maxSize) { return frame; } - private void updateSeqWindowTimeout(final Batch batch) { + private void updateSeqWindowTimeout(final SingularBatch batch) { var timeout = batch.epochNum().add(this.seqWindowTimeout); this.updateTimeout(timeout); } diff --git a/hildr-node/src/main/java/io/optimism/config/Config.java b/hildr-node/src/main/java/io/optimism/config/Config.java index 5ab153af..95533a25 100644 --- a/hildr-node/src/main/java/io/optimism/config/Config.java +++ b/hildr-node/src/main/java/io/optimism/config/Config.java @@ -2,6 +2,7 @@ import static java.util.Map.entry; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; @@ -180,6 +181,8 @@ public Map toConfigMap() { * The type ChainConfig. * * @param network The network name. + * @param l1ChainId The L1 chain id. + * @param l2ChainId The L2 chain id. * @param l1StartEpoch The L1 block referenced by the L2 chainConfig. * @param l2Genesis The L2 genesis block info. * @param systemConfig The initial system config value. @@ -192,10 +195,9 @@ public Map toConfigMap() { * @param maxSeqDrift Maximum timestamp drift. * @param regolithTime Timestamp of the regolith hardfork. * @param canyonTime Timestamp of the canyon hardfork. + * @param deltaTime Timestamp of the canyon hardfork. * @param blockTime Network blocktime. * @param l2Tol1MessagePasser L2 To L1 Message passer address. - * @param l1ChainId The L1 chain id. - * @param l2ChainId The L2 chain id. * @author grapebaba * @since 0.1.0 */ @@ -215,6 +217,7 @@ public record ChainConfig( BigInteger maxSeqDrift, BigInteger regolithTime, BigInteger canyonTime, + BigInteger deltaTime, BigInteger blockTime, String l2Tol1MessagePasser) { @@ -252,6 +255,7 @@ public static ChainConfig optimism() { BigInteger.valueOf(600L), BigInteger.ZERO, BigInteger.valueOf(1704992401L), + BigInteger.valueOf(-1L), BigInteger.valueOf(2L), "0x4200000000000000000000000000000000000016"); } @@ -290,6 +294,7 @@ public static ChainConfig base() { BigInteger.valueOf(600L), BigInteger.ZERO, BigInteger.valueOf(1704992401L), + BigInteger.valueOf(-1L), BigInteger.valueOf(2L), "0x4200000000000000000000000000000000000016"); } @@ -328,6 +333,7 @@ public static ChainConfig optimismGoerli() { BigInteger.valueOf(600L), BigInteger.valueOf(1679079600L), BigInteger.valueOf(1699981200L), + BigInteger.valueOf(1703116800L), BigInteger.valueOf(2L), "0xEF2ec5A5465f075E010BE70966a8667c94BCe15a"); } @@ -366,6 +372,7 @@ public static ChainConfig optimismSepolia() { BigInteger.valueOf(600L), BigInteger.ZERO, BigInteger.valueOf(1699981200L), + BigInteger.valueOf(1703203200L), BigInteger.valueOf(2L), "0x4200000000000000000000000000000000000016"); } @@ -404,6 +411,7 @@ public static ChainConfig baseGoerli() { BigInteger.valueOf(600L), BigInteger.valueOf(1683219600L), BigInteger.valueOf(1699981200L), + BigInteger.valueOf(-1L), BigInteger.valueOf(2L), "0x4200000000000000000000000000000000000016"); } @@ -442,6 +450,7 @@ public static ChainConfig baseSepolia() { BigInteger.valueOf(600L), BigInteger.ZERO, BigInteger.valueOf(1699981200L), + BigInteger.valueOf(-1L), BigInteger.valueOf(2L), "0x4200000000000000000000000000000000000016"); } @@ -454,6 +463,7 @@ public static ChainConfig baseSepolia() { */ public static ChainConfig fromJson(String filePath) { ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); try { ExternalChainConfig externalChainConfig = mapper.readValue( Files.readString(Path.of(filePath), StandardCharsets.UTF_8), ExternalChainConfig.class); @@ -495,6 +505,7 @@ public static ChainConfig fromExternal(ExternalChainConfig external) { external.maxSequencerDrift, external.regolithTime, external.canyonTime == null ? BigInteger.valueOf(-1L) : external.canyonTime, + external.deltaTime == null ? BigInteger.valueOf(-1L) : external.deltaTime, external.blockTime, "0x4200000000000000000000000000000000000016"); } @@ -544,6 +555,7 @@ public Map toConfigMap() { entry("config.chainConfig.maxSeqDrift", this.maxSeqDrift.toString()), entry("config.chainConfig.regolithTime", this.regolithTime.toString()), entry("config.chainConfig.canyonTime", this.canyonTime.toString()), + entry("config.chainConfig.deltaTime", this.deltaTime.toString()), entry("config.chainConfig.blockTime", this.blockTime.toString()), entry("config.chainConfig.l2Tol1MessagePasser", this.l2Tol1MessagePasser)); } @@ -657,6 +669,7 @@ public String batcherHash() { * @param l2ChainId l2 chain id * @param regolithTime regolith time * @param canyonTime canyon time + * @param deltaTime delta time * @param batchInboxAddress batch inbox address * @param depositContractAddress deposit contract address * @param l1SystemConfigAddress l1 system config address @@ -673,6 +686,7 @@ public record ExternalChainConfig( BigInteger l2ChainId, BigInteger regolithTime, BigInteger canyonTime, + BigInteger deltaTime, String batchInboxAddress, String depositContractAddress, String l1SystemConfigAddress) {} diff --git a/hildr-node/src/main/java/io/optimism/derive/State.java b/hildr-node/src/main/java/io/optimism/derive/State.java index 7bb380dc..07a64423 100644 --- a/hildr-node/src/main/java/io/optimism/derive/State.java +++ b/hildr-node/src/main/java/io/optimism/derive/State.java @@ -3,11 +3,18 @@ import io.optimism.common.BlockInfo; import io.optimism.common.Epoch; import io.optimism.config.Config; +import io.optimism.driver.HeadInfo; import io.optimism.l1.L1Info; import java.math.BigInteger; import java.util.Map.Entry; import java.util.TreeMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.StructuredTaskScope; import org.apache.commons.lang3.StringUtils; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.DefaultBlockParameter; +import org.web3j.protocol.core.methods.response.EthBlock; +import org.web3j.tuples.generated.Tuple2; /** * The type State. @@ -21,6 +28,8 @@ public class State { private final TreeMap l1Hashes; + private final TreeMap> l2Refs; + private BlockInfo safeHead; private Epoch safeEpoch; @@ -34,6 +43,7 @@ public class State { * * @param l1Info the L1 info * @param l1Hashes the L1 hashes + * @param l2Refs the L2 block info references * @param safeHead the safe head * @param safeEpoch the safe epoch * @param currentEpochNum the current epoch num @@ -42,12 +52,14 @@ public class State { public State( TreeMap l1Info, TreeMap l1Hashes, + TreeMap> l2Refs, BlockInfo safeHead, Epoch safeEpoch, BigInteger currentEpochNum, Config config) { this.l1Info = l1Info; this.l1Hashes = l1Hashes; + this.l2Refs = l2Refs; this.safeHead = safeHead; this.safeEpoch = safeEpoch; this.currentEpochNum = currentEpochNum; @@ -57,13 +69,19 @@ public State( /** * Create state. * + * @param l2Refs the L2 block info references * @param finalizedHead the finalized head * @param finalizedEpoch the finalized epoch * @param config the config * @return the state */ - public static State create(BlockInfo finalizedHead, Epoch finalizedEpoch, Config config) { - return new State(new TreeMap<>(), new TreeMap<>(), finalizedHead, finalizedEpoch, BigInteger.ZERO, config); + public static State create( + TreeMap> l2Refs, + BlockInfo finalizedHead, + Epoch finalizedEpoch, + Config config) { + return new State( + new TreeMap<>(), new TreeMap<>(), l2Refs, finalizedHead, finalizedEpoch, BigInteger.ZERO, config); } /** @@ -90,6 +108,20 @@ public L1Info l1Info(BigInteger number) { return l1Info.get(l1Hashes.get(number)); } + /** + * Gets L2 block info and epoch by block timestamp. + * + * @param timestamp the number + * @return the tuple of L2 block info and epoch + */ + public Tuple2 l2Info(BigInteger timestamp) { + final BigInteger blockNum = timestamp + .subtract(config.chainConfig().l2Genesis().timestamp()) + .divide(config.chainConfig().blockTime()) + .add(config.chainConfig().l2Genesis().number()); + return this.l2Refs.get(blockNum); + } + /** * Epoch epoch. * @@ -146,6 +178,7 @@ public void purge(BlockInfo safeHead, Epoch safeEpoch) { this.l1Info.clear(); this.l1Hashes.clear(); this.currentEpochNum = BigInteger.ZERO; + this.updateSafeHead(safeHead, safeEpoch); } /** @@ -157,6 +190,7 @@ public void purge(BlockInfo safeHead, Epoch safeEpoch) { public void updateSafeHead(BlockInfo safeHead, Epoch safeEpoch) { this.safeHead = safeHead; this.safeEpoch = safeEpoch; + this.l2Refs.put(safeHead.number(), new Tuple2<>(safeHead, safeEpoch)); } /** @@ -225,5 +259,63 @@ private void prune() { this.l1Info.remove(blockNumAndHash.getValue()); this.l1Hashes.pollFirstEntry(); } + + pruneUntil = this.safeHead + .number() + .subtract(this.config + .chainConfig() + .maxSeqDrift() + .divide(this.config.chainConfig().blockTime())); + + Entry> blockRefEntry; + while ((blockRefEntry = this.l2Refs.firstEntry()) != null) { + if (blockRefEntry.getKey().compareTo(pruneUntil) >= 0) { + break; + } + this.l2Refs.pollFirstEntry(); + } + } + + /** + * Init L2 refs tree map. + * + * @param headNum the l2 head block number + * @param chainConfig the chain config + * @param l2Client the l2 web3j client + * @return the L2 refs tree map. + * @throws ExecutionException throws the ExecutionException when the Task has been failed + * @throws InterruptedException throws the InterruptedException when the thread has been interrupted + */ + public static TreeMap> initL2Refs( + BigInteger headNum, Config.ChainConfig chainConfig, Web3j l2Client) + throws ExecutionException, InterruptedException { + final BigInteger lookback = chainConfig.maxSeqDrift().divide(chainConfig.blockTime()); + BigInteger start; + if (headNum.compareTo(lookback) < 0) { + start = chainConfig.l2Genesis().number(); + } else { + start = headNum.subtract(lookback).max(chainConfig.l2Genesis().number()); + } + final TreeMap> l2Refs = new TreeMap<>(); + for (BigInteger i = start; i.compareTo(headNum) <= 0; i = i.add(BigInteger.ONE)) { + try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { + var l2Num = i; + var blockTask = + scope.fork(() -> l2Client.ethGetBlockByNumber(DefaultBlockParameter.valueOf(l2Num), true) + .send() + .getBlock()); + scope.join(); + scope.throwIfFailed(); + EthBlock.Block block = blockTask.get(); + if (block == null) { + continue; + } + final HeadInfo l2BlockInfo = HeadInfo.from(block); + l2Refs.put( + l2BlockInfo.l2BlockInfo().number(), + new Tuple2<>(l2BlockInfo.l2BlockInfo(), l2BlockInfo.l1Epoch())); + } + } + return l2Refs; } } diff --git a/hildr-node/src/main/java/io/optimism/derive/stages/Attributes.java b/hildr-node/src/main/java/io/optimism/derive/stages/Attributes.java index 7f37e2e3..51902e09 100644 --- a/hildr-node/src/main/java/io/optimism/derive/stages/Attributes.java +++ b/hildr-node/src/main/java/io/optimism/derive/stages/Attributes.java @@ -9,6 +9,7 @@ import io.optimism.engine.ExecutionPayload.PayloadAttributes; import io.optimism.l1.L1Info; import io.optimism.utilities.derive.stages.Batch; +import io.optimism.utilities.derive.stages.SingularBatch; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -78,7 +79,8 @@ public PayloadAttributes next() { return batch != null ? this.deriveAttributes(batch) : null; } - private PayloadAttributes deriveAttributes(Batch batch) { + private PayloadAttributes deriveAttributes(Batch batchWrapper) { + SingularBatch batch = (SingularBatch) batchWrapper.batch(); LOGGER.debug("attributes derived from block {}", batch.epochNum()); LOGGER.debug("batch epoch hash {}", batch.epochHash()); @@ -91,7 +93,7 @@ private PayloadAttributes deriveAttributes(Batch batch) { batch.epochNum(), batch.epochHash(), l1Info.blockInfo().timestamp()); BigInteger timestamp = batch.timestamp(); - BigInteger l1InclusionBlock = batch.l1InclusionBlock(); + BigInteger l1InclusionBlock = batchWrapper.l1InclusionBlock(); BigInteger seqNumber = this.sequenceNumber; String prevRandao = l1Info.blockInfo().mixHash(); List transactions = this.deriveTransactions(batch, l1Info); @@ -120,7 +122,7 @@ private PayloadAttributes deriveAttributes(Batch batch) { seqNumber); } - private List deriveTransactions(Batch batch, L1Info l1Info) { + private List deriveTransactions(SingularBatch batch, L1Info l1Info) { List transactions = new ArrayList<>(); String attributesTx = this.deriveAttributesDeposited(l1Info, batch.timestamp()); diff --git a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java index f3fca0fe..b8b541fa 100644 --- a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java +++ b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java @@ -7,22 +7,34 @@ import io.optimism.derive.PurgeableIterator; import io.optimism.derive.State; import io.optimism.derive.stages.Channels.Channel; +import io.optimism.l1.L1Info; import io.optimism.utilities.derive.stages.Batch; +import io.optimism.utilities.derive.stages.BatchType; +import io.optimism.utilities.derive.stages.IBatch; +import io.optimism.utilities.derive.stages.RawSpanBatch; +import io.optimism.utilities.derive.stages.SingularBatch; +import io.optimism.utilities.derive.stages.SpanBatch; +import io.optimism.utilities.derive.stages.SpanBatchElement; import java.io.ByteArrayOutputStream; import java.math.BigInteger; +import java.util.ArrayList; import java.util.List; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.zip.DataFormatException; import java.util.zip.Inflater; import org.apache.commons.lang3.ArrayUtils; +import org.jctools.queues.atomic.SpscAtomicArrayQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.web3j.rlp.RlpDecoder; import org.web3j.rlp.RlpList; import org.web3j.rlp.RlpString; import org.web3j.rlp.RlpType; +import org.web3j.tuples.generated.Tuple2; +import org.web3j.utils.Numeric; /** * The type Batches. @@ -42,6 +54,8 @@ public class Batches> implements PurgeableI private final Config config; + private SpscAtomicArrayQueue nextSingularBatches; + /** * Instantiates a new Batches. * @@ -55,19 +69,32 @@ public Batches(TreeMap batches, I channelIterator, AtomicRefe this.channelIterator = channelIterator; this.state = state; this.config = config; + this.nextSingularBatches = new SpscAtomicArrayQueue<>(1024); } @Override public void purge() { this.channelIterator.purge(); this.batches.clear(); + this.nextSingularBatches.clear(); } @Override public Batch next() { + final var nextBatch = nextSingularBatches.poll(); + if (nextBatch != null) { + return nextBatch; + } Channel channel = this.channelIterator.next(); if (channel != null) { - decodeBatches(channel).forEach(batch -> this.batches.put(batch.timestamp(), batch)); + decodeBatches(channel) + .forEach(batch -> this.batches.put( + batch.batch() + .getTimestamp(this.config + .chainConfig() + .l2Genesis() + .timestamp()), + batch)); } Batch derivedBatch = null; @@ -75,14 +102,15 @@ public Batch next() { while (true) { if (this.batches.firstEntry() != null) { Batch batch = this.batches.firstEntry().getValue(); + BigInteger timestamp = this.config.chainConfig().l2Genesis().timestamp(); switch (batchStatus(batch)) { case Accept: derivedBatch = batch; - this.batches.remove(batch.timestamp()); + this.batches.remove(batch.timestamp(timestamp)); break loop; case Drop: LOGGER.warn("dropping invalid batch"); - this.batches.remove(batch.timestamp()); + this.batches.remove(batch.timestamp(timestamp)); continue; case Future, Undecided: break loop; @@ -96,32 +124,31 @@ public Batch next() { Batch batch = null; if (derivedBatch != null) { - batch = derivedBatch; - } else { - State state = this.state.get(); - - BigInteger currentL1Block = state.getCurrentEpochNum(); - BlockInfo safeHead = state.getSafeHead(); - Epoch epoch = state.getSafeEpoch(); - Epoch nextEpoch = state.epoch(epoch.number().add(BigInteger.ONE)); - BigInteger seqWindowSize = this.config.chainConfig().seqWindowSize(); - - if (nextEpoch != null) { - if (currentL1Block.compareTo(epoch.number().add(seqWindowSize)) > 0) { - BigInteger nextTimestamp = - safeHead.timestamp().add(this.config.chainConfig().blockTime()); - Epoch epochRes = nextTimestamp.compareTo(nextEpoch.timestamp()) < 0 ? epoch : nextEpoch; - batch = new Batch( - safeHead.parentHash(), - epochRes.number(), - epochRes.hash(), - nextTimestamp, - Lists.newArrayList(), - currentL1Block); - } + List singularBatches = this.getSingularBatches(derivedBatch.batch(), this.state.get()); + if (singularBatches.size() != 0) { + this.nextSingularBatches.addAll(singularBatches); + return this.nextSingularBatches.poll(); } } + State state = this.state.get(); + + BigInteger currentL1Block = state.getCurrentEpochNum(); + BlockInfo safeHead = state.getSafeHead(); + Epoch epoch = state.getSafeEpoch(); + Epoch nextEpoch = state.epoch(epoch.number().add(BigInteger.ONE)); + BigInteger seqWindowSize = this.config.chainConfig().seqWindowSize(); + + if (nextEpoch != null) { + if (currentL1Block.compareTo(epoch.number().add(seqWindowSize)) > 0) { + BigInteger nextTimestamp = + safeHead.timestamp().add(this.config.chainConfig().blockTime()); + Epoch epochRes = nextTimestamp.compareTo(nextEpoch.timestamp()) < 0 ? epoch : nextEpoch; + var singularBatch = new SingularBatch( + safeHead.parentHash(), epochRes.number(), epochRes.hash(), nextTimestamp, Lists.newArrayList()); + batch = new Batch(singularBatch, currentL1Block); + } + } return batch; } @@ -136,11 +163,19 @@ public static List decodeBatches(Channel channel) { List batches = RlpDecoder.decode(channelData).getValues(); return batches.stream() .map(rlpType -> { - byte[] batchData = ArrayUtils.subarray( - ((RlpString) rlpType).getBytes(), 1, ((RlpString) rlpType).getBytes().length); - RlpList rlpBatchData = - (RlpList) RlpDecoder.decode(batchData).getValues().getFirst(); - return Batch.decode(rlpBatchData, channel.l1InclusionBlock()); + byte[] buffer = ((RlpString) rlpType).getBytes(); + byte batchType = buffer[0]; + byte[] batchData = ArrayUtils.subarray(buffer, 1, buffer.length); + + if (BatchType.SPAN_BATCH_TYPE.getCode() == ((int) batchType)) { + return Batch.decodeRawSpanBatch(batchData, channel.l1InclusionBlock()); + } else if (BatchType.SINGULAR_BATCH_TYPE.getCode() == ((int) batchType)) { + RlpList rlpBatchData = (RlpList) + RlpDecoder.decode(batchData).getValues().getFirst(); + return Batch.decodeSingularBatch(rlpBatchData, channel.l1InclusionBlock()); + } else { + throw new IllegalArgumentException("invalid batch type"); + } }) .collect(Collectors.toList()); } @@ -153,6 +188,9 @@ private static byte[] decompressZlib(byte[] data) { byte[] buffer = new byte[1024]; while (!inflater.finished()) { int count = inflater.inflate(buffer); + if (count == 0) { + break; + } outputStream.write(buffer, 0, count); } @@ -163,7 +201,18 @@ private static byte[] decompressZlib(byte[] data) { } @SuppressWarnings("WhitespaceAround") - private BatchStatus batchStatus(Batch batch) { + private BatchStatus batchStatus(final Batch batch) { + if (batch.batch() instanceof SingularBatch) { + return singularBatchStatus(batch); + } else if (batch.batch() instanceof RawSpanBatch) { + return spanBatchStatus(batch); + } else { + throw new IllegalStateException("unknown batch type"); + } + } + + private BatchStatus singularBatchStatus(final Batch batchWrapper) { + final SingularBatch batch = (SingularBatch) batchWrapper.batch(); State state = this.state.get(); Epoch epoch = state.getSafeEpoch(); Epoch nextEpoch = state.epoch(epoch.number().add(BigInteger.ONE)); @@ -172,7 +221,8 @@ private BatchStatus batchStatus(Batch batch) { head.timestamp().add(this.config.chainConfig().blockTime()); // check timestamp range - switch (batch.timestamp().compareTo(nextTimestamp)) { + switch (batch.getTimestamp(this.config.chainConfig().l2Genesis().timestamp()) + .compareTo(nextTimestamp)) { case 1 -> { return BatchStatus.Future; } @@ -189,7 +239,8 @@ private BatchStatus batchStatus(Batch batch) { } // check the inclusion delay - if (batch.epochNum().add(this.config.chainConfig().seqWindowSize()).compareTo(batch.l1InclusionBlock()) < 0) { + if (batch.epochNum().add(this.config.chainConfig().seqWindowSize()).compareTo(batchWrapper.l1InclusionBlock()) + < 0) { LOGGER.warn("inclusion window elapsed"); return BatchStatus.Drop; } @@ -252,6 +303,211 @@ private BatchStatus batchStatus(Batch batch) { return BatchStatus.Accept; } + private BatchStatus spanBatchStatus(final Batch batchWrapper) { + final RawSpanBatch rawSpanBatch = (RawSpanBatch) batchWrapper.batch(); + final SpanBatch spanBatch = rawSpanBatch.toSpanBatch( + this.config.chainConfig().blockTime(), + this.config.chainConfig().l2Genesis().timestamp(), + this.config.chainConfig().l2ChainId()); + final State state = this.state.get(); + final Epoch epoch = state.getSafeEpoch(); + final Epoch nextEpoch = state.epoch(epoch.number().add(BigInteger.ONE)); + final BlockInfo l2SafeHead = state.getSafeHead(); + final BigInteger nextTimestamp = + l2SafeHead.timestamp().add(this.config.chainConfig().blockTime()); + + BigInteger originBits = rawSpanBatch.spanbatchPayload().originBits(); + + final BigInteger startEpochNum = rawSpanBatch + .spanbatchPrefix() + .l1OriginNum() + .subtract(originBits) + .add(originBits.testBit(0) ? BigInteger.ONE : BigInteger.ZERO); + final BigInteger endEpochNum = + Numeric.toBigInt(rawSpanBatch.spanbatchPrefix().encodeL1OriginNum()); + + final BigInteger spanStartTimestamp = rawSpanBatch + .spanbatchPrefix() + .relTimestamp() + .add(this.config.chainConfig().l2Genesis().timestamp()); + final BigInteger spanEndTimestamp = spanStartTimestamp.add( + BigInteger.valueOf(rawSpanBatch.spanbatchPayload().blockCount()) + .multiply(this.config.chainConfig().blockTime())); + + // check batch timestamp + if (spanEndTimestamp.compareTo(nextTimestamp) < 0) { + LOGGER.warn("past batch"); + return BatchStatus.Drop; + } + if (spanStartTimestamp.compareTo(nextTimestamp) > 0) { + return BatchStatus.Future; + } + + // check for delta activation + // startEpoch == (safeEpoch.number + 1) + final Epoch batchOrigin = startEpochNum.compareTo(epoch.number().add(BigInteger.ONE)) == 0 ? nextEpoch : epoch; + + if (batchOrigin == null) { + return BatchStatus.Undecided; + } + if (batchOrigin.timestamp().compareTo(this.config.chainConfig().deltaTime()) < 0) { + LOGGER.warn("epoch start time is before delta activation: epochStartTime=%d".formatted(batchOrigin.timestamp())); + return BatchStatus.Drop; + } + + // find previous l2 block + final BigInteger prevTimestamp = + spanStartTimestamp.subtract(this.config.chainConfig().blockTime()); + final var prevL2Info = state.l2Info(prevTimestamp); + if (prevL2Info == null) { + LOGGER.warn("previous l2 block not found: %d".formatted(prevTimestamp)); + return BatchStatus.Drop; + } + + final var prevL2Block = prevL2Info.component1(); + final var prevL2Epoch = prevL2Info.component2(); + // check that block builds on existing chain + if (!rawSpanBatch.spanbatchPrefix().parentCheck().toHexString().equalsIgnoreCase(prevL2Block.hash())) { + LOGGER.warn("batch parent check failed"); + return BatchStatus.Drop; + } + + if (startEpochNum.add(this.config.chainConfig().seqWindowSize()).compareTo(batchWrapper.l1InclusionBlock()) + < 0) { + LOGGER.warn("sequence window check failed"); + return BatchStatus.Drop; + } + + if (startEpochNum.compareTo(prevL2Block.number().add(BigInteger.ONE)) > 0) { + LOGGER.warn("invalid start epoch number"); + return BatchStatus.Drop; + } + + final Epoch l1Origin = state.epoch(endEpochNum); + if (l1Origin == null) { + LOGGER.warn("l1 origin not found"); + return BatchStatus.Drop; + } + if (rawSpanBatch.spanbatchPrefix().l1OriginCheck().toHexString().equalsIgnoreCase(l1Origin.hash())) { + LOGGER.warn("l1 origin check failed"); + return BatchStatus.Drop; + } + + if (startEpochNum.compareTo(prevL2Epoch.number()) < 0) { + LOGGER.warn("invalid start epoch number"); + return BatchStatus.Drop; + } + + // check sequencer drift + final int blockCount = (int) rawSpanBatch.spanbatchPayload().blockCount(); + for (int i = 0; i < blockCount; i++) { + final var blockTimestamp = spanBatch.getBlockTimestamp(i); + if (blockTimestamp.compareTo(l2SafeHead.timestamp()) <= 0) { + continue; + } + final BigInteger l1OriginNum = spanBatch.getBlockEpochNum(i); + final L1Info batchL1Origin = state.l1Info(l1OriginNum); + if (batchL1Origin == null) { + LOGGER.warn("l1 origin not found"); + return BatchStatus.Drop; + } + if (blockTimestamp.compareTo(batchL1Origin.blockInfo().timestamp()) < 0) { + LOGGER.warn("block timestamp is less than L1 origin timestamp"); + return BatchStatus.Drop; + } + final var max = batchL1Origin + .blockInfo() + .timestamp() + .add(this.config.chainConfig().maxSeqDrift()); + if (blockTimestamp.compareTo(max) > 0) { + if (!spanBatch.getBlockTransactions(i).isEmpty()) { + LOGGER.warn(String.format( + "batch exceeded sequencer time drift, sequencer must adopt new L1 origin to include transactions again: max=%d", + max)); + return BatchStatus.Drop; + } + if (!rawSpanBatch.spanbatchPayload().originBits().testBit(i)) { + var batchNextEpoch = state.l1Info(l1OriginNum.add(BigInteger.ONE)); + if (batchNextEpoch != null) { + if (blockTimestamp.compareTo(batchNextEpoch.blockInfo().timestamp()) >= 0) { + LOGGER.warn( + "batch exceeded sequencer time drift without adopting next origin, and next L1 origin would have been valid"); + return BatchStatus.Drop; + } + } else { + return BatchStatus.Undecided; + } + } + } + + if (spanBatch.hasInvalidTransactions(i)) { + LOGGER.warn(String.format("invalid transaction: empty or deposits into batch data: txIndex=%d", i)); + return BatchStatus.Drop; + } + } + + // overlapped block checks + for (SpanBatchElement element : spanBatch.getBatches()) { + if (element.timestamp().compareTo(nextTimestamp) >= 0) { + continue; + } + Tuple2 info = state.l2Info(element.timestamp()); + if (info == null) { + LOGGER.warn("overlapped l2 block not found"); + return BatchStatus.Drop; + } + + if (element.epochNum().compareTo(info.component2().number()) != 0) { + LOGGER.warn("epoch mismatch in overlapped blocks"); + return BatchStatus.Drop; + } + } + return BatchStatus.Accept; + } + + /** + * Gets singular batche list from IBatch instance. + * + * @param batch IBatch instance + * @param state the state + * @return the list that inner batch data was singular batch + */ + public List getSingularBatches(final IBatch batch, final State state) { + Function f = singularBatch -> new Batch(batch, state.getCurrentEpochNum()); + if (batch instanceof SingularBatch typedBatch) { + return List.of(f.apply(typedBatch)); + } else if (batch instanceof RawSpanBatch typedBatch) { + SpanBatch spanBatch = typedBatch.toSpanBatch( + this.config.chainConfig().blockTime(), + this.config.chainConfig().l2Genesis().timestamp(), + this.config.chainConfig().l2ChainId()); + return this.toSingularBatches(spanBatch, state).stream().map(f).collect(Collectors.toList()); + } else { + throw new IllegalStateException("unknown batch type"); + } + } + + private List toSingularBatches(final SpanBatch batch, final State state) { + List singularBatches = new ArrayList<>(); + for (SpanBatchElement element : batch.getBatches()) { + if (element.timestamp().compareTo(state.getSafeHead().timestamp()) <= 0) { + continue; + } + SingularBatch singularBatch = new SingularBatch(); + singularBatch.setEpochNum(singularBatch.epochNum()); + singularBatch.setTimestamp(singularBatch.timestamp()); + singularBatch.setTransactions(singularBatch.transactions()); + + Epoch l1Origins = state.epoch(singularBatch.epochNum()); + if (l1Origins == null) { + throw new RuntimeException("cannot find origin for epochNum: %d".formatted(element.epochNum())); + } + singularBatch.setEpochHash(state.epoch(singularBatch.epochNum()).hash()); + singularBatches.add(singularBatch); + } + return singularBatches; + } + /** * Create batches. * diff --git a/hildr-node/src/main/java/io/optimism/driver/Driver.java b/hildr-node/src/main/java/io/optimism/driver/Driver.java index 31fb7edf..f7c6540b 100644 --- a/hildr-node/src/main/java/io/optimism/driver/Driver.java +++ b/hildr-node/src/main/java/io/optimism/driver/Driver.java @@ -206,8 +206,9 @@ public static Driver from(Config config, CountDownLatch latch) finalizedHead.number(), config); + var l2Refs = io.optimism.derive.State.initL2Refs(finalizedHead.number(), config.chainConfig(), provider); AtomicReference state = - new AtomicReference<>(io.optimism.derive.State.create(finalizedHead, finalizedEpoch, config)); + new AtomicReference<>(io.optimism.derive.State.create(l2Refs, finalizedHead, finalizedEpoch, config)); EngineDriver engineDriver = new EngineDriver<>(finalizedHead, finalizedEpoch, provider, config); diff --git a/hildr-node/src/test/java/io/optimism/derive/stages/BatcherTransactionsTest.java b/hildr-node/src/test/java/io/optimism/derive/stages/BatcherTransactionsTest.java index e664f6f6..9a7e2b20 100644 --- a/hildr-node/src/test/java/io/optimism/derive/stages/BatcherTransactionsTest.java +++ b/hildr-node/src/test/java/io/optimism/derive/stages/BatcherTransactionsTest.java @@ -106,6 +106,9 @@ class BatcherTransactionsTest { + "4c665ca197cebff1c90e5484cc8a6cb2c5b1badab35aefa35c1384f0bb6459061ad574c2f" + "37f8bbbd2e8dff5f27f020000ffff8db4683801"; + private static final String BATCHER_TX_DATA = + "00656531d7fca1ad32740ea3adca85922a0000000005dc78dadac9f58b71c9d7edacb77bd6323dd823c8ffeb44c059dee7ffb405f9b68b2feb9a3ef3508cc78be9f9edab1ea8557c09e3b1e83cffc05f2a8445c09141c08145c0914580010e181930012332c588a68c114323238c603cffb8e3e20ecb8f4f0d365a15b4ffe09abf6ddad1b7755a79ac67ff39b7bb9ddf3c67ab929e46cd439bf56c7757a8f67dddd968dbf1fc647b4498f6929c0b75a5f2d5557d491b6293a37343b33f681e2c37ae551763b8fc8c598271c67aed7426ff8e2dd7170a31ffbdfce97bb5d9ed0b1dfb94efcb6eb5efdb1bfb7152f8c4b9ae321c5b73af7f12517f3ec15e6effd5f0ddae251cd7673eb65b5d26a1b1e5e68e4b328587b5e6dd56717fb93d6cb3d5ea07b7ffdc0c0af2f86ab8485c73cd3fef280316fe282d96b4be42fd9df28d562c77edecef9c923fe9f6a069a346c1b7b33e9cc76c3e46dc4bacfc191cd3c8afcbc12e52eeaa7c9127ed6412c70ebee6b52dbc825971322c5eaea9adfb6673a54fddf37696757ff4aafa433f6da3531b23988abba61d3ba7beeecbb40db56935f1e7661d3812798fb95131b69eefe68f25fbf7ee7dd870517a79b4cecf0bb73ac439d5a7b7942c3cdef156ac284f31467ba5e0b39a4d8f569c303bba2c52e1b8f98c0ce91d4a96b33ffcaa985c94b2c06ec781a0c9e9d3bc2670ef1429e09b782fb323d9692607dbe9a30589dbbb6e479efbbe72d62af9f038b605f38ced7d32266f751189ff6a68f2d4b63d94c5f88cf575f7cfbbc3e3fae64b5cdc7d4cadf8ebc24bb2894b657e733d78fb3e6d47dca4bdfc1d264c9d2562dfaff4396cb83cfd94c2dc7766cbd3d218fde61f12e6b9767ed36dc625138d6778f7187a28075597196a6d522f9ac9b8e60a77dc094daf395ec7175c0f63f1326a5f257762b172c517dfbdf6ce7ed7f518129fac14fa77d84140d9e2f92791a34b7e3d7f27a4e82c7c66fbf38589266a16d3a2db4eba4e0d7b646e98fdbdea9af4e3a7739a0acb5c53f65c70c24ca002361a978eee8e5a59adbce3c786730719839d1fce3e894d8c12bdc48a31fd64126c68e6777268e677cedbc9c4a2bf26538a011f60725ecb801f24e097665c40403fe7fefa0f719efb64a6f1b7ca591d5aaa36bfece6cb15dfc37ea65d6cf37fd3b971b6848de6dc1bd7debe378909b2bdd6afc061fd29fa6e59a3935dea85d34213658e093f3a776abee3b523ab2eb933771ee2f0718c8d55ce0fff7e4b4a3395fba9bd8949656292c2a18d5cb97dcfcfccaeba72f6d59b2f824df5f5ca6eff5f1db96e57b14fe370a9b0cca7aeca4e7d4b5b33a9b06496a936455325669e8b489e2c1e5bf5e55666cf0b57070f7585cf35d922eaf6a57f4d583f2e8d8e6cbf31b7f1d3c9d432b377166db5f61bf7695b6ed67cc4f2e58bc4d1a7b39fe79e63f1582adbac7831454fc322c952de71f9d463ff73b86ec5bcd0e5519176645bc29572fa7df1cf49d3df24ea2e10d00b9f1fdd2c3c4b32d0f3e8a6355bf57708142c6ae3e8e0ff97ae2fe0e9f1a09b5b488140f8317dbed5ba6f8acc3e09bb0299aae517394dea2eb96419548530587fbffde1a7c734b7a625d2193a179630bf3634942998f4517fd6c71b0155779c7f7ff9686daf705934ed00d38f9dedfc5a8b58ba2f30b44466e88308831f3b96186d67c845b6e8de5a7488c75550f328040d84141c60faf181bb59e0e45710def1242c523632b128a984814ae088bb4a55457efea747cf9ec61a2a7aaf7f74cc600b012d5c145a49483f37162f2715270f772f6f6ac097342f74698aa7dafab9714c563029fcc0c0a1f6dbc1049769bc0fb66d5e9ec230104933a9b8b86058c7d3ab866681ea0b4b362847edd3ecff7e22df3661dd5a9eb50c6c4e57171c5c67bebef4ec9e87d33bb9773f9e9f701a49a9492dd781dfb5075a6f58cfdb32d3edd0546dbd035167b8c4266d0c083cb22f5479fa8f6eae66c12d293b5a18577c48fd3355d363bdd5ef7cb6acc5fb7630cf3feda55f5678d57b87f786794f055d8eb1c5d23a8c7e08c91cf439e4237bd867c71da69d779876dd61dab794e5e73ef6090bf9272ce46f5fca3161217fcb69c923b7246ecc976407000000ffff01"; + /** Test decode tx. */ @Test @DisplayName("test decode tx.") diff --git a/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java b/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java index db8bd077..35773284 100644 --- a/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java +++ b/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java @@ -1,14 +1,22 @@ package io.optimism.derive.stages; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import io.optimism.config.Config; import io.optimism.derive.stages.Channels.Channel; import io.optimism.utilities.derive.stages.Batch; +import io.optimism.utilities.derive.stages.Frame; +import io.optimism.utilities.derive.stages.RawSpanBatch; +import io.optimism.utilities.derive.stages.SingularBatch; +import io.optimism.utilities.derive.stages.SpanBatch; import java.math.BigInteger; import java.util.List; +import org.bouncycastle.jcajce.provider.digest.Keccak; import org.bouncycastle.util.encoders.Hex; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.web3j.utils.Numeric; /** * The type BatchesTest. @@ -18,9 +26,11 @@ */ class BatchesTest { - /** Decode batches. */ + /** + * Decode singular batches. + */ @Test - @DisplayName("Test decode batches successfully") + @DisplayName("Test decode singular batches successfully") void decodeBatches() { String data = "78dad459793894fbdb7f9e19db20eb902dbb9086b410b2af2939b66c255bd60991" + "c8a133c6845276c9daa36c21bb3211932c8908591a6509132a3b1959decb" @@ -125,11 +135,65 @@ void decodeBatches() { + "59061ad574c2f37f8bbbd2e8dff5f27f020000ffff8db46838"; Channel channel = new Channel(BigInteger.ONE, Hex.decode(data), BigInteger.ONE); List batches = Batches.decodeBatches(channel); - System.out.println(batches); assertEquals(6, batches.size()); assertEquals( "0x9a6d7cf81309515caed98e08edffe9a467a71a707910474b5fde43e2a6fc6454", - batches.get(0).parentHash()); + ((SingularBatch) batches.get(0).batch()).parentHash()); + } + + /** + * Decode span batches. + */ + @Test + @DisplayName("Test decode span batches successfully") + void testDecodeSpanBatch() { + String data = + "00656531d7fca1ad32740ea3adca85922a0000000005dc78dadac9f58b71c9d7edacb77bd6323dd823c8ffeb44c059dee7ffb405f9b68b2feb9a3ef3508cc78be9f9edab1ea8557c09e3b1e83cffc05f2a8445c09141c08145c0914580010e181930012332c588a68c114323238c603cffb8e3e20ecb8f4f0d365a15b4ffe09abf6ddad1b7755a79ac67ff39b7bb9ddf3c67ab929e46cd439bf56c7757a8f67dddd968dbf1fc647b4498f6929c0b75a5f2d5557d491b6293a37343b33f681e2c37ae551763b8fc8c598271c67aed7426ff8e2dd7170a31ffbdfce97bb5d9ed0b1dfb94efcb6eb5efdb1bfb7152f8c4b9ae321c5b73af7f12517f3ec15e6effd5f0ddae251cd7673eb65b5d26a1b1e5e68e4b328587b5e6dd56717fb93d6cb3d5ea07b7ffdc0c0af2f86ab8485c73cd3fef280316fe282d96b4be42fd9df28d562c77edecef9c923fe9f6a069a346c1b7b33e9cc76c3e46dc4bacfc191cd3c8afcbc12e52eeaa7c9127ed6412c70ebee6b52dbc825971322c5eaea9adfb6673a54fddf37696757ff4aafa433f6da3531b23988abba61d3ba7beeecbb40db56935f1e7661d3812798fb95131b69eefe68f25fbf7ee7dd870517a79b4cecf0bb73ac439d5a7b7942c3cdef156ac284f31467ba5e0b39a4d8f569c303bba2c52e1b8f98c0ce91d4a96b33ffcaa985c94b2c06ec781a0c9e9d3bc2670ef1429e09b782fb323d9692607dbe9a30589dbbb6e479efbbe72d62af9f038b605f38ced7d32266f751189ff6a68f2d4b63d94c5f88cf575f7cfbbc3e3fae64b5cdc7d4cadf8ebc24bb2894b657e733d78fb3e6d47dca4bdfc1d264c9d2562dfaff4396cb83cfd94c2dc7766cbd3d218fde61f12e6b9767ed36dc625138d6778f7187a28075597196a6d522f9ac9b8e60a77dc094daf395ec7175c0f63f1326a5f257762b172c517dfbdf6ce7ed7f518129fac14fa77d84140d9e2f92791a34b7e3d7f27a4e82c7c66fbf38589266a16d3a2db4eba4e0d7b646e98fdbdea9af4e3a7739a0acb5c53f65c70c24ca002361a978eee8e5a59adbce3c786730719839d1fce3e894d8c12bdc48a31fd64126c68e6777268e677cedbc9c4a2bf26538a011f60725ecb801f24e097665c40403fe7fefa0f719efb64a6f1b7ca591d5aaa36bfece6cb15dfc37ea65d6cf37fd3b971b6848de6dc1bd7debe378909b2bdd6afc061fd29fa6e59a3935dea85d34213658e093f3a776abee3b523ab2eb933771ee2f0718c8d55ce0fff7e4b4a3395fba9bd8949656292c2a18d5cb97dcfcfccaeba72f6d59b2f824df5f5ca6eff5f1db96e57b14fe370a9b0cca7aeca4e7d4b5b33a9b06496a936455325669e8b489e2c1e5bf5e55666cf0b57070f7585cf35d922eaf6a57f4d583f2e8d8e6cbf31b7f1d3c9d432b377166db5f61bf7695b6ed67cc4f2e58bc4d1a7b39fe79e63f1582adbac7831454fc322c952de71f9d463ff73b86ec5bcd0e5519176645bc29572fa7df1cf49d3df24ea2e10d00b9f1fdd2c3c4b32d0f3e8a6355bf57708142c6ae3e8e0ff97ae2fe0e9f1a09b5b488140f8317dbed5ba6f8acc3e09bb0299aae517394dea2eb96419548530587fbffde1a7c734b7a625d2193a179630bf3634942998f4517fd6c71b0155779c7f7ff9686daf705934ed00d38f9dedfc5a8b58ba2f30b44466e88308831f3b96186d67c845b6e8de5a7488c75550f328040d84141c60faf181bb59e0e45710def1242c523632b128a984814ae088bb4a55457efea747cf9ec61a2a7aaf7f74cc600b012d5c145a49483f37162f2715270f772f6f6ac097342f74698aa7dafab9714c563029fcc0c0a1f6dbc1049769bc0fb66d5e9ec230104933a9b8b86058c7d3ab866681ea0b4b362847edd3ecff7e22df3661dd5a9eb50c6c4e57171c5c67bebef4ec9e87d33bb9773f9e9f701a49a9492dd781dfb5075a6f58cfdb32d3edd0546dbd035167b8c4266d0c083cb22f5479fa8f6eae66c12d293b5a18577c48fd3355d363bdd5ef7cb6acc5fb7630cf3feda55f5678d57b87f786794f055d8eb1c5d23a8c7e08c91cf439e4237bd867c71da69d779876dd61dab794e5e73ef6090bf9272ce46f5fca3161217fcb69c923b7246ecc976407000000ffff01"; + byte[] dataBytes = Numeric.hexStringToByteArray(data); + BatcherTransactions.BatcherTransaction tx = + BatcherTransactions.BatcherTransaction.create(dataBytes, BigInteger.valueOf(10254359L)); + Channels.PendingChannel pendingChannel = + Channels.PendingChannel.create(tx.frames().get(0)); + List frames = tx.frames(); + for (int i = 1; i < frames.size(); i++) { + pendingChannel.pushFrame(frames.get(i)); + } + Channel parseChannel = Channel.from(pendingChannel); + + String channelData = + "78dadac9f58b71c9d7edacb77bd6323dd823c8ffeb44c059dee7ffb405f9b68b2feb9a3ef3508cc78be9f9edab1ea8557c09e3b1e83cffc05f2a8445c09141c08145c0914580010e181930012332c588a68c114323238c603cffb8e3e20ecb8f4f0d365a15b4ffe09abf6ddad1b7755a79ac67ff39b7bb9ddf3c67ab929e46cd439bf56c7757a8f67dddd968dbf1fc647b4498f6929c0b75a5f2d5557d491b6293a37343b33f681e2c37ae551763b8fc8c598271c67aed7426ff8e2dd7170a31ffbdfce97bb5d9ed0b1dfb94efcb6eb5efdb1bfb7152f8c4b9ae321c5b73af7f12517f3ec15e6effd5f0ddae251cd7673eb65b5d26a1b1e5e68e4b328587b5e6dd56717fb93d6cb3d5ea07b7ffdc0c0af2f86ab8485c73cd3fef280316fe282d96b4be42fd9df28d562c77edecef9c923fe9f6a069a346c1b7b33e9cc76c3e46dc4bacfc191cd3c8afcbc12e52eeaa7c9127ed6412c70ebee6b52dbc825971322c5eaea9adfb6673a54fddf37696757ff4aafa433f6da3531b23988abba61d3ba7beeecbb40db56935f1e7661d3812798fb95131b69eefe68f25fbf7ee7dd870517a79b4cecf0bb73ac439d5a7b7942c3cdef156ac284f31467ba5e0b39a4d8f569c303bba2c52e1b8f98c0ce91d4a96b33ffcaa985c94b2c06ec781a0c9e9d3bc2670ef1429e09b782fb323d9692607dbe9a30589dbbb6e479efbbe72d62af9f038b605f38ced7d32266f751189ff6a68f2d4b63d94c5f88cf575f7cfbbc3e3fae64b5cdc7d4cadf8ebc24bb2894b657e733d78fb3e6d47dca4bdfc1d264c9d2562dfaff4396cb83cfd94c2dc7766cbd3d218fde61f12e6b9767ed36dc625138d6778f7187a28075597196a6d522f9ac9b8e60a77dc094daf395ec7175c0f63f1326a5f257762b172c517dfbdf6ce7ed7f518129fac14fa77d84140d9e2f92791a34b7e3d7f27a4e82c7c66fbf38589266a16d3a2db4eba4e0d7b646e98fdbdea9af4e3a7739a0acb5c53f65c70c24ca002361a978eee8e5a59adbce3c786730719839d1fce3e894d8c12bdc48a31fd64126c68e6777268e677cedbc9c4a2bf26538a011f60725ecb801f24e097665c40403fe7fefa0f719efb64a6f1b7ca591d5aaa36bfece6cb15dfc37ea65d6cf37fd3b971b6848de6dc1bd7debe378909b2bdd6afc061fd29fa6e59a3935dea85d34213658e093f3a776abee3b523ab2eb933771ee2f0718c8d55ce0fff7e4b4a3395fba9bd8949656292c2a18d5cb97dcfcfccaeba72f6d59b2f824df5f5ca6eff5f1db96e57b14fe370a9b0cca7aeca4e7d4b5b33a9b06496a936455325669e8b489e2c1e5bf5e55666cf0b57070f7585cf35d922eaf6a57f4d583f2e8d8e6cbf31b7f1d3c9d432b377166db5f61bf7695b6ed67cc4f2e58bc4d1a7b39fe79e63f1582adbac7831454fc322c952de71f9d463ff73b86ec5bcd0e5519176645bc29572fa7df1cf49d3df24ea2e10d00b9f1fdd2c3c4b32d0f3e8a6355bf57708142c6ae3e8e0ff97ae2fe0e9f1a09b5b488140f8317dbed5ba6f8acc3e09bb0299aae517394dea2eb96419548530587fbffde1a7c734b7a625d2193a179630bf3634942998f4517fd6c71b0155779c7f7ff9686daf705934ed00d38f9dedfc5a8b58ba2f30b44466e88308831f3b96186d67c845b6e8de5a7488c75550f328040d84141c60faf181bb59e0e45710def1242c523632b128a984814ae088bb4a55457efea747cf9ec61a2a7aaf7f74cc600b012d5c145a49483f37162f2715270f772f6f6ac097342f74698aa7dafab9714c563029fcc0c0a1f6dbc1049769bc0fb66d5e9ec230104933a9b8b86058c7d3ab866681ea0b4b362847edd3ecff7e22df3661dd5a9eb50c6c4e57171c5c67bebef4ec9e87d33bb9773f9e9f701a49a9492dd781dfb5075a6f58cfdb32d3edd0546dbd035167b8c4266d0c083cb22f5479fa8f6eae66c12d293b5a18577c48fd3355d363bdd5ef7cb6acc5fb7630cf3feda55f5678d57b87f786794f055d8eb1c5d23a8c7e08c91cf439e4237bd867c71da69d779876dd61dab794e5e73ef6090bf9272ce46f5fca3161217fcb69c923b7246ecc976407000000ffff"; + Channel channel = new Channel(BigInteger.ONE, Hex.decode(channelData), BigInteger.ZERO); + + assertArrayEquals(channel.data(), parseChannel.data()); + + List batches = Batches.decodeBatches(channel); + assertEquals(1, batches.size()); + + final Config.ChainConfig chainConfig = Config.ChainConfig.optimismSepolia(); + final var batch = (RawSpanBatch) batches.get(0).batch(); + + final SpanBatch spanBatch = batch.toSpanBatch( + chainConfig.blockTime(), chainConfig.l2Genesis().timestamp(), chainConfig.l2ChainId()); + long blockTxCountsSum = spanBatch.getBatches().stream() + .mapToLong(e -> e.transactions().size()) + .sum(); + assertEquals(9, blockTxCountsSum); + + assertEquals(BigInteger.ZERO, batches.get(0).l1InclusionBlock()); + + spanBatch.getBatches().forEach(element -> { + BigInteger unusedBlockNum = element.timestamp() + .subtract(chainConfig.l2Genesis().timestamp()) + .divide(BigInteger.TWO); + BigInteger unusedEpochNum = element.epochNum(); + System.out.println( + "block: %d, epoch: %d".formatted(unusedBlockNum.longValue(), unusedEpochNum.longValue())); + element.transactions().forEach(txStr -> { + var digest = new Keccak.Digest256(); + byte[] hash = digest.digest(Numeric.hexStringToByteArray(txStr)); + System.out.println(Numeric.toHexString(hash)); + }); + }); } } diff --git a/hildr-node/src/test/java/io/optimism/engine/EngineApiRequestTest.java b/hildr-node/src/test/java/io/optimism/engine/EngineApiRequestTest.java new file mode 100644 index 00000000..6a91e434 --- /dev/null +++ b/hildr-node/src/test/java/io/optimism/engine/EngineApiRequestTest.java @@ -0,0 +1,241 @@ +package io.optimism.engine; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Splitter; +import io.jsonwebtoken.security.Keys; +import io.optimism.utilities.rpc.Web3jProvider; +import java.io.File; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.Key; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.apache.tuweni.units.ethereum.Wei; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.Request; +import org.web3j.protocol.core.methods.response.EthSendTransaction; +import org.web3j.protocol.http.HttpService; +import org.web3j.tx.RawTransactionManager; +import org.web3j.tx.TransactionManager; +import org.web3j.utils.Numeric; + +/** + * @author thinkAfCod + * @since 0.1.1 + */ +public class EngineApiRequestTest { + + static final Key key = Keys.hmacShaKeyFor( + Numeric.hexStringToByteArray("bf549f5188556ce0951048ef467ec93067bc4ea21acebe46ef675cd4e8e015ff")); + ; + + @Test + @DisplayName("SendRequest") + void testSendReq() throws IOException { + // final String localServiceUrl = "http://localhost:8551"; + final String localServiceUrl = "http://127.0.0.1:9552"; + OkHttpClient client = new OkHttpClient.Builder() + .readTimeout(Duration.ofMinutes(5)) + .callTimeout(Duration.ofMinutes(5)) + .connectTimeout(Duration.ofMinutes(5)) + .build(); + + final var startIndex = 0; + // final var startIndex = 99149; + // final var startIndex = 13241; + final var pattern = Pattern.compile("\\d+"); + var sorter = (Comparator) (file1, file2) -> { + Matcher no1Matcher = pattern.matcher(file1.getName()); + Matcher no2Matcher = pattern.matcher(file2.getName()); + no1Matcher.find(); + no2Matcher.find(); + String file1No = no1Matcher.group(); + String file2No = no2Matcher.group(); + return Integer.valueOf(file1No).compareTo(Integer.valueOf(file2No)); + }; + // 遍历"./requeset_raw"文件夹内的文件 + var requestFiles = Arrays.stream(Objects.requireNonNull( + // new File("/Users/xiaqingchuan/WorkSpace/github/rollup/hildr/request_raw") + new File("/Users/xiaqingchuan/WorkSpace/github/rollup/hildr/request_rollop") + .listFiles(prefilterFile -> { + if (!prefilterFile.getName().contains("Request")) { + return false; + } + if (startIndex == 0) { + return true; + } + Matcher no1Matcher = pattern.matcher(prefilterFile.getName()); + no1Matcher.find(); + String no = no1Matcher.group(); + return Integer.parseInt(no) >= startIndex; + }))) + .sorted(sorter) + .toList(); + var mapper = new ObjectMapper(); + for (int i = 0; i < requestFiles.size(); i++) { + final File file = requestFiles.get(i); + // 读取文件内容 + Matcher no1Matcher = pattern.matcher(file.getName()); + no1Matcher.find(); + String unused = no1Matcher.group(); + String postBody = Files.readString(Paths.get(file.getPath())); + List split = Splitter.on("\r\n\r\n").splitToList(postBody); + Map map = mapper.readValue(split.getLast(), new TypeReference>() {}); + + var params = (ArrayList) map.get("params"); + if (map.get("method").equals("engine_forkchoiceUpdatedV2") && params.getLast() != null) { + var txs = (ArrayList) ((Map) params.getLast()).get("transactions"); + if (txs.size() != 1) { + System.out.println("has normal tx: " + unused); + } + } + // 构造请求 + RequestBody requestBody = RequestBody.create(split.getLast(), MediaType.get("application/json")); + final okhttp3.Request request = new okhttp3.Request.Builder() + .url(localServiceUrl) + .addHeader("authorization", String.format("Bearer %1$s", EngineApi.generateJws(key))) + .post(requestBody) + .build(); + // 发送请求 + try { + Response execute = client.newCall(request).execute(); + if (!execute.isSuccessful()) { + throw new IllegalStateException( + String.format("request failed: \n file: %s \n body:\n%s", file.getName(), postBody)); + } else { + unused = execute.body().string(); + System.out.println(unused); + } + execute.close(); + } catch (IllegalStateException e) { + throw e; + } catch (Exception e) { + e.printStackTrace(); + throw new IllegalStateException( + String.format("request failed: \n file: %s \n body:\n%s", file.getName(), postBody)); + } + } + } + + @Test + void testSendTransaction() throws Exception { + Web3j client = Web3jProvider.createClient("http://192.168.50.109:9545"); + Credentials credentials = + Credentials.create("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"); + TransactionManager txMgr = new RawTransactionManager(client, credentials); + // BigInteger gasPrice, BigInteger gasLimit, String to, String data, BigInteger value + EthSendTransaction unused = txMgr.sendEIP1559Transaction( + 1201101712L, + BigInteger.valueOf(10000000L), + BigInteger.valueOf(30000000L), + BigInteger.valueOf(1000000L), + "0xf5f0A5135486fF2715b1dfAead54eEaFfe6B8404", + "test12345668", + Wei.fromEth(1L).toBigInteger().divide(BigInteger.valueOf(100L))); + } + + @Test + @DisplayName("") + void testUpdateV2WithNullAttributes() throws IOException { + // HttpService httpService = new HttpService("http://127.0.0.1:8551"); + HttpService httpService = new HttpService("http://127.0.0.1:8552"); + ForkChoiceUpdate.ForkchoiceState state = new ForkChoiceUpdate.ForkchoiceState( + "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", + "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", + "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"); + // ForkChoiceUpdate.ForkchoiceState state = new + // ForkChoiceUpdate.ForkchoiceState( + // "0xe460dd641f493c0184f2544c9bcfe3b4dcfe69cfa8054f8aed291b0ddda0025e", + // "0xe460dd641f493c0184f2544c9bcfe3b4dcfe69cfa8054f8aed291b0ddda0025e", + // "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"); + updatePayload(httpService, Arrays.asList(state, null)); + } + + @Test + @DisplayName("") + void testGetPayloadV2() throws IOException { + HttpService httpService = new HttpService("http://127.0.0.1:8551"); + // HttpService httpService = new HttpService("http://127.0.0.1:8552"); + ExecutionPayload payloadV2 = getPayloadV2(httpService, List.of("0x59a95f1a0e05a669")); + // ExecutionPayload payloadV2 = getPayloadV2(httpService, + // List.of("0x2935588c228f5ab5")); + + var payloadStatus = + newPayloadV2(httpService, Collections.singletonList(payloadV2 != null ? payloadV2.toReq() : null)); + System.out.println(payloadStatus.getPayloadStatus().getStatus()); + } + + @Test + @DisplayName("test forkchoiceUpdateV2") + void testUpdateV2() throws IOException { + HttpService httpService = new HttpService("http://127.0.0.1:8551"); + // HttpService httpService = new HttpService("http://127.0.0.1:8552"); + + ForkChoiceUpdate.ForkchoiceState state = new ForkChoiceUpdate.ForkchoiceState( + "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", + "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", + "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"); + + ExecutionPayload.PayloadAttributes.PayloadAttributesReq req = + new ExecutionPayload.PayloadAttributes.PayloadAttributesReq( + "0x64d6dbae", + "0x32e4469959675ceed3d1a9f43709a8055d689d712844f820aa34dbc9f49e286c", + "0x4200000000000000000000000000000000000011", + Arrays.asList( + "0x7ef90159a03f8cb0302fe9f6cb3df3ea8a99cb388fa68ea51948490cd5ecd1a2572ad66a6c94deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b90104015d8eb900000000000000000000000000000000000000000000000000000000003e1ff00000000000000000000000000000000000000000000000000000000064d6dbac000000000000000000000000000000000000000000000000000000000ba15b6748f520cf4ddaf34c8336e6e490632ea3cf1e5e93b0b2bc6e917557e31845371b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000008f23bb38f531600e5d8fddaaec41f13fab46e98c00000000000000000000000000000000000000000000000000000000000000bc00000000000000000000000000000000000000000000000000000000000a6fe0"), + null, + true, + "0x1c9c380"); + OpEthForkChoiceUpdate unused = updatePayload(httpService, Arrays.asList(state, req)); + + // var payloadId = send.getForkChoiceUpdate().payloadId(); + // ExecutionPayload executionPayload = getPayloadV2(httpService, + // Collections.singletonList( + // payloadId != null ? Numeric.toHexStringWithPrefixZeroPadded(payloadId, 16) : + // null)); + // + // var payloadStatus = newPayloadV2(httpService, + // Collections.singletonList(executionPayload != null ? executionPayload.toReq() + // : null)); + // System.out.println(ExecutionPayload.Status.VALID.equals(payloadStatus.getPayloadStatus().getStatus())); + } + + public OpEthForkChoiceUpdate updatePayload(HttpService httpService, List params) throws IOException { + httpService.addHeader("authorization", String.format("Bearer %1$s", EngineApi.generateJws(key))); + Request r = + new Request<>("engine_forkchoiceUpdatedV2", params, httpService, OpEthForkChoiceUpdate.class); + return r.send(); + } + + public ExecutionPayload getPayloadV2(HttpService httpService, List params) throws IOException { + httpService.addHeader("authorization", String.format("Bearer %1$s", EngineApi.generateJws(key))); + Request payloadRes = + new Request<>("engine_getPayloadV2", params, httpService, OpEthExecutionPayload.class); + return payloadRes.send().getExecutionPayload(); + } + + public OpEthPayloadStatus newPayloadV2(HttpService httpService, List params) throws IOException { + httpService.addHeader("authorization", String.format("Bearer %1$s", EngineApi.generateJws(key))); + Request payloadRes = + new Request<>("engine_newPayloadV2", params, httpService, OpEthPayloadStatus.class); + return payloadRes.send(); + } +} diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java index f9a0caf8..94205867 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java @@ -1,34 +1,28 @@ package io.optimism.utilities.derive.stages; +import com.google.common.primitives.Bytes; +import io.netty.buffer.Unpooled; import java.math.BigInteger; -import java.util.List; -import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.web3j.rlp.RlpEncoder; import org.web3j.rlp.RlpList; -import org.web3j.rlp.RlpString; -import org.web3j.rlp.RlpType; -import org.web3j.utils.Numeric; /** * The type Batch. * - * @param parentHash the parent hash - * @param epochNum the epoch num - * @param epochHash the epoch hash - * @param timestamp the timestamp - * @param transactions the transactions + * @param batch the batch * @param l1InclusionBlock L1 inclusion block * @author grapebaba - * @since 0.1.0 + * @since 0.2.4 */ -public record Batch( - String parentHash, - BigInteger epochNum, - String epochHash, - BigInteger timestamp, - List transactions, - BigInteger l1InclusionBlock) { +public record Batch(IBatch batch, BigInteger l1InclusionBlock) { + + /** + * Gets timestamp. + * + * @return the timestamp + */ + public BigInteger timestamp(BigInteger l2genesisTimestamp) { + return batch.getTimestamp(l2genesisTimestamp); + } /** * Encode batch. @@ -36,46 +30,40 @@ public record Batch( * @return encoded bytes by the batch */ public byte[] encode() { - List collect = transactions().stream() - .map(tx -> (RlpType) RlpString.create(tx)) - .collect(Collectors.toList()); - return RlpEncoder.encode(new RlpList( - RlpString.create(parentHash()), - RlpString.create(epochNum()), - RlpString.create(epochHash()), - RlpString.create(timestamp()), - new RlpList(collect))); + if (batch instanceof SingularBatch) { + var typedBatch = (SingularBatch) batch; + return typedBatch.encode(); + } else if (batch instanceof RawSpanBatch) { + var typedBatch = (RawSpanBatch) batch; + return Bytes.concat( + typedBatch.spanbatchPrefix().encode(), + typedBatch.spanbatchPayload().encode()); + } else { + throw new IllegalStateException("unknown batch type"); + } } /** - * Decode batch. + * Decode singular batch. * * @param rlp the rlp * @param l1InclusionBlock L1 inclusion block * @return the batch */ - public static Batch decode(RlpList rlp, BigInteger l1InclusionBlock) { - String parentHash = ((RlpString) rlp.getValues().get(0)).asString(); - BigInteger epochNum = ((RlpString) rlp.getValues().get(1)).asPositiveBigInteger(); - String epochHash = ((RlpString) rlp.getValues().get(2)).asString(); - BigInteger timestamp = ((RlpString) rlp.getValues().get(3)).asPositiveBigInteger(); - List transactions = ((RlpList) rlp.getValues().get(4)) - .getValues().stream() - .map(rlpString -> ((RlpString) rlpString).asString()) - .collect(Collectors.toList()); - return new Batch(parentHash, epochNum, epochHash, timestamp, transactions, l1InclusionBlock); + public static Batch decodeSingularBatch(final RlpList rlp, final BigInteger l1InclusionBlock) { + return new Batch(SingularBatch.decode(rlp), l1InclusionBlock); } /** - * Has invalid transactions boolean. + * Decode span batch. * - * @return the boolean + * @param buf the span batch encoded bytes + * @param l1InclusionBlock L1 inclusion block + * @return the batch */ - public boolean hasInvalidTransactions() { - return this.transactions.stream() - .anyMatch(s -> StringUtils.isEmpty(s) - || (Numeric.containsHexPrefix("0x") - ? StringUtils.startsWithIgnoreCase(s, "0x7E") - : StringUtils.startsWithIgnoreCase(s, "7E"))); + public static Batch decodeRawSpanBatch(final byte[] buf, final BigInteger l1InclusionBlock) { + final RawSpanBatch rawSpanBatch = new RawSpanBatch(); + rawSpanBatch.decode(Unpooled.wrappedBuffer(buf)); + return new Batch(rawSpanBatch, l1InclusionBlock); } } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java index 05e7c93b..f3f1646d 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java @@ -24,5 +24,5 @@ public interface IBatch { * * @return the timestamp */ - BigInteger getTimestamp(); + BigInteger getTimestamp(BigInteger l2genesisTimestamp); } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java index 1fa7cf80..0c361050 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java @@ -96,8 +96,8 @@ public BatchType getBatchType() { } @Override - public BigInteger getTimestamp() { - return null; + public BigInteger getTimestamp(BigInteger l2genesisTimestamp) { + return spanbatchPrefix.relTimestamp().add(l2genesisTimestamp); } /** diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SingularBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SingularBatch.java index 4745a4fa..94dff075 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SingularBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SingularBatch.java @@ -5,10 +5,12 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.web3j.rlp.RlpEncoder; import org.web3j.rlp.RlpList; import org.web3j.rlp.RlpString; import org.web3j.rlp.RlpType; +import org.web3j.utils.Numeric; /** * The type SingularBatch. @@ -96,7 +98,7 @@ public BatchType getBatchType() { } @Override - public BigInteger getTimestamp() { + public BigInteger getTimestamp(BigInteger l2genesisTimestamp) { return timestamp(); } @@ -229,4 +231,17 @@ public String toString() { return "SingularBatch[parentHash=%s, epochNum=%s, epochHash=%s, timestamp=%s, transactions=%s]" .formatted(parentHash, epochNum, epochHash, timestamp, transactions); } + + /** + * Has invalid transactions boolean. + * + * @return the boolean + */ + public boolean hasInvalidTransactions() { + return this.transactions.stream() + .anyMatch(s -> StringUtils.isEmpty(s) + || (Numeric.containsHexPrefix(s) + ? StringUtils.startsWithIgnoreCase(s, "0x7E") + : StringUtils.startsWithIgnoreCase(s, "7E"))); + } } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java index 0e3faa85..285c3792 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java @@ -10,6 +10,7 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.apache.tuweni.bytes.Bytes; import org.slf4j.Logger; import org.web3j.utils.Numeric; @@ -98,7 +99,7 @@ public BatchType getBatchType() { } @Override - public BigInteger getTimestamp() { + public BigInteger getTimestamp(BigInteger l2genesisTimestamp) { return batches.getFirst().timestamp(); } @@ -161,6 +162,20 @@ public List getBlockTransactions(int index) { return this.batches.get(index).transactions(); } + /** + * Has invalid transactions boolean. + * + * @param index the index + * @return the boolean + */ + public boolean hasInvalidTransactions(int index) { + return this.getBlockTransactions(index).stream() + .anyMatch(s -> StringUtils.isEmpty(s) + || (Numeric.containsHexPrefix(s) + ? StringUtils.startsWithIgnoreCase(s, "0x7E") + : StringUtils.startsWithIgnoreCase(s, "7E"))); + } + /** * GetBlockCount * @@ -176,7 +191,7 @@ public int getBlockCount() { * * @param singularBatch SingularBatch */ - public void AppendSingularBatch(SingularBatch singularBatch) { + public void appendSingularBatch(SingularBatch singularBatch) { if (batches.isEmpty()) { this.parentCheck = Bytes.fromHexStringLenient(singularBatch.parentHash().substring(0, 40)); @@ -426,7 +441,7 @@ public void AppendSingularBatch(SingularBatch singularBatch, BigInteger seqNum) } } - this.spanBatch.AppendSingularBatch(singularBatch); + this.spanBatch.appendSingularBatch(singularBatch); } /** From 572e05a643c713b284097816e2e674921f7a4574 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Tue, 30 Jan 2024 16:27:45 +0800 Subject: [PATCH 02/11] fix: add logs --- .../main/java/io/optimism/derive/stages/Batches.java | 12 +++++++++--- .../io/optimism/utilities/derive/stages/Batch.java | 1 + .../io/optimism/utilities/derive/stages/IBatch.java | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java index b8b541fa..b3882ad1 100644 --- a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java +++ b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java @@ -351,7 +351,8 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { return BatchStatus.Undecided; } if (batchOrigin.timestamp().compareTo(this.config.chainConfig().deltaTime()) < 0) { - LOGGER.warn("epoch start time is before delta activation: epochStartTime=%d".formatted(batchOrigin.timestamp())); + LOGGER.warn("epoch start time is before delta activation: epochStartTime=%d" + .formatted(batchOrigin.timestamp())); return BatchStatus.Drop; } @@ -367,8 +368,13 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { final var prevL2Block = prevL2Info.component1(); final var prevL2Epoch = prevL2Info.component2(); // check that block builds on existing chain - if (!rawSpanBatch.spanbatchPrefix().parentCheck().toHexString().equalsIgnoreCase(prevL2Block.hash())) { - LOGGER.warn("batch parent check failed"); + final String spanBatchParentCheck = + rawSpanBatch.spanbatchPrefix().parentCheck().toHexString(); + if (!spanBatchParentCheck.equalsIgnoreCase(prevL2Block.hash())) { + LOGGER.warn( + "batch parent check failed: batchParent={}; prevL2BlockHash={}", + spanBatchParentCheck, + prevL2Block.hash()); return BatchStatus.Drop; } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java index 94205867..32bbd636 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java @@ -18,6 +18,7 @@ public record Batch(IBatch batch, BigInteger l1InclusionBlock) { /** * Gets timestamp. * + * @param l2genesisTimestamp L2 genesis timestamp * @return the timestamp */ public BigInteger timestamp(BigInteger l2genesisTimestamp) { diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java index f3f1646d..dc838d62 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java @@ -22,6 +22,7 @@ public interface IBatch { /** * Gets timestamp. * + * @param l2genesisTimestamp L2 genesis timestamp * @return the timestamp */ BigInteger getTimestamp(BigInteger l2genesisTimestamp); From 9b51162b54ea078f19b4d4f376c02d438cf09857 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Tue, 30 Jan 2024 16:46:03 +0800 Subject: [PATCH 03/11] fix: l1 origin check value and parent check value --- .../src/main/java/io/optimism/derive/stages/Batches.java | 7 +++++-- .../test/java/io/optimism/derive/stages/BatchesTest.java | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java index b3882ad1..41d6e27c 100644 --- a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java +++ b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java @@ -370,7 +370,8 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { // check that block builds on existing chain final String spanBatchParentCheck = rawSpanBatch.spanbatchPrefix().parentCheck().toHexString(); - if (!spanBatchParentCheck.equalsIgnoreCase(prevL2Block.hash())) { + + if (!spanBatchParentCheck.equalsIgnoreCase(prevL2Block.hash().substring(0, 42))) { LOGGER.warn( "batch parent check failed: batchParent={}; prevL2BlockHash={}", spanBatchParentCheck, @@ -394,7 +395,9 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { LOGGER.warn("l1 origin not found"); return BatchStatus.Drop; } - if (rawSpanBatch.spanbatchPrefix().l1OriginCheck().toHexString().equalsIgnoreCase(l1Origin.hash())) { + final String l1OriginCheck = + rawSpanBatch.spanbatchPrefix().l1OriginCheck().toHexString(); + if (l1OriginCheck.equalsIgnoreCase(l1Origin.hash().substring(0, 42))) { LOGGER.warn("l1 origin check failed"); return BatchStatus.Drop; } diff --git a/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java b/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java index 35773284..4cfea0fb 100644 --- a/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java +++ b/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java @@ -196,4 +196,12 @@ void testDecodeSpanBatch() { }); }); } + + @Test + void testSub() { + String s1 = "0xe0bc110ffac850cd0de7fe2b110eb717a68a9799"; + String s2 = "0xe0bc110ffac850cd0de7fe2b110eb717a68a9799797fd99cd89bf1b155a7aac2"; + String s3 = s2.substring(0, 42); + assertEquals(s1, s3); + } } From 3795fe47b25c3f07e915e6b2a9c8011e3e03e9bd Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Tue, 30 Jan 2024 18:33:17 +0800 Subject: [PATCH 04/11] fix: startEpochNum value and l1 origin check value --- .../java/io/optimism/derive/stages/Batches.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java index 41d6e27c..bc6d374c 100644 --- a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java +++ b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java @@ -34,7 +34,6 @@ import org.web3j.rlp.RlpString; import org.web3j.rlp.RlpType; import org.web3j.tuples.generated.Tuple2; -import org.web3j.utils.Numeric; /** * The type Batches. @@ -321,10 +320,9 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { final BigInteger startEpochNum = rawSpanBatch .spanbatchPrefix() .l1OriginNum() - .subtract(originBits) + .subtract(BigInteger.valueOf(originBits.bitCount())) .add(originBits.testBit(0) ? BigInteger.ONE : BigInteger.ZERO); - final BigInteger endEpochNum = - Numeric.toBigInt(rawSpanBatch.spanbatchPrefix().encodeL1OriginNum()); + final BigInteger endEpochNum = rawSpanBatch.spanbatchPrefix().l1OriginNum(); final BigInteger spanStartTimestamp = rawSpanBatch .spanbatchPrefix() @@ -381,7 +379,11 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { if (startEpochNum.add(this.config.chainConfig().seqWindowSize()).compareTo(batchWrapper.l1InclusionBlock()) < 0) { - LOGGER.warn("sequence window check failed"); + LOGGER.warn( + "sequence window check failed: startEpochNum={} + seqWindowSize={} < l1InclusionBlock={}", + startEpochNum, + this.config.chainConfig().seqWindowSize(), + batchWrapper.l1InclusionBlock()); return BatchStatus.Drop; } @@ -397,7 +399,7 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { } final String l1OriginCheck = rawSpanBatch.spanbatchPrefix().l1OriginCheck().toHexString(); - if (l1OriginCheck.equalsIgnoreCase(l1Origin.hash().substring(0, 42))) { + if (!l1OriginCheck.equalsIgnoreCase(l1Origin.hash().substring(0, 42))) { LOGGER.warn("l1 origin check failed"); return BatchStatus.Drop; } From a83d9df3e4d3bc22c29329922c17b70c39fb828a Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Tue, 30 Jan 2024 19:24:09 +0800 Subject: [PATCH 05/11] fix: to singular batches method --- .../java/io/optimism/derive/stages/Batches.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java index bc6d374c..66538017 100644 --- a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java +++ b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java @@ -101,15 +101,16 @@ public Batch next() { while (true) { if (this.batches.firstEntry() != null) { Batch batch = this.batches.firstEntry().getValue(); - BigInteger timestamp = this.config.chainConfig().l2Genesis().timestamp(); + BigInteger l1GenesisTimestamp = + this.config.chainConfig().l2Genesis().timestamp(); switch (batchStatus(batch)) { case Accept: derivedBatch = batch; - this.batches.remove(batch.timestamp(timestamp)); + this.batches.remove(batch.timestamp(l1GenesisTimestamp)); break loop; case Drop: LOGGER.warn("dropping invalid batch"); - this.batches.remove(batch.timestamp(timestamp)); + this.batches.remove(batch.timestamp(l1GenesisTimestamp)); continue; case Future, Undecided: break loop; @@ -484,7 +485,7 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { * @return the list that inner batch data was singular batch */ public List getSingularBatches(final IBatch batch, final State state) { - Function f = singularBatch -> new Batch(batch, state.getCurrentEpochNum()); + Function f = singularBatch -> new Batch(singularBatch, state.getCurrentEpochNum()); if (batch instanceof SingularBatch typedBatch) { return List.of(f.apply(typedBatch)); } else if (batch instanceof RawSpanBatch typedBatch) { @@ -505,11 +506,11 @@ private List toSingularBatches(final SpanBatch batch, final State continue; } SingularBatch singularBatch = new SingularBatch(); - singularBatch.setEpochNum(singularBatch.epochNum()); - singularBatch.setTimestamp(singularBatch.timestamp()); - singularBatch.setTransactions(singularBatch.transactions()); + singularBatch.setEpochNum(element.epochNum()); + singularBatch.setTimestamp(element.timestamp()); + singularBatch.setTransactions(element.transactions()); - Epoch l1Origins = state.epoch(singularBatch.epochNum()); + Epoch l1Origins = state.epoch(element.epochNum()); if (l1Origins == null) { throw new RuntimeException("cannot find origin for epochNum: %d".formatted(element.epochNum())); } From c61fd7fefdd8a0fb9168cf3dba4845ec2a4efe21 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Tue, 30 Jan 2024 19:52:18 +0800 Subject: [PATCH 06/11] fix: delete code --- .../main/java/io/optimism/rpc/RpcServer.java | 7 - .../optimism/engine/EngineApiRequestTest.java | 241 ------------------ 2 files changed, 248 deletions(-) delete mode 100644 hildr-node/src/test/java/io/optimism/engine/EngineApiRequestTest.java diff --git a/hildr-node/src/main/java/io/optimism/rpc/RpcServer.java b/hildr-node/src/main/java/io/optimism/rpc/RpcServer.java index ae4c7c15..f421526c 100644 --- a/hildr-node/src/main/java/io/optimism/rpc/RpcServer.java +++ b/hildr-node/src/main/java/io/optimism/rpc/RpcServer.java @@ -19,7 +19,6 @@ import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.ServerWebSocket; import io.vertx.ext.web.Route; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; @@ -68,7 +67,6 @@ public RpcServer(final Config config) { /** Start. */ public void start() { this.httpServer = vertx.createHttpServer(getHttpServerOptions(config)); - httpServer.webSocketHandler(webSocketHandler()); httpServer.connectionHandler(connectionHandler()); CompletableFuture future = new CompletableFuture<>(); @@ -133,11 +131,6 @@ private Handler connectionHandler() { }; } - private Handler webSocketHandler() { - Handler o = null; - return o; - } - private HttpServerOptions getHttpServerOptions(final Config config) { final HttpServerOptions httpServerOptions = new HttpServerOptions() .setHost("0.0.0.0") diff --git a/hildr-node/src/test/java/io/optimism/engine/EngineApiRequestTest.java b/hildr-node/src/test/java/io/optimism/engine/EngineApiRequestTest.java deleted file mode 100644 index 6a91e434..00000000 --- a/hildr-node/src/test/java/io/optimism/engine/EngineApiRequestTest.java +++ /dev/null @@ -1,241 +0,0 @@ -package io.optimism.engine; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Splitter; -import io.jsonwebtoken.security.Keys; -import io.optimism.utilities.rpc.Web3jProvider; -import java.io.File; -import java.io.IOException; -import java.math.BigInteger; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.Key; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.RequestBody; -import okhttp3.Response; -import org.apache.tuweni.units.ethereum.Wei; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.web3j.crypto.Credentials; -import org.web3j.protocol.Web3j; -import org.web3j.protocol.core.Request; -import org.web3j.protocol.core.methods.response.EthSendTransaction; -import org.web3j.protocol.http.HttpService; -import org.web3j.tx.RawTransactionManager; -import org.web3j.tx.TransactionManager; -import org.web3j.utils.Numeric; - -/** - * @author thinkAfCod - * @since 0.1.1 - */ -public class EngineApiRequestTest { - - static final Key key = Keys.hmacShaKeyFor( - Numeric.hexStringToByteArray("bf549f5188556ce0951048ef467ec93067bc4ea21acebe46ef675cd4e8e015ff")); - ; - - @Test - @DisplayName("SendRequest") - void testSendReq() throws IOException { - // final String localServiceUrl = "http://localhost:8551"; - final String localServiceUrl = "http://127.0.0.1:9552"; - OkHttpClient client = new OkHttpClient.Builder() - .readTimeout(Duration.ofMinutes(5)) - .callTimeout(Duration.ofMinutes(5)) - .connectTimeout(Duration.ofMinutes(5)) - .build(); - - final var startIndex = 0; - // final var startIndex = 99149; - // final var startIndex = 13241; - final var pattern = Pattern.compile("\\d+"); - var sorter = (Comparator) (file1, file2) -> { - Matcher no1Matcher = pattern.matcher(file1.getName()); - Matcher no2Matcher = pattern.matcher(file2.getName()); - no1Matcher.find(); - no2Matcher.find(); - String file1No = no1Matcher.group(); - String file2No = no2Matcher.group(); - return Integer.valueOf(file1No).compareTo(Integer.valueOf(file2No)); - }; - // 遍历"./requeset_raw"文件夹内的文件 - var requestFiles = Arrays.stream(Objects.requireNonNull( - // new File("/Users/xiaqingchuan/WorkSpace/github/rollup/hildr/request_raw") - new File("/Users/xiaqingchuan/WorkSpace/github/rollup/hildr/request_rollop") - .listFiles(prefilterFile -> { - if (!prefilterFile.getName().contains("Request")) { - return false; - } - if (startIndex == 0) { - return true; - } - Matcher no1Matcher = pattern.matcher(prefilterFile.getName()); - no1Matcher.find(); - String no = no1Matcher.group(); - return Integer.parseInt(no) >= startIndex; - }))) - .sorted(sorter) - .toList(); - var mapper = new ObjectMapper(); - for (int i = 0; i < requestFiles.size(); i++) { - final File file = requestFiles.get(i); - // 读取文件内容 - Matcher no1Matcher = pattern.matcher(file.getName()); - no1Matcher.find(); - String unused = no1Matcher.group(); - String postBody = Files.readString(Paths.get(file.getPath())); - List split = Splitter.on("\r\n\r\n").splitToList(postBody); - Map map = mapper.readValue(split.getLast(), new TypeReference>() {}); - - var params = (ArrayList) map.get("params"); - if (map.get("method").equals("engine_forkchoiceUpdatedV2") && params.getLast() != null) { - var txs = (ArrayList) ((Map) params.getLast()).get("transactions"); - if (txs.size() != 1) { - System.out.println("has normal tx: " + unused); - } - } - // 构造请求 - RequestBody requestBody = RequestBody.create(split.getLast(), MediaType.get("application/json")); - final okhttp3.Request request = new okhttp3.Request.Builder() - .url(localServiceUrl) - .addHeader("authorization", String.format("Bearer %1$s", EngineApi.generateJws(key))) - .post(requestBody) - .build(); - // 发送请求 - try { - Response execute = client.newCall(request).execute(); - if (!execute.isSuccessful()) { - throw new IllegalStateException( - String.format("request failed: \n file: %s \n body:\n%s", file.getName(), postBody)); - } else { - unused = execute.body().string(); - System.out.println(unused); - } - execute.close(); - } catch (IllegalStateException e) { - throw e; - } catch (Exception e) { - e.printStackTrace(); - throw new IllegalStateException( - String.format("request failed: \n file: %s \n body:\n%s", file.getName(), postBody)); - } - } - } - - @Test - void testSendTransaction() throws Exception { - Web3j client = Web3jProvider.createClient("http://192.168.50.109:9545"); - Credentials credentials = - Credentials.create("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"); - TransactionManager txMgr = new RawTransactionManager(client, credentials); - // BigInteger gasPrice, BigInteger gasLimit, String to, String data, BigInteger value - EthSendTransaction unused = txMgr.sendEIP1559Transaction( - 1201101712L, - BigInteger.valueOf(10000000L), - BigInteger.valueOf(30000000L), - BigInteger.valueOf(1000000L), - "0xf5f0A5135486fF2715b1dfAead54eEaFfe6B8404", - "test12345668", - Wei.fromEth(1L).toBigInteger().divide(BigInteger.valueOf(100L))); - } - - @Test - @DisplayName("") - void testUpdateV2WithNullAttributes() throws IOException { - // HttpService httpService = new HttpService("http://127.0.0.1:8551"); - HttpService httpService = new HttpService("http://127.0.0.1:8552"); - ForkChoiceUpdate.ForkchoiceState state = new ForkChoiceUpdate.ForkchoiceState( - "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", - "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", - "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"); - // ForkChoiceUpdate.ForkchoiceState state = new - // ForkChoiceUpdate.ForkchoiceState( - // "0xe460dd641f493c0184f2544c9bcfe3b4dcfe69cfa8054f8aed291b0ddda0025e", - // "0xe460dd641f493c0184f2544c9bcfe3b4dcfe69cfa8054f8aed291b0ddda0025e", - // "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"); - updatePayload(httpService, Arrays.asList(state, null)); - } - - @Test - @DisplayName("") - void testGetPayloadV2() throws IOException { - HttpService httpService = new HttpService("http://127.0.0.1:8551"); - // HttpService httpService = new HttpService("http://127.0.0.1:8552"); - ExecutionPayload payloadV2 = getPayloadV2(httpService, List.of("0x59a95f1a0e05a669")); - // ExecutionPayload payloadV2 = getPayloadV2(httpService, - // List.of("0x2935588c228f5ab5")); - - var payloadStatus = - newPayloadV2(httpService, Collections.singletonList(payloadV2 != null ? payloadV2.toReq() : null)); - System.out.println(payloadStatus.getPayloadStatus().getStatus()); - } - - @Test - @DisplayName("test forkchoiceUpdateV2") - void testUpdateV2() throws IOException { - HttpService httpService = new HttpService("http://127.0.0.1:8551"); - // HttpService httpService = new HttpService("http://127.0.0.1:8552"); - - ForkChoiceUpdate.ForkchoiceState state = new ForkChoiceUpdate.ForkchoiceState( - "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", - "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", - "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"); - - ExecutionPayload.PayloadAttributes.PayloadAttributesReq req = - new ExecutionPayload.PayloadAttributes.PayloadAttributesReq( - "0x64d6dbae", - "0x32e4469959675ceed3d1a9f43709a8055d689d712844f820aa34dbc9f49e286c", - "0x4200000000000000000000000000000000000011", - Arrays.asList( - "0x7ef90159a03f8cb0302fe9f6cb3df3ea8a99cb388fa68ea51948490cd5ecd1a2572ad66a6c94deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b90104015d8eb900000000000000000000000000000000000000000000000000000000003e1ff00000000000000000000000000000000000000000000000000000000064d6dbac000000000000000000000000000000000000000000000000000000000ba15b6748f520cf4ddaf34c8336e6e490632ea3cf1e5e93b0b2bc6e917557e31845371b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000008f23bb38f531600e5d8fddaaec41f13fab46e98c00000000000000000000000000000000000000000000000000000000000000bc00000000000000000000000000000000000000000000000000000000000a6fe0"), - null, - true, - "0x1c9c380"); - OpEthForkChoiceUpdate unused = updatePayload(httpService, Arrays.asList(state, req)); - - // var payloadId = send.getForkChoiceUpdate().payloadId(); - // ExecutionPayload executionPayload = getPayloadV2(httpService, - // Collections.singletonList( - // payloadId != null ? Numeric.toHexStringWithPrefixZeroPadded(payloadId, 16) : - // null)); - // - // var payloadStatus = newPayloadV2(httpService, - // Collections.singletonList(executionPayload != null ? executionPayload.toReq() - // : null)); - // System.out.println(ExecutionPayload.Status.VALID.equals(payloadStatus.getPayloadStatus().getStatus())); - } - - public OpEthForkChoiceUpdate updatePayload(HttpService httpService, List params) throws IOException { - httpService.addHeader("authorization", String.format("Bearer %1$s", EngineApi.generateJws(key))); - Request r = - new Request<>("engine_forkchoiceUpdatedV2", params, httpService, OpEthForkChoiceUpdate.class); - return r.send(); - } - - public ExecutionPayload getPayloadV2(HttpService httpService, List params) throws IOException { - httpService.addHeader("authorization", String.format("Bearer %1$s", EngineApi.generateJws(key))); - Request payloadRes = - new Request<>("engine_getPayloadV2", params, httpService, OpEthExecutionPayload.class); - return payloadRes.send().getExecutionPayload(); - } - - public OpEthPayloadStatus newPayloadV2(HttpService httpService, List params) throws IOException { - httpService.addHeader("authorization", String.format("Bearer %1$s", EngineApi.generateJws(key))); - Request payloadRes = - new Request<>("engine_newPayloadV2", params, httpService, OpEthPayloadStatus.class); - return payloadRes.send(); - } -} From 7414da3e809bf9d4025b6201e61c96f3cdbc290a Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Tue, 30 Jan 2024 20:13:25 +0800 Subject: [PATCH 07/11] fix: fix test case --- .../io/optimism/utilities/derive/stages/SpanBatchTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hildr-utilities/src/test/java/io/optimism/utilities/derive/stages/SpanBatchTest.java b/hildr-utilities/src/test/java/io/optimism/utilities/derive/stages/SpanBatchTest.java index 1ab78f00..5036adc0 100644 --- a/hildr-utilities/src/test/java/io/optimism/utilities/derive/stages/SpanBatchTest.java +++ b/hildr-utilities/src/test/java/io/optimism/utilities/derive/stages/SpanBatchTest.java @@ -49,7 +49,9 @@ void testSpanBatchForBatchInterface() throws IOException { SpanBatch spanBatch = SpanBatch.newSpanBatch(singularBatches1); assertEquals(spanBatch.getBatchType(), BatchType.SPAN_BATCH_TYPE); - assertEquals(spanBatch.getTimestamp(), singularBatches1.getFirst().getTimestamp()); + assertEquals( + spanBatch.getTimestamp(BigInteger.ZERO), + singularBatches1.getFirst().getTimestamp(BigInteger.ZERO)); assertEquals(spanBatch.getStartEpochNum(), singularBatches1.getFirst().getEpochNum()); assertTrue(spanBatch.checkOriginHash( From 7d651c9964db0cec3c7f093b374ba893d66ec06c Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Wed, 31 Jan 2024 00:00:09 +0800 Subject: [PATCH 08/11] fix: raw span batch remove IBatch interface --- .../io/optimism/derive/stages/Batches.java | 92 ++++++++----------- .../stages/BatcherTransactionsTest.java | 3 - .../optimism/derive/stages/BatchesTest.java | 23 ++--- .../utilities/derive/stages/Batch.java | 18 +++- .../utilities/derive/stages/IBatch.java | 3 +- .../utilities/derive/stages/RawSpanBatch.java | 13 ++- .../derive/stages/SingularBatch.java | 2 +- .../utilities/derive/stages/SpanBatch.java | 6 +- .../derive/stages/SpanBatchTest.java | 8 +- 9 files changed, 70 insertions(+), 98 deletions(-) diff --git a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java index 66538017..ef5216f7 100644 --- a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java +++ b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java @@ -11,7 +11,6 @@ import io.optimism.utilities.derive.stages.Batch; import io.optimism.utilities.derive.stages.BatchType; import io.optimism.utilities.derive.stages.IBatch; -import io.optimism.utilities.derive.stages.RawSpanBatch; import io.optimism.utilities.derive.stages.SingularBatch; import io.optimism.utilities.derive.stages.SpanBatch; import io.optimism.utilities.derive.stages.SpanBatchElement; @@ -26,6 +25,7 @@ import java.util.zip.DataFormatException; import java.util.zip.Inflater; import org.apache.commons.lang3.ArrayUtils; +import org.apache.tuweni.bytes.Bytes; import org.jctools.queues.atomic.SpscAtomicArrayQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -68,7 +68,7 @@ public Batches(TreeMap batches, I channelIterator, AtomicRefe this.channelIterator = channelIterator; this.state = state; this.config = config; - this.nextSingularBatches = new SpscAtomicArrayQueue<>(1024); + this.nextSingularBatches = new SpscAtomicArrayQueue<>(1024 * 64); } @Override @@ -86,14 +86,8 @@ public Batch next() { } Channel channel = this.channelIterator.next(); if (channel != null) { - decodeBatches(channel) - .forEach(batch -> this.batches.put( - batch.batch() - .getTimestamp(this.config - .chainConfig() - .l2Genesis() - .timestamp()), - batch)); + decodeBatches(this.config.chainConfig(), channel) + .forEach(batch -> this.batches.put(batch.batch().getTimestamp(), batch)); } Batch derivedBatch = null; @@ -101,16 +95,14 @@ public Batch next() { while (true) { if (this.batches.firstEntry() != null) { Batch batch = this.batches.firstEntry().getValue(); - BigInteger l1GenesisTimestamp = - this.config.chainConfig().l2Genesis().timestamp(); switch (batchStatus(batch)) { case Accept: derivedBatch = batch; - this.batches.remove(batch.timestamp(l1GenesisTimestamp)); + this.batches.remove(batch.timestamp()); break loop; case Drop: LOGGER.warn("dropping invalid batch"); - this.batches.remove(batch.timestamp(l1GenesisTimestamp)); + this.batches.remove(batch.timestamp()); continue; case Future, Undecided: break loop; @@ -158,7 +150,7 @@ public Batch next() { * @param channel the channel * @return the list */ - public static List decodeBatches(Channel channel) { + public static List decodeBatches(final Config.ChainConfig chainConfig, final Channel channel) { byte[] channelData = decompressZlib(channel.data()); List batches = RlpDecoder.decode(channelData).getValues(); return batches.stream() @@ -168,7 +160,12 @@ public static List decodeBatches(Channel channel) { byte[] batchData = ArrayUtils.subarray(buffer, 1, buffer.length); if (BatchType.SPAN_BATCH_TYPE.getCode() == ((int) batchType)) { - return Batch.decodeRawSpanBatch(batchData, channel.l1InclusionBlock()); + return Batch.decodeRawSpanBatch( + batchData, + chainConfig.blockTime(), + chainConfig.l2Genesis().timestamp(), + chainConfig.l2ChainId(), + channel.l1InclusionBlock()); } else if (BatchType.SINGULAR_BATCH_TYPE.getCode() == ((int) batchType)) { RlpList rlpBatchData = (RlpList) RlpDecoder.decode(batchData).getValues().getFirst(); @@ -204,7 +201,7 @@ private static byte[] decompressZlib(byte[] data) { private BatchStatus batchStatus(final Batch batch) { if (batch.batch() instanceof SingularBatch) { return singularBatchStatus(batch); - } else if (batch.batch() instanceof RawSpanBatch) { + } else if (batch.batch() instanceof SpanBatch) { return spanBatchStatus(batch); } else { throw new IllegalStateException("unknown batch type"); @@ -221,8 +218,7 @@ private BatchStatus singularBatchStatus(final Batch batchWrapper) { head.timestamp().add(this.config.chainConfig().blockTime()); // check timestamp range - switch (batch.getTimestamp(this.config.chainConfig().l2Genesis().timestamp()) - .compareTo(nextTimestamp)) { + switch (batch.getTimestamp().compareTo(nextTimestamp)) { case 1 -> { return BatchStatus.Future; } @@ -304,11 +300,7 @@ private BatchStatus singularBatchStatus(final Batch batchWrapper) { } private BatchStatus spanBatchStatus(final Batch batchWrapper) { - final RawSpanBatch rawSpanBatch = (RawSpanBatch) batchWrapper.batch(); - final SpanBatch spanBatch = rawSpanBatch.toSpanBatch( - this.config.chainConfig().blockTime(), - this.config.chainConfig().l2Genesis().timestamp(), - this.config.chainConfig().l2ChainId()); + final SpanBatch spanBatch = (SpanBatch) batchWrapper.batch(); final State state = this.state.get(); final Epoch epoch = state.getSafeEpoch(); final Epoch nextEpoch = state.epoch(epoch.number().add(BigInteger.ONE)); @@ -316,22 +308,11 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { final BigInteger nextTimestamp = l2SafeHead.timestamp().add(this.config.chainConfig().blockTime()); - BigInteger originBits = rawSpanBatch.spanbatchPayload().originBits(); + final BigInteger startEpochNum = spanBatch.getStartEpochNum(); + final BigInteger endEpochNum = spanBatch.getBlockEpochNum(spanBatch.getBlockCount() - 1); - final BigInteger startEpochNum = rawSpanBatch - .spanbatchPrefix() - .l1OriginNum() - .subtract(BigInteger.valueOf(originBits.bitCount())) - .add(originBits.testBit(0) ? BigInteger.ONE : BigInteger.ZERO); - final BigInteger endEpochNum = rawSpanBatch.spanbatchPrefix().l1OriginNum(); - - final BigInteger spanStartTimestamp = rawSpanBatch - .spanbatchPrefix() - .relTimestamp() - .add(this.config.chainConfig().l2Genesis().timestamp()); - final BigInteger spanEndTimestamp = spanStartTimestamp.add( - BigInteger.valueOf(rawSpanBatch.spanbatchPayload().blockCount()) - .multiply(this.config.chainConfig().blockTime())); + final BigInteger spanStartTimestamp = spanBatch.getTimestamp(); + final BigInteger spanEndTimestamp = spanBatch.getBlockTimestamp(spanBatch.getBlockCount() - 1); // check batch timestamp if (spanEndTimestamp.compareTo(nextTimestamp) < 0) { @@ -366,11 +347,10 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { final var prevL2Block = prevL2Info.component1(); final var prevL2Epoch = prevL2Info.component2(); - // check that block builds on existing chain - final String spanBatchParentCheck = - rawSpanBatch.spanbatchPrefix().parentCheck().toHexString(); - if (!spanBatchParentCheck.equalsIgnoreCase(prevL2Block.hash().substring(0, 42))) { + // check that block builds on existing chain + final String spanBatchParentCheck = spanBatch.getParentCheck().toHexString(); + if (!spanBatch.checkParentHash(Bytes.fromHexString(prevL2Block.hash()))) { LOGGER.warn( "batch parent check failed: batchParent={}; prevL2BlockHash={}", spanBatchParentCheck, @@ -398,10 +378,9 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { LOGGER.warn("l1 origin not found"); return BatchStatus.Drop; } - final String l1OriginCheck = - rawSpanBatch.spanbatchPrefix().l1OriginCheck().toHexString(); - if (!l1OriginCheck.equalsIgnoreCase(l1Origin.hash().substring(0, 42))) { - LOGGER.warn("l1 origin check failed"); + final String l1OriginCheck = spanBatch.getL1OriginCheck().toHexString(); + if (!spanBatch.checkOriginHash(Bytes.fromHexString(l1Origin.hash()))) { + LOGGER.warn("l1 origin check failed: l1OriginCheck={}; l1Origin={}", l1OriginCheck, l1Origin.hash()); return BatchStatus.Drop; } @@ -411,7 +390,7 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { } // check sequencer drift - final int blockCount = (int) rawSpanBatch.spanbatchPayload().blockCount(); + final int blockCount = spanBatch.getBlockCount(); for (int i = 0; i < blockCount; i++) { final var blockTimestamp = spanBatch.getBlockTimestamp(i); if (blockTimestamp.compareTo(l2SafeHead.timestamp()) <= 0) { @@ -438,7 +417,14 @@ private BatchStatus spanBatchStatus(final Batch batchWrapper) { max)); return BatchStatus.Drop; } - if (!rawSpanBatch.spanbatchPayload().originBits().testBit(i)) { + boolean originAdvanced; + if (i == 0) { + originAdvanced = startEpochNum.compareTo(l2SafeHead.number().add(BigInteger.ONE)) == 0; + } else { + originAdvanced = spanBatch.getBlockEpochNum(i).compareTo(spanBatch.getBlockEpochNum(i - 1)) > 0; + } + + if (!originAdvanced) { var batchNextEpoch = state.l1Info(l1OriginNum.add(BigInteger.ONE)); if (batchNextEpoch != null) { if (blockTimestamp.compareTo(batchNextEpoch.blockInfo().timestamp()) >= 0) { @@ -488,12 +474,8 @@ public List getSingularBatches(final IBatch batch, final State state) { Function f = singularBatch -> new Batch(singularBatch, state.getCurrentEpochNum()); if (batch instanceof SingularBatch typedBatch) { return List.of(f.apply(typedBatch)); - } else if (batch instanceof RawSpanBatch typedBatch) { - SpanBatch spanBatch = typedBatch.toSpanBatch( - this.config.chainConfig().blockTime(), - this.config.chainConfig().l2Genesis().timestamp(), - this.config.chainConfig().l2ChainId()); - return this.toSingularBatches(spanBatch, state).stream().map(f).collect(Collectors.toList()); + } else if (batch instanceof SpanBatch typedBatch) { + return this.toSingularBatches(typedBatch, state).stream().map(f).collect(Collectors.toList()); } else { throw new IllegalStateException("unknown batch type"); } diff --git a/hildr-node/src/test/java/io/optimism/derive/stages/BatcherTransactionsTest.java b/hildr-node/src/test/java/io/optimism/derive/stages/BatcherTransactionsTest.java index 9a7e2b20..e664f6f6 100644 --- a/hildr-node/src/test/java/io/optimism/derive/stages/BatcherTransactionsTest.java +++ b/hildr-node/src/test/java/io/optimism/derive/stages/BatcherTransactionsTest.java @@ -106,9 +106,6 @@ class BatcherTransactionsTest { + "4c665ca197cebff1c90e5484cc8a6cb2c5b1badab35aefa35c1384f0bb6459061ad574c2f" + "37f8bbbd2e8dff5f27f020000ffff8db4683801"; - private static final String BATCHER_TX_DATA = - "00656531d7fca1ad32740ea3adca85922a0000000005dc78dadac9f58b71c9d7edacb77bd6323dd823c8ffeb44c059dee7ffb405f9b68b2feb9a3ef3508cc78be9f9edab1ea8557c09e3b1e83cffc05f2a8445c09141c08145c0914580010e181930012332c588a68c114323238c603cffb8e3e20ecb8f4f0d365a15b4ffe09abf6ddad1b7755a79ac67ff39b7bb9ddf3c67ab929e46cd439bf56c7757a8f67dddd968dbf1fc647b4498f6929c0b75a5f2d5557d491b6293a37343b33f681e2c37ae551763b8fc8c598271c67aed7426ff8e2dd7170a31ffbdfce97bb5d9ed0b1dfb94efcb6eb5efdb1bfb7152f8c4b9ae321c5b73af7f12517f3ec15e6effd5f0ddae251cd7673eb65b5d26a1b1e5e68e4b328587b5e6dd56717fb93d6cb3d5ea07b7ffdc0c0af2f86ab8485c73cd3fef280316fe282d96b4be42fd9df28d562c77edecef9c923fe9f6a069a346c1b7b33e9cc76c3e46dc4bacfc191cd3c8afcbc12e52eeaa7c9127ed6412c70ebee6b52dbc825971322c5eaea9adfb6673a54fddf37696757ff4aafa433f6da3531b23988abba61d3ba7beeecbb40db56935f1e7661d3812798fb95131b69eefe68f25fbf7ee7dd870517a79b4cecf0bb73ac439d5a7b7942c3cdef156ac284f31467ba5e0b39a4d8f569c303bba2c52e1b8f98c0ce91d4a96b33ffcaa985c94b2c06ec781a0c9e9d3bc2670ef1429e09b782fb323d9692607dbe9a30589dbbb6e479efbbe72d62af9f038b605f38ced7d32266f751189ff6a68f2d4b63d94c5f88cf575f7cfbbc3e3fae64b5cdc7d4cadf8ebc24bb2894b657e733d78fb3e6d47dca4bdfc1d264c9d2562dfaff4396cb83cfd94c2dc7766cbd3d218fde61f12e6b9767ed36dc625138d6778f7187a28075597196a6d522f9ac9b8e60a77dc094daf395ec7175c0f63f1326a5f257762b172c517dfbdf6ce7ed7f518129fac14fa77d84140d9e2f92791a34b7e3d7f27a4e82c7c66fbf38589266a16d3a2db4eba4e0d7b646e98fdbdea9af4e3a7739a0acb5c53f65c70c24ca002361a978eee8e5a59adbce3c786730719839d1fce3e894d8c12bdc48a31fd64126c68e6777268e677cedbc9c4a2bf26538a011f60725ecb801f24e097665c40403fe7fefa0f719efb64a6f1b7ca591d5aaa36bfece6cb15dfc37ea65d6cf37fd3b971b6848de6dc1bd7debe378909b2bdd6afc061fd29fa6e59a3935dea85d34213658e093f3a776abee3b523ab2eb933771ee2f0718c8d55ce0fff7e4b4a3395fba9bd8949656292c2a18d5cb97dcfcfccaeba72f6d59b2f824df5f5ca6eff5f1db96e57b14fe370a9b0cca7aeca4e7d4b5b33a9b06496a936455325669e8b489e2c1e5bf5e55666cf0b57070f7585cf35d922eaf6a57f4d583f2e8d8e6cbf31b7f1d3c9d432b377166db5f61bf7695b6ed67cc4f2e58bc4d1a7b39fe79e63f1582adbac7831454fc322c952de71f9d463ff73b86ec5bcd0e5519176645bc29572fa7df1cf49d3df24ea2e10d00b9f1fdd2c3c4b32d0f3e8a6355bf57708142c6ae3e8e0ff97ae2fe0e9f1a09b5b488140f8317dbed5ba6f8acc3e09bb0299aae517394dea2eb96419548530587fbffde1a7c734b7a625d2193a179630bf3634942998f4517fd6c71b0155779c7f7ff9686daf705934ed00d38f9dedfc5a8b58ba2f30b44466e88308831f3b96186d67c845b6e8de5a7488c75550f328040d84141c60faf181bb59e0e45710def1242c523632b128a984814ae088bb4a55457efea747cf9ec61a2a7aaf7f74cc600b012d5c145a49483f37162f2715270f772f6f6ac097342f74698aa7dafab9714c563029fcc0c0a1f6dbc1049769bc0fb66d5e9ec230104933a9b8b86058c7d3ab866681ea0b4b362847edd3ecff7e22df3661dd5a9eb50c6c4e57171c5c67bebef4ec9e87d33bb9773f9e9f701a49a9492dd781dfb5075a6f58cfdb32d3edd0546dbd035167b8c4266d0c083cb22f5479fa8f6eae66c12d293b5a18577c48fd3355d363bdd5ef7cb6acc5fb7630cf3feda55f5678d57b87f786794f055d8eb1c5d23a8c7e08c91cf439e4237bd867c71da69d779876dd61dab794e5e73ef6090bf9272ce46f5fca3161217fcb69c923b7246ecc976407000000ffff01"; - /** Test decode tx. */ @Test @DisplayName("test decode tx.") diff --git a/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java b/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java index 4cfea0fb..297b15c0 100644 --- a/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java +++ b/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java @@ -7,7 +7,6 @@ import io.optimism.derive.stages.Channels.Channel; import io.optimism.utilities.derive.stages.Batch; import io.optimism.utilities.derive.stages.Frame; -import io.optimism.utilities.derive.stages.RawSpanBatch; import io.optimism.utilities.derive.stages.SingularBatch; import io.optimism.utilities.derive.stages.SpanBatch; import java.math.BigInteger; @@ -134,7 +133,7 @@ void decodeBatches() { + "4c665ca197cebff1c90e5484cc8a6cb2c5b1badab35aefa35c1384f0bb64" + "59061ad574c2f37f8bbbd2e8dff5f27f020000ffff8db46838"; Channel channel = new Channel(BigInteger.ONE, Hex.decode(data), BigInteger.ONE); - List batches = Batches.decodeBatches(channel); + List batches = Batches.decodeBatches(Config.ChainConfig.optimismSepolia(), channel); assertEquals(6, batches.size()); assertEquals( @@ -167,22 +166,20 @@ void testDecodeSpanBatch() { assertArrayEquals(channel.data(), parseChannel.data()); - List batches = Batches.decodeBatches(channel); + final Config.ChainConfig chainConfig = Config.ChainConfig.optimismSepolia(); + List batches = Batches.decodeBatches(chainConfig, channel); assertEquals(1, batches.size()); - final Config.ChainConfig chainConfig = Config.ChainConfig.optimismSepolia(); - final var batch = (RawSpanBatch) batches.get(0).batch(); + final var batch = (SpanBatch) batches.get(0).batch(); - final SpanBatch spanBatch = batch.toSpanBatch( - chainConfig.blockTime(), chainConfig.l2Genesis().timestamp(), chainConfig.l2ChainId()); - long blockTxCountsSum = spanBatch.getBatches().stream() + long blockTxCountsSum = batch.getBatches().stream() .mapToLong(e -> e.transactions().size()) .sum(); assertEquals(9, blockTxCountsSum); assertEquals(BigInteger.ZERO, batches.get(0).l1InclusionBlock()); - spanBatch.getBatches().forEach(element -> { + batch.getBatches().forEach(element -> { BigInteger unusedBlockNum = element.timestamp() .subtract(chainConfig.l2Genesis().timestamp()) .divide(BigInteger.TWO); @@ -196,12 +193,4 @@ void testDecodeSpanBatch() { }); }); } - - @Test - void testSub() { - String s1 = "0xe0bc110ffac850cd0de7fe2b110eb717a68a9799"; - String s2 = "0xe0bc110ffac850cd0de7fe2b110eb717a68a9799797fd99cd89bf1b155a7aac2"; - String s3 = s2.substring(0, 42); - assertEquals(s1, s3); - } } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java index 32bbd636..89f43a7b 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java @@ -18,11 +18,10 @@ public record Batch(IBatch batch, BigInteger l1InclusionBlock) { /** * Gets timestamp. * - * @param l2genesisTimestamp L2 genesis timestamp * @return the timestamp */ - public BigInteger timestamp(BigInteger l2genesisTimestamp) { - return batch.getTimestamp(l2genesisTimestamp); + public BigInteger timestamp() { + return batch.getTimestamp(); } /** @@ -59,12 +58,21 @@ public static Batch decodeSingularBatch(final RlpList rlp, final BigInteger l1In * Decode span batch. * * @param buf the span batch encoded bytes + * @param blockTime the block time + * @param l2genesisTimestamp L2 genesis timestamp + * @param l2ChainId the L2 chain id * @param l1InclusionBlock L1 inclusion block * @return the batch */ - public static Batch decodeRawSpanBatch(final byte[] buf, final BigInteger l1InclusionBlock) { + public static Batch decodeRawSpanBatch( + final byte[] buf, + final BigInteger blockTime, + final BigInteger l2genesisTimestamp, + final BigInteger l2ChainId, + final BigInteger l1InclusionBlock) { final RawSpanBatch rawSpanBatch = new RawSpanBatch(); rawSpanBatch.decode(Unpooled.wrappedBuffer(buf)); - return new Batch(rawSpanBatch, l1InclusionBlock); + final SpanBatch spanBatch = rawSpanBatch.toSpanBatch(blockTime, l2genesisTimestamp, l2ChainId); + return new Batch(spanBatch, l1InclusionBlock); } } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java index dc838d62..05e7c93b 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/IBatch.java @@ -22,8 +22,7 @@ public interface IBatch { /** * Gets timestamp. * - * @param l2genesisTimestamp L2 genesis timestamp * @return the timestamp */ - BigInteger getTimestamp(BigInteger l2genesisTimestamp); + BigInteger getTimestamp(); } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java index 0c361050..d6adc327 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java @@ -13,7 +13,7 @@ * @author grapebaba * @since 0.2.4 */ -public class RawSpanBatch implements IBatch { +public class RawSpanBatch { private SpanBatchPrefix spanbatchPrefix; private SpanBatchPayload spanbatchPayload; @@ -90,12 +90,11 @@ public String toString() { return "RawSpanBatch[spanbatchPrefix=%s, spanbatchPayload=%s]".formatted(spanbatchPrefix, spanbatchPayload); } - @Override - public BatchType getBatchType() { - return BatchType.SPAN_BATCH_TYPE; - } - - @Override + /** + * Gets span batch timestamp + * @param l2genesisTimestamp l2 genesis timestamp + * @return the span batch timestamp + */ public BigInteger getTimestamp(BigInteger l2genesisTimestamp) { return spanbatchPrefix.relTimestamp().add(l2genesisTimestamp); } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SingularBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SingularBatch.java index 94dff075..bfaaf893 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SingularBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SingularBatch.java @@ -98,7 +98,7 @@ public BatchType getBatchType() { } @Override - public BigInteger getTimestamp(BigInteger l2genesisTimestamp) { + public BigInteger getTimestamp() { return timestamp(); } diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java index 285c3792..1e1e7d17 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java @@ -99,7 +99,7 @@ public BatchType getBatchType() { } @Override - public BigInteger getTimestamp(BigInteger l2genesisTimestamp) { + public BigInteger getTimestamp() { return batches.getFirst().timestamp(); } @@ -119,7 +119,7 @@ public BigInteger getStartEpochNum() { * @return boolean. boolean */ public boolean checkOriginHash(Bytes hash) { - return this.l1OriginCheck.equals(hash); + return this.l1OriginCheck.equals(hash.slice(0, this.l1OriginCheck.size())); } /** @@ -129,7 +129,7 @@ public boolean checkOriginHash(Bytes hash) { * @return boolean. boolean */ public boolean checkParentHash(Bytes hash) { - return this.parentCheck.equals(hash); + return this.parentCheck.equals(hash.slice(0, this.parentCheck.size())); } /** diff --git a/hildr-utilities/src/test/java/io/optimism/utilities/derive/stages/SpanBatchTest.java b/hildr-utilities/src/test/java/io/optimism/utilities/derive/stages/SpanBatchTest.java index 5036adc0..717cb1ab 100644 --- a/hildr-utilities/src/test/java/io/optimism/utilities/derive/stages/SpanBatchTest.java +++ b/hildr-utilities/src/test/java/io/optimism/utilities/derive/stages/SpanBatchTest.java @@ -49,15 +49,13 @@ void testSpanBatchForBatchInterface() throws IOException { SpanBatch spanBatch = SpanBatch.newSpanBatch(singularBatches1); assertEquals(spanBatch.getBatchType(), BatchType.SPAN_BATCH_TYPE); - assertEquals( - spanBatch.getTimestamp(BigInteger.ZERO), - singularBatches1.getFirst().getTimestamp(BigInteger.ZERO)); + assertEquals(spanBatch.getTimestamp(), singularBatches1.getFirst().getTimestamp()); assertEquals(spanBatch.getStartEpochNum(), singularBatches1.getFirst().getEpochNum()); assertTrue(spanBatch.checkOriginHash( - Bytes.fromHexString(singularBatches1.getLast().epochHash().substring(0, 40)))); + Bytes.fromHexString(singularBatches1.getLast().epochHash()))); assertTrue(spanBatch.checkParentHash( - Bytes.fromHexString(singularBatches1.getFirst().parentHash().substring(0, 40)))); + Bytes.fromHexString(singularBatches1.getFirst().parentHash()))); } /** From 25cfd824bcca8301e6fd2a0ea1ed25040884b7b1 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Wed, 31 Jan 2024 11:59:45 +0800 Subject: [PATCH 09/11] fix: raw span batch remove IBatch interface --- .../io/optimism/derive/stages/Batches.java | 2 +- .../optimism/derive/stages/BatchesTest.java | 19 +------------ .../optimism/derive/stages/ChannelsTest.java | 27 +++++++++++++++++++ .../utilities/derive/stages/Batch.java | 10 +++---- .../utilities/derive/stages/RawSpanBatch.java | 9 ------- .../utilities/derive/stages/SpanBatch.java | 9 +++---- 6 files changed, 36 insertions(+), 40 deletions(-) diff --git a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java index ef5216f7..7a81a46e 100644 --- a/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java +++ b/hildr-node/src/main/java/io/optimism/derive/stages/Batches.java @@ -160,7 +160,7 @@ public static List decodeBatches(final Config.ChainConfig chainConfig, fi byte[] batchData = ArrayUtils.subarray(buffer, 1, buffer.length); if (BatchType.SPAN_BATCH_TYPE.getCode() == ((int) batchType)) { - return Batch.decodeRawSpanBatch( + return Batch.decodeSpanBatch( batchData, chainConfig.blockTime(), chainConfig.l2Genesis().timestamp(), diff --git a/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java b/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java index 297b15c0..c766def4 100644 --- a/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java +++ b/hildr-node/src/test/java/io/optimism/derive/stages/BatchesTest.java @@ -1,12 +1,10 @@ package io.optimism.derive.stages; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import io.optimism.config.Config; import io.optimism.derive.stages.Channels.Channel; import io.optimism.utilities.derive.stages.Batch; -import io.optimism.utilities.derive.stages.Frame; import io.optimism.utilities.derive.stages.SingularBatch; import io.optimism.utilities.derive.stages.SpanBatch; import java.math.BigInteger; @@ -147,26 +145,11 @@ void decodeBatches() { @Test @DisplayName("Test decode span batches successfully") void testDecodeSpanBatch() { - String data = - "00656531d7fca1ad32740ea3adca85922a0000000005dc78dadac9f58b71c9d7edacb77bd6323dd823c8ffeb44c059dee7ffb405f9b68b2feb9a3ef3508cc78be9f9edab1ea8557c09e3b1e83cffc05f2a8445c09141c08145c0914580010e181930012332c588a68c114323238c603cffb8e3e20ecb8f4f0d365a15b4ffe09abf6ddad1b7755a79ac67ff39b7bb9ddf3c67ab929e46cd439bf56c7757a8f67dddd968dbf1fc647b4498f6929c0b75a5f2d5557d491b6293a37343b33f681e2c37ae551763b8fc8c598271c67aed7426ff8e2dd7170a31ffbdfce97bb5d9ed0b1dfb94efcb6eb5efdb1bfb7152f8c4b9ae321c5b73af7f12517f3ec15e6effd5f0ddae251cd7673eb65b5d26a1b1e5e68e4b328587b5e6dd56717fb93d6cb3d5ea07b7ffdc0c0af2f86ab8485c73cd3fef280316fe282d96b4be42fd9df28d562c77edecef9c923fe9f6a069a346c1b7b33e9cc76c3e46dc4bacfc191cd3c8afcbc12e52eeaa7c9127ed6412c70ebee6b52dbc825971322c5eaea9adfb6673a54fddf37696757ff4aafa433f6da3531b23988abba61d3ba7beeecbb40db56935f1e7661d3812798fb95131b69eefe68f25fbf7ee7dd870517a79b4cecf0bb73ac439d5a7b7942c3cdef156ac284f31467ba5e0b39a4d8f569c303bba2c52e1b8f98c0ce91d4a96b33ffcaa985c94b2c06ec781a0c9e9d3bc2670ef1429e09b782fb323d9692607dbe9a30589dbbb6e479efbbe72d62af9f038b605f38ced7d32266f751189ff6a68f2d4b63d94c5f88cf575f7cfbbc3e3fae64b5cdc7d4cadf8ebc24bb2894b657e733d78fb3e6d47dca4bdfc1d264c9d2562dfaff4396cb83cfd94c2dc7766cbd3d218fde61f12e6b9767ed36dc625138d6778f7187a28075597196a6d522f9ac9b8e60a77dc094daf395ec7175c0f63f1326a5f257762b172c517dfbdf6ce7ed7f518129fac14fa77d84140d9e2f92791a34b7e3d7f27a4e82c7c66fbf38589266a16d3a2db4eba4e0d7b646e98fdbdea9af4e3a7739a0acb5c53f65c70c24ca002361a978eee8e5a59adbce3c786730719839d1fce3e894d8c12bdc48a31fd64126c68e6777268e677cedbc9c4a2bf26538a011f60725ecb801f24e097665c40403fe7fefa0f719efb64a6f1b7ca591d5aaa36bfece6cb15dfc37ea65d6cf37fd3b971b6848de6dc1bd7debe378909b2bdd6afc061fd29fa6e59a3935dea85d34213658e093f3a776abee3b523ab2eb933771ee2f0718c8d55ce0fff7e4b4a3395fba9bd8949656292c2a18d5cb97dcfcfccaeba72f6d59b2f824df5f5ca6eff5f1db96e57b14fe370a9b0cca7aeca4e7d4b5b33a9b06496a936455325669e8b489e2c1e5bf5e55666cf0b57070f7585cf35d922eaf6a57f4d583f2e8d8e6cbf31b7f1d3c9d432b377166db5f61bf7695b6ed67cc4f2e58bc4d1a7b39fe79e63f1582adbac7831454fc322c952de71f9d463ff73b86ec5bcd0e5519176645bc29572fa7df1cf49d3df24ea2e10d00b9f1fdd2c3c4b32d0f3e8a6355bf57708142c6ae3e8e0ff97ae2fe0e9f1a09b5b488140f8317dbed5ba6f8acc3e09bb0299aae517394dea2eb96419548530587fbffde1a7c734b7a625d2193a179630bf3634942998f4517fd6c71b0155779c7f7ff9686daf705934ed00d38f9dedfc5a8b58ba2f30b44466e88308831f3b96186d67c845b6e8de5a7488c75550f328040d84141c60faf181bb59e0e45710def1242c523632b128a984814ae088bb4a55457efea747cf9ec61a2a7aaf7f74cc600b012d5c145a49483f37162f2715270f772f6f6ac097342f74698aa7dafab9714c563029fcc0c0a1f6dbc1049769bc0fb66d5e9ec230104933a9b8b86058c7d3ab866681ea0b4b362847edd3ecff7e22df3661dd5a9eb50c6c4e57171c5c67bebef4ec9e87d33bb9773f9e9f701a49a9492dd781dfb5075a6f58cfdb32d3edd0546dbd035167b8c4266d0c083cb22f5479fa8f6eae66c12d293b5a18577c48fd3355d363bdd5ef7cb6acc5fb7630cf3feda55f5678d57b87f786794f055d8eb1c5d23a8c7e08c91cf439e4237bd867c71da69d779876dd61dab794e5e73ef6090bf9272ce46f5fca3161217fcb69c923b7246ecc976407000000ffff01"; - byte[] dataBytes = Numeric.hexStringToByteArray(data); - BatcherTransactions.BatcherTransaction tx = - BatcherTransactions.BatcherTransaction.create(dataBytes, BigInteger.valueOf(10254359L)); - Channels.PendingChannel pendingChannel = - Channels.PendingChannel.create(tx.frames().get(0)); - List frames = tx.frames(); - for (int i = 1; i < frames.size(); i++) { - pendingChannel.pushFrame(frames.get(i)); - } - Channel parseChannel = Channel.from(pendingChannel); + final Config.ChainConfig chainConfig = Config.ChainConfig.optimismSepolia(); String channelData = "78dadac9f58b71c9d7edacb77bd6323dd823c8ffeb44c059dee7ffb405f9b68b2feb9a3ef3508cc78be9f9edab1ea8557c09e3b1e83cffc05f2a8445c09141c08145c0914580010e181930012332c588a68c114323238c603cffb8e3e20ecb8f4f0d365a15b4ffe09abf6ddad1b7755a79ac67ff39b7bb9ddf3c67ab929e46cd439bf56c7757a8f67dddd968dbf1fc647b4498f6929c0b75a5f2d5557d491b6293a37343b33f681e2c37ae551763b8fc8c598271c67aed7426ff8e2dd7170a31ffbdfce97bb5d9ed0b1dfb94efcb6eb5efdb1bfb7152f8c4b9ae321c5b73af7f12517f3ec15e6effd5f0ddae251cd7673eb65b5d26a1b1e5e68e4b328587b5e6dd56717fb93d6cb3d5ea07b7ffdc0c0af2f86ab8485c73cd3fef280316fe282d96b4be42fd9df28d562c77edecef9c923fe9f6a069a346c1b7b33e9cc76c3e46dc4bacfc191cd3c8afcbc12e52eeaa7c9127ed6412c70ebee6b52dbc825971322c5eaea9adfb6673a54fddf37696757ff4aafa433f6da3531b23988abba61d3ba7beeecbb40db56935f1e7661d3812798fb95131b69eefe68f25fbf7ee7dd870517a79b4cecf0bb73ac439d5a7b7942c3cdef156ac284f31467ba5e0b39a4d8f569c303bba2c52e1b8f98c0ce91d4a96b33ffcaa985c94b2c06ec781a0c9e9d3bc2670ef1429e09b782fb323d9692607dbe9a30589dbbb6e479efbbe72d62af9f038b605f38ced7d32266f751189ff6a68f2d4b63d94c5f88cf575f7cfbbc3e3fae64b5cdc7d4cadf8ebc24bb2894b657e733d78fb3e6d47dca4bdfc1d264c9d2562dfaff4396cb83cfd94c2dc7766cbd3d218fde61f12e6b9767ed36dc625138d6778f7187a28075597196a6d522f9ac9b8e60a77dc094daf395ec7175c0f63f1326a5f257762b172c517dfbdf6ce7ed7f518129fac14fa77d84140d9e2f92791a34b7e3d7f27a4e82c7c66fbf38589266a16d3a2db4eba4e0d7b646e98fdbdea9af4e3a7739a0acb5c53f65c70c24ca002361a978eee8e5a59adbce3c786730719839d1fce3e894d8c12bdc48a31fd64126c68e6777268e677cedbc9c4a2bf26538a011f60725ecb801f24e097665c40403fe7fefa0f719efb64a6f1b7ca591d5aaa36bfece6cb15dfc37ea65d6cf37fd3b971b6848de6dc1bd7debe378909b2bdd6afc061fd29fa6e59a3935dea85d34213658e093f3a776abee3b523ab2eb933771ee2f0718c8d55ce0fff7e4b4a3395fba9bd8949656292c2a18d5cb97dcfcfccaeba72f6d59b2f824df5f5ca6eff5f1db96e57b14fe370a9b0cca7aeca4e7d4b5b33a9b06496a936455325669e8b489e2c1e5bf5e55666cf0b57070f7585cf35d922eaf6a57f4d583f2e8d8e6cbf31b7f1d3c9d432b377166db5f61bf7695b6ed67cc4f2e58bc4d1a7b39fe79e63f1582adbac7831454fc322c952de71f9d463ff73b86ec5bcd0e5519176645bc29572fa7df1cf49d3df24ea2e10d00b9f1fdd2c3c4b32d0f3e8a6355bf57708142c6ae3e8e0ff97ae2fe0e9f1a09b5b488140f8317dbed5ba6f8acc3e09bb0299aae517394dea2eb96419548530587fbffde1a7c734b7a625d2193a179630bf3634942998f4517fd6c71b0155779c7f7ff9686daf705934ed00d38f9dedfc5a8b58ba2f30b44466e88308831f3b96186d67c845b6e8de5a7488c75550f328040d84141c60faf181bb59e0e45710def1242c523632b128a984814ae088bb4a55457efea747cf9ec61a2a7aaf7f74cc600b012d5c145a49483f37162f2715270f772f6f6ac097342f74698aa7dafab9714c563029fcc0c0a1f6dbc1049769bc0fb66d5e9ec230104933a9b8b86058c7d3ab866681ea0b4b362847edd3ecff7e22df3661dd5a9eb50c6c4e57171c5c67bebef4ec9e87d33bb9773f9e9f701a49a9492dd781dfb5075a6f58cfdb32d3edd0546dbd035167b8c4266d0c083cb22f5479fa8f6eae66c12d293b5a18577c48fd3355d363bdd5ef7cb6acc5fb7630cf3feda55f5678d57b87f786794f055d8eb1c5d23a8c7e08c91cf439e4237bd867c71da69d779876dd61dab794e5e73ef6090bf9272ce46f5fca3161217fcb69c923b7246ecc976407000000ffff"; Channel channel = new Channel(BigInteger.ONE, Hex.decode(channelData), BigInteger.ZERO); - - assertArrayEquals(channel.data(), parseChannel.data()); - - final Config.ChainConfig chainConfig = Config.ChainConfig.optimismSepolia(); List batches = Batches.decodeBatches(chainConfig, channel); assertEquals(1, batches.size()); diff --git a/hildr-node/src/test/java/io/optimism/derive/stages/ChannelsTest.java b/hildr-node/src/test/java/io/optimism/derive/stages/ChannelsTest.java index 655ea86a..6b7442f0 100644 --- a/hildr-node/src/test/java/io/optimism/derive/stages/ChannelsTest.java +++ b/hildr-node/src/test/java/io/optimism/derive/stages/ChannelsTest.java @@ -1,5 +1,6 @@ package io.optimism.derive.stages; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -10,12 +11,15 @@ import io.optimism.derive.stages.Channels.Channel; import io.optimism.utilities.derive.stages.Frame; import java.math.BigInteger; +import java.util.List; import java.util.Optional; +import org.bouncycastle.util.encoders.Hex; import org.jctools.queues.MessagePassingQueue; import org.jctools.queues.MpscGrowableArrayQueue; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.web3j.tuples.generated.Tuple2; +import org.web3j.utils.Numeric; /** * The type ChannelsTest. @@ -88,6 +92,29 @@ void testReadyChannelStillPending() { assertTrue(channelOpt.isEmpty()); } + @Test + @DisplayName("Test read channel data from batch tx successfully") + void testReadChannelData() { + String data = + "00656531d7fca1ad32740ea3adca85922a0000000005dc78dadac9f58b71c9d7edacb77bd6323dd823c8ffeb44c059dee7ffb405f9b68b2feb9a3ef3508cc78be9f9edab1ea8557c09e3b1e83cffc05f2a8445c09141c08145c0914580010e181930012332c588a68c114323238c603cffb8e3e20ecb8f4f0d365a15b4ffe09abf6ddad1b7755a79ac67ff39b7bb9ddf3c67ab929e46cd439bf56c7757a8f67dddd968dbf1fc647b4498f6929c0b75a5f2d5557d491b6293a37343b33f681e2c37ae551763b8fc8c598271c67aed7426ff8e2dd7170a31ffbdfce97bb5d9ed0b1dfb94efcb6eb5efdb1bfb7152f8c4b9ae321c5b73af7f12517f3ec15e6effd5f0ddae251cd7673eb65b5d26a1b1e5e68e4b328587b5e6dd56717fb93d6cb3d5ea07b7ffdc0c0af2f86ab8485c73cd3fef280316fe282d96b4be42fd9df28d562c77edecef9c923fe9f6a069a346c1b7b33e9cc76c3e46dc4bacfc191cd3c8afcbc12e52eeaa7c9127ed6412c70ebee6b52dbc825971322c5eaea9adfb6673a54fddf37696757ff4aafa433f6da3531b23988abba61d3ba7beeecbb40db56935f1e7661d3812798fb95131b69eefe68f25fbf7ee7dd870517a79b4cecf0bb73ac439d5a7b7942c3cdef156ac284f31467ba5e0b39a4d8f569c303bba2c52e1b8f98c0ce91d4a96b33ffcaa985c94b2c06ec781a0c9e9d3bc2670ef1429e09b782fb323d9692607dbe9a30589dbbb6e479efbbe72d62af9f038b605f38ced7d32266f751189ff6a68f2d4b63d94c5f88cf575f7cfbbc3e3fae64b5cdc7d4cadf8ebc24bb2894b657e733d78fb3e6d47dca4bdfc1d264c9d2562dfaff4396cb83cfd94c2dc7766cbd3d218fde61f12e6b9767ed36dc625138d6778f7187a28075597196a6d522f9ac9b8e60a77dc094daf395ec7175c0f63f1326a5f257762b172c517dfbdf6ce7ed7f518129fac14fa77d84140d9e2f92791a34b7e3d7f27a4e82c7c66fbf38589266a16d3a2db4eba4e0d7b646e98fdbdea9af4e3a7739a0acb5c53f65c70c24ca002361a978eee8e5a59adbce3c786730719839d1fce3e894d8c12bdc48a31fd64126c68e6777268e677cedbc9c4a2bf26538a011f60725ecb801f24e097665c40403fe7fefa0f719efb64a6f1b7ca591d5aaa36bfece6cb15dfc37ea65d6cf37fd3b971b6848de6dc1bd7debe378909b2bdd6afc061fd29fa6e59a3935dea85d34213658e093f3a776abee3b523ab2eb933771ee2f0718c8d55ce0fff7e4b4a3395fba9bd8949656292c2a18d5cb97dcfcfccaeba72f6d59b2f824df5f5ca6eff5f1db96e57b14fe370a9b0cca7aeca4e7d4b5b33a9b06496a936455325669e8b489e2c1e5bf5e55666cf0b57070f7585cf35d922eaf6a57f4d583f2e8d8e6cbf31b7f1d3c9d432b377166db5f61bf7695b6ed67cc4f2e58bc4d1a7b39fe79e63f1582adbac7831454fc322c952de71f9d463ff73b86ec5bcd0e5519176645bc29572fa7df1cf49d3df24ea2e10d00b9f1fdd2c3c4b32d0f3e8a6355bf57708142c6ae3e8e0ff97ae2fe0e9f1a09b5b488140f8317dbed5ba6f8acc3e09bb0299aae517394dea2eb96419548530587fbffde1a7c734b7a625d2193a179630bf3634942998f4517fd6c71b0155779c7f7ff9686daf705934ed00d38f9dedfc5a8b58ba2f30b44466e88308831f3b96186d67c845b6e8de5a7488c75550f328040d84141c60faf181bb59e0e45710def1242c523632b128a984814ae088bb4a55457efea747cf9ec61a2a7aaf7f74cc600b012d5c145a49483f37162f2715270f772f6f6ac097342f74698aa7dafab9714c563029fcc0c0a1f6dbc1049769bc0fb66d5e9ec230104933a9b8b86058c7d3ab866681ea0b4b362847edd3ecff7e22df3661dd5a9eb50c6c4e57171c5c67bebef4ec9e87d33bb9773f9e9f701a49a9492dd781dfb5075a6f58cfdb32d3edd0546dbd035167b8c4266d0c083cb22f5479fa8f6eae66c12d293b5a18577c48fd3355d363bdd5ef7cb6acc5fb7630cf3feda55f5678d57b87f786794f055d8eb1c5d23a8c7e08c91cf439e4237bd867c71da69d779876dd61dab794e5e73ef6090bf9272ce46f5fca3161217fcb69c923b7246ecc976407000000ffff01"; + byte[] dataBytes = Numeric.hexStringToByteArray(data); + BatcherTransactions.BatcherTransaction tx = + BatcherTransactions.BatcherTransaction.create(dataBytes, BigInteger.valueOf(10254359L)); + Channels.PendingChannel pendingChannel = + Channels.PendingChannel.create(tx.frames().get(0)); + List frames = tx.frames(); + for (int i = 1; i < frames.size(); i++) { + pendingChannel.pushFrame(frames.get(i)); + } + Channel parseChannel = Channel.from(pendingChannel); + + String channelData = + "78dadac9f58b71c9d7edacb77bd6323dd823c8ffeb44c059dee7ffb405f9b68b2feb9a3ef3508cc78be9f9edab1ea8557c09e3b1e83cffc05f2a8445c09141c08145c0914580010e181930012332c588a68c114323238c603cffb8e3e20ecb8f4f0d365a15b4ffe09abf6ddad1b7755a79ac67ff39b7bb9ddf3c67ab929e46cd439bf56c7757a8f67dddd968dbf1fc647b4498f6929c0b75a5f2d5557d491b6293a37343b33f681e2c37ae551763b8fc8c598271c67aed7426ff8e2dd7170a31ffbdfce97bb5d9ed0b1dfb94efcb6eb5efdb1bfb7152f8c4b9ae321c5b73af7f12517f3ec15e6effd5f0ddae251cd7673eb65b5d26a1b1e5e68e4b328587b5e6dd56717fb93d6cb3d5ea07b7ffdc0c0af2f86ab8485c73cd3fef280316fe282d96b4be42fd9df28d562c77edecef9c923fe9f6a069a346c1b7b33e9cc76c3e46dc4bacfc191cd3c8afcbc12e52eeaa7c9127ed6412c70ebee6b52dbc825971322c5eaea9adfb6673a54fddf37696757ff4aafa433f6da3531b23988abba61d3ba7beeecbb40db56935f1e7661d3812798fb95131b69eefe68f25fbf7ee7dd870517a79b4cecf0bb73ac439d5a7b7942c3cdef156ac284f31467ba5e0b39a4d8f569c303bba2c52e1b8f98c0ce91d4a96b33ffcaa985c94b2c06ec781a0c9e9d3bc2670ef1429e09b782fb323d9692607dbe9a30589dbbb6e479efbbe72d62af9f038b605f38ced7d32266f751189ff6a68f2d4b63d94c5f88cf575f7cfbbc3e3fae64b5cdc7d4cadf8ebc24bb2894b657e733d78fb3e6d47dca4bdfc1d264c9d2562dfaff4396cb83cfd94c2dc7766cbd3d218fde61f12e6b9767ed36dc625138d6778f7187a28075597196a6d522f9ac9b8e60a77dc094daf395ec7175c0f63f1326a5f257762b172c517dfbdf6ce7ed7f518129fac14fa77d84140d9e2f92791a34b7e3d7f27a4e82c7c66fbf38589266a16d3a2db4eba4e0d7b646e98fdbdea9af4e3a7739a0acb5c53f65c70c24ca002361a978eee8e5a59adbce3c786730719839d1fce3e894d8c12bdc48a31fd64126c68e6777268e677cedbc9c4a2bf26538a011f60725ecb801f24e097665c40403fe7fefa0f719efb64a6f1b7ca591d5aaa36bfece6cb15dfc37ea65d6cf37fd3b971b6848de6dc1bd7debe378909b2bdd6afc061fd29fa6e59a3935dea85d34213658e093f3a776abee3b523ab2eb933771ee2f0718c8d55ce0fff7e4b4a3395fba9bd8949656292c2a18d5cb97dcfcfccaeba72f6d59b2f824df5f5ca6eff5f1db96e57b14fe370a9b0cca7aeca4e7d4b5b33a9b06496a936455325669e8b489e2c1e5bf5e55666cf0b57070f7585cf35d922eaf6a57f4d583f2e8d8e6cbf31b7f1d3c9d432b377166db5f61bf7695b6ed67cc4f2e58bc4d1a7b39fe79e63f1582adbac7831454fc322c952de71f9d463ff73b86ec5bcd0e5519176645bc29572fa7df1cf49d3df24ea2e10d00b9f1fdd2c3c4b32d0f3e8a6355bf57708142c6ae3e8e0ff97ae2fe0e9f1a09b5b488140f8317dbed5ba6f8acc3e09bb0299aae517394dea2eb96419548530587fbffde1a7c734b7a625d2193a179630bf3634942998f4517fd6c71b0155779c7f7ff9686daf705934ed00d38f9dedfc5a8b58ba2f30b44466e88308831f3b96186d67c845b6e8de5a7488c75550f328040d84141c60faf181bb59e0e45710def1242c523632b128a984814ae088bb4a55457efea747cf9ec61a2a7aaf7f74cc600b012d5c145a49483f37162f2715270f772f6f6ac097342f74698aa7dafab9714c563029fcc0c0a1f6dbc1049769bc0fb66d5e9ec230104933a9b8b86058c7d3ab866681ea0b4b362847edd3ecff7e22df3661dd5a9eb50c6c4e57171c5c67bebef4ec9e87d33bb9773f9e9f701a49a9492dd781dfb5075a6f58cfdb32d3edd0546dbd035167b8c4266d0c083cb22f5479fa8f6eae66c12d293b5a18577c48fd3355d363bdd5ef7cb6acc5fb7630cf3feda55f5678d57b87f786794f055d8eb1c5d23a8c7e08c91cf439e4237bd867c71da69d779876dd61dab794e5e73ef6090bf9272ce46f5fca3161217fcb69c923b7246ecc976407000000ffff"; + Channel channel = new Channel(BigInteger.ONE, Hex.decode(channelData), BigInteger.ZERO); + + assertArrayEquals(channel.data(), parseChannel.data()); + } + private Tuple2, MessagePassingQueue> createStage() { Config config = new Config("", "", "", "", null, null, 9545, false, ChainConfig.optimismGoerli()); MessagePassingQueue transactionMessageMessagePassingQueue = diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java index 89f43a7b..7ea071fb 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/Batch.java @@ -1,6 +1,5 @@ package io.optimism.utilities.derive.stages; -import com.google.common.primitives.Bytes; import io.netty.buffer.Unpooled; import java.math.BigInteger; import org.web3j.rlp.RlpList; @@ -33,11 +32,8 @@ public byte[] encode() { if (batch instanceof SingularBatch) { var typedBatch = (SingularBatch) batch; return typedBatch.encode(); - } else if (batch instanceof RawSpanBatch) { - var typedBatch = (RawSpanBatch) batch; - return Bytes.concat( - typedBatch.spanbatchPrefix().encode(), - typedBatch.spanbatchPayload().encode()); + } else if (batch instanceof SpanBatch) { + throw new IllegalStateException("unsupport batch type: %s".formatted(batch.getBatchType())); } else { throw new IllegalStateException("unknown batch type"); } @@ -64,7 +60,7 @@ public static Batch decodeSingularBatch(final RlpList rlp, final BigInteger l1In * @param l1InclusionBlock L1 inclusion block * @return the batch */ - public static Batch decodeRawSpanBatch( + public static Batch decodeSpanBatch( final byte[] buf, final BigInteger blockTime, final BigInteger l2genesisTimestamp, diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java index d6adc327..70f3e8ad 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java @@ -90,15 +90,6 @@ public String toString() { return "RawSpanBatch[spanbatchPrefix=%s, spanbatchPayload=%s]".formatted(spanbatchPrefix, spanbatchPayload); } - /** - * Gets span batch timestamp - * @param l2genesisTimestamp l2 genesis timestamp - * @return the span batch timestamp - */ - public BigInteger getTimestamp(BigInteger l2genesisTimestamp) { - return spanbatchPrefix.relTimestamp().add(l2genesisTimestamp); - } - /** * Decode. * diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java index 1e1e7d17..b4427276 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/SpanBatch.java @@ -390,7 +390,7 @@ public static SpanBatch newSpanBatch(List singularBatches) { } /** - * Derive span batch span batch. + * Derive raw span batch to span batch. * * @param batch the batch * @param blockTime the block time @@ -399,9 +399,8 @@ public static SpanBatch newSpanBatch(List singularBatches) { * @return the span batch */ public static SpanBatch deriveSpanBatch( - IBatch batch, BigInteger blockTime, BigInteger genesisTimestamp, BigInteger chainID) { - RawSpanBatch rawSpanBatch = (RawSpanBatch) batch; - return rawSpanBatch.toSpanBatch(blockTime, genesisTimestamp, chainID); + RawSpanBatch batch, BigInteger blockTime, BigInteger genesisTimestamp, BigInteger chainID) { + return batch.toSpanBatch(blockTime, genesisTimestamp, chainID); } /** @@ -433,7 +432,7 @@ public SpanBatchBuilder(BigInteger genesisTimestamp, BigInteger chainID) { * @param singularBatch the singular batch * @param seqNum the seq num */ - public void AppendSingularBatch(SingularBatch singularBatch, BigInteger seqNum) { + public void appendSingularBatch(SingularBatch singularBatch, BigInteger seqNum) { if (this.getBlockCount() == 0) { this.originChangedBit = 0; if (seqNum.compareTo(BigInteger.ZERO) == 0) { From 47b1b27900ef37da81f7c2cf5f445bd93e72df19 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Wed, 31 Jan 2024 12:06:21 +0800 Subject: [PATCH 10/11] feat: encode raw span batch --- .../java/io/optimism/rpc/methods/OutputAtBlock.java | 2 +- .../utilities/derive/stages/RawSpanBatch.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hildr-node/src/main/java/io/optimism/rpc/methods/OutputAtBlock.java b/hildr-node/src/main/java/io/optimism/rpc/methods/OutputAtBlock.java index cd1f2ce0..dcba6a6c 100644 --- a/hildr-node/src/main/java/io/optimism/rpc/methods/OutputAtBlock.java +++ b/hildr-node/src/main/java/io/optimism/rpc/methods/OutputAtBlock.java @@ -86,7 +86,7 @@ public JsonRpcResponse response(JsonRpcRequestContext context) { private String computeL2OutputRoot(EthBlock.Block block, String storageRoot) { var version = new byte[32]; - byte[] digestBytes = null; + byte[] digestBytes = new byte[0]; digestBytes = ArrayUtils.addAll(digestBytes, version); digestBytes = ArrayUtils.addAll(digestBytes, Numeric.hexStringToByteArray(block.getStateRoot())); digestBytes = ArrayUtils.addAll(digestBytes, Numeric.hexStringToByteArray(storageRoot)); diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java index 70f3e8ad..6182144e 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java @@ -5,6 +5,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; + +import org.apache.commons.lang3.ArrayUtils; import org.web3j.utils.Numeric; /** @@ -90,6 +92,15 @@ public String toString() { return "RawSpanBatch[spanbatchPrefix=%s, spanbatchPayload=%s]".formatted(spanbatchPrefix, spanbatchPayload); } + /** + * Encode raw span batch. + * + * @return the encoded raw span batch bytes + */ + public byte[] encode() { + return ArrayUtils.addAll(this.spanbatchPrefix.encode(), this.spanbatchPayload.encode()); + } + /** * Decode. * From 1bd24c5205cc65c6d00da931635886cd7b920ab8 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Wed, 31 Jan 2024 15:03:23 +0800 Subject: [PATCH 11/11] fix: span batch format --- .../java/io/optimism/utilities/derive/stages/RawSpanBatch.java | 1 - 1 file changed, 1 deletion(-) diff --git a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java index 6182144e..959c3a6b 100644 --- a/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java +++ b/hildr-utilities/src/main/java/io/optimism/utilities/derive/stages/RawSpanBatch.java @@ -5,7 +5,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; - import org.apache.commons.lang3.ArrayUtils; import org.web3j.utils.Numeric;