Skip to content

Commit

Permalink
add span-batch
Browse files Browse the repository at this point in the history
  • Loading branch information
zhouop0 committed Dec 27, 2023
1 parent 95b54ac commit 1c1e5a8
Show file tree
Hide file tree
Showing 20 changed files with 1,329 additions and 0 deletions.
13 changes: 13 additions & 0 deletions hildr-utilities/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ repositories {
maven {
url "https://artifacts.consensys.net/public/maven/maven/"
}
maven { url "https://artifacts.consensys.net/public/maven/maven/" }
maven { url "https://jitpack.io" }
google()
}

java {
Expand Down Expand Up @@ -75,11 +78,21 @@ dependencies {

implementation 'ch.qos.logback:logback-core:1.4.7'
implementation 'ch.qos.logback:logback-classic:1.4.7'

implementation 'io.tmio:tuweni-rlp:2.4.2'
implementation 'org.bouncycastle:bcprov-jdk18on:1.76'
implementation 'org.slf4j:slf4j-api:2.0.7'
implementation 'io.libp2p:jvm-libp2p:1.0.1-RELEASE'

testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'

testImplementation 'io.tmio:tuweni-ssz:2.4.2'
testImplementation 'io.tmio:tuweni-units:2.4.2'
testImplementation('io.tmio:tuweni-crypto:2.4.2'){
exclude group: 'org.bouncycastle', module: 'bcprov-jdk15on'
}

errorprone("com.google.errorprone:error_prone_core:2.18.0")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.optimism.utilities.derive.stages;

public enum BatchType {
SINGULAR_BATCH_TYPE(0, "SingularBatchType"),
SPAN_BATCH_TYPE(1, "SpanBatchType");
private final int code;
private final String name;

BatchType(int code, String name) {
this.code = code;
this.name = name;
}

public int getCode() {
return code;
}

public String getName() {
return name;
}

public static BatchType from(int code) {
for (BatchType batchType : BatchType.values()) {
if (batchType.getCode() == code) {
return batchType;
}
}
throw new IllegalArgumentException("Invalid BatchType code: " + code);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.optimism.utilities.derive.stages;

import java.math.BigInteger;

/**
* Batch contains information to build one or multiple L2 blocks.
* Batcher converts L2 blocks into Batch and writes encoded bytes to Channel.
* Derivation pipeline decodes Batch from Channel, and converts to one or multiple payload attributes.
*
* @author zhouop0
* @since 0.1.0
*/
public interface IBatch {

int getBatchType();

BigInteger getTimestamp();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package io.optimism.utilities.derive.stages;

public record RawSpanBatch(SpanBatchPrefix spanbatchPrefix, SpanBatchPayload spanbatchPayload) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.optimism.utilities.derive.stages;

import io.optimism.type.BlockId;
import java.math.BigInteger;
import java.util.List;
import java.util.stream.Collectors;
import org.web3j.rlp.RlpEncoder;
import org.web3j.rlp.RlpList;
import org.web3j.rlp.RlpString;
import org.web3j.rlp.RlpType;

public record SingularBatch(
String parentHash, BigInteger epochNum, String epochHash, BigInteger timestamp, List<String> transactions)
implements IBatch {

public BlockId epoch() {
return new BlockId(epochHash(), epochNum());
}

public byte[] encode() {
List<RlpType> 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)));
}

/**
* Decode batch.
*
* @param rlp the rlp
* @return the batch
*/
public static SingularBatch decode(RlpList rlp) {
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<String> transactions = ((RlpList) rlp.getValues().get(4))
.getValues().stream()
.map(rlpString -> ((RlpString) rlpString).asString())
.collect(Collectors.toList());
return new SingularBatch(parentHash, epochNum, epochHash, timestamp, transactions);
}

@Override
public int getBatchType() {
return BatchType.SINGULAR_BATCH_TYPE.getCode();
}

@Override
public BigInteger getTimestamp() {
return timestamp();
}

public BigInteger getEpochNum() {
return epochNum();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package io.optimism.utilities.derive.stages;

import java.math.BigInteger;
import java.util.List;

/**
* SpanBatch is an implementation of Batch interface,
* containing the input to build a span of L2 blocks in derived form (SpanBatchElement)
*
* @author zhouop0
* @since 0.1.0
*/
public class SpanBatch implements IBatch {

// First 20 bytes of the first block's parent hash
private String parentCheck;
// First 20 bytes of the last block's L1 origin hash
private String l1OriginCheck;
// List of block input in derived form
private List<SpanBatchElement> batches;

public String getParentCheck() {
return parentCheck;
}

public String getL1OriginCheck() {
return l1OriginCheck;
}

public List<SpanBatchElement> getBatches() {
return batches;
}

@Override
public int getBatchType() {
return BatchType.SPAN_BATCH_TYPE.getCode();
}

@Override
public BigInteger getTimestamp() {
return batches.getFirst().timestamp();
}

/**
* GetStartEpochNum returns epoch number(L1 origin block number) of the first block in the span.
*/
public BigInteger getStartEpochNum() {
return this.batches.getFirst().epochNum();
}

/**
* checks if the parentCheck matches the first 20 bytes of given hash, probably the current L2 safe head.
* @param hash the first 20 bytes of given hash.
* @return boolean.
*/
public boolean checkOriginHash(String hash) {
return this.l1OriginCheck.equals(hash);
}

/**
* checks if the parentCheck matches the first 20 bytes of given hash, probably the current L2 safe head.
* @param hash the first 20 bytes of given hash.
* @return boolean.
*/
public boolean checkParentHash(String hash) {
return this.parentCheck.equals(hash);
}

/**
* GetBlockEpochNum
* @param index batches index.
* @return the epoch number(L1 origin block number) of the block at the given index in the span.
*/
public BigInteger getBlockEpochNum(int index) {
return this.batches.get(index).epochNum();
}

/**
* GetBlockTimestamp
* @param index batches index.
* @return the timestamp of the block at the given index in the span.
*/
public BigInteger getBlockTimestamp(int index) {
return this.batches.get(index).timestamp();
}

/**
* GetBlockCount
* @return the number of blocks in the span.
*/
public int getBlockCount() {
return this.batches.size();
}

/**
* AppendSingularBatch appends a SingularBatch into the span batch
* updates l1OriginCheck or parentCheck if needed.
*
* @param singularBatch SingularBatch
*/
public void AppendSingularBatch(SingularBatch singularBatch) {
if (batches.size() == 0) {
this.parentCheck = singularBatch.parentHash().substring(0, 20);
}
this.batches.add(SpanBatchElement.singularBatchToElement(singularBatch)); // add the batch to the list
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.optimism.utilities.derive.stages;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.web3j.crypto.AccessListObject;
import org.web3j.crypto.transaction.type.TransactionType;
import org.web3j.rlp.RlpEncoder;
import org.web3j.rlp.RlpList;
import org.web3j.rlp.RlpString;
import org.web3j.rlp.RlpType;

/**
* EIP-2930.
*
*/
public record SpanBatchAccessListTxData(
BigInteger value, BigInteger gasPrice, String data, List<AccessListObject> accessList)
implements SpanBatchTxData {

@Override
public byte txType() {
return TransactionType.EIP2930.getRlpType();
}

public byte[] encode() {
List<RlpType> rlpList = new ArrayList<>();
for (AccessListObject access : accessList) {
rlpList.add(RlpString.create(access.getAddress()));
rlpList.add(new RlpList(
access.getStorageKeys().stream().map(RlpString::create).collect(Collectors.toList())));
}
return RlpEncoder.encode(new RlpList(
RlpString.create(value()),
RlpString.create(gasPrice()),
RlpString.create(data()),
new RlpList(rlpList)));
}

public static SpanBatchAccessListTxData decode(RlpList rlp) {
BigInteger value = ((RlpString) rlp.getValues().get(0)).asPositiveBigInteger();
BigInteger gasPrice = ((RlpString) rlp.getValues().get(1)).asPositiveBigInteger();
String data = ((RlpString) rlp.getValues().get(2)).asString();
List<AccessListObject> accessObjList = new ArrayList<>();
((RlpList) rlp.getValues().get(3)).getValues().forEach(rlpType -> {
RlpList rlpList = (RlpList) rlpType;
String address = ((RlpString) rlpList.getValues().get(0)).asString();
List<String> storageKeys = ((RlpList) rlpList.getValues().get(1))
.getValues().stream()
.map(stKey -> ((RlpString) stKey).asString())
.collect(Collectors.toList());
accessObjList.add(new AccessListObject(address, storageKeys));
});
return new SpanBatchAccessListTxData(value, gasPrice, data, accessObjList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.optimism.utilities.derive.stages;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.web3j.crypto.AccessListObject;
import org.web3j.crypto.transaction.type.TransactionType;
import org.web3j.rlp.RlpEncoder;
import org.web3j.rlp.RlpList;
import org.web3j.rlp.RlpString;
import org.web3j.rlp.RlpType;

public record SpanBatchDynamicFeeTxData(
BigInteger value, BigInteger gasTipCap, BigInteger gasFeeCap, String data, List<AccessListObject> accessList)
implements SpanBatchTxData {
@Override
public byte txType() {
return TransactionType.EIP1559.getRlpType();
}

public byte[] encode() {
List<RlpType> rlpList = new ArrayList<>();
for (AccessListObject access : accessList) {
rlpList.add(RlpString.create(access.getAddress()));
rlpList.add(new RlpList(
access.getStorageKeys().stream().map(RlpString::create).collect(Collectors.toList())));
}
return RlpEncoder.encode(new RlpList(
RlpString.create(value()),
RlpString.create(gasTipCap()),
RlpString.create(gasFeeCap()),
RlpString.create(data()),
new RlpList(rlpList)));
}

public static SpanBatchDynamicFeeTxData decode(RlpList rlp) {
BigInteger value = ((RlpString) rlp.getValues().get(0)).asPositiveBigInteger();
BigInteger gasTipCap = ((RlpString) rlp.getValues().get(1)).asPositiveBigInteger();
BigInteger gasFeeCap = ((RlpString) rlp.getValues().get(2)).asPositiveBigInteger();
String data = ((RlpString) rlp.getValues().get(2)).asString();
List<AccessListObject> accessObjList = new ArrayList<>();
((RlpList) rlp.getValues().get(3)).getValues().forEach(rlpType -> {
RlpList rlpList = (RlpList) rlpType;
String address = ((RlpString) rlpList.getValues().get(0)).asString();
List<String> storageKeys = ((RlpList) rlpList.getValues().get(1))
.getValues().stream()
.map(stKey -> ((RlpString) stKey).asString())
.collect(Collectors.toList());
accessObjList.add(new AccessListObject(address, storageKeys));
});
return new SpanBatchDynamicFeeTxData(value, gasTipCap, gasFeeCap, data, accessObjList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.optimism.utilities.derive.stages;

import java.math.BigInteger;
import java.util.List;

public record SpanBatchElement(BigInteger epochNum, BigInteger timestamp, List<String> transactions) {

public static SpanBatchElement singularBatchToElement(SingularBatch singularBatch) {
return new SpanBatchElement(singularBatch.epochNum(), singularBatch.timestamp(), singularBatch.transactions());
}
}
Loading

0 comments on commit 1c1e5a8

Please sign in to comment.