Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

1679 blockhash update #1681

Merged
merged 46 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9e03688
updated trace file
lorenzogentile404 Jan 6, 2025
df15c1c
implemented macro perspective
lorenzogentile404 Jan 6, 2025
8ed1bb5
implementated preprocessing perspective
lorenzogentile404 Jan 7, 2025
ebb5159
removed outdated code
lorenzogentile404 Jan 7, 2025
2d98fac
added comment
lorenzogentile404 Jan 7, 2025
ca8df9f
revised draft implementation
lorenzogentile404 Jan 7, 2025
9ec0cce
cleaned code --no-verify
lorenzogentile404 Jan 8, 2025
74e101b
updated blockdata constants for gas limit from linea to ethereum
lorenzogentile404 Jan 8, 2025
4646563
solved java issues emerging when running BlockhashTest
lorenzogentile404 Jan 8, 2025
57adb92
added back comments with code for wcp extra rows
lorenzogentile404 Jan 8, 2025
8c874eb
moved preprocessing and calls to wcp before commit
lorenzogentile404 Jan 9, 2025
ef70d16
updated constraints
lorenzogentile404 Jan 9, 2025
be570e9
add multiblock tests draft
lorenzogentile404 Jan 9, 2025
c102738
update constraints
lorenzogentile404 Jan 10, 2025
6540271
partially debugged multiblock tests for blockhash
lorenzogentile404 Jan 10, 2025
d69e489
fixed multi block tests for blockhash
lorenzogentile404 Jan 10, 2025
0a76b28
added test for blockdata involving several blocks with different gas …
lorenzogentile404 Jan 10, 2025
fb9f16b
Merge branch 'arith-dev' into 1679-blockhash-update
lorenzogentile404 Jan 10, 2025
4e9ec31
feat: extract methods and classes for GAS_LIMIT tests
OlivierBBB Jan 10, 2025
d33c3bd
fix: test for all legal GAS_LIMIT transitions
OlivierBBB Jan 11, 2025
596eae4
spotless
OlivierBBB Jan 11, 2025
edafcd2
ras
OlivierBBB Jan 11, 2025
ab842ec
extracted MultiBlockUtils
lorenzogentile404 Jan 11, 2025
3ea75da
merge
OlivierBBB Jan 11, 2025
964b8a5
ras
OlivierBBB Jan 11, 2025
68b61ea
ras
OlivierBBB Jan 11, 2025
e5d550b
extracted max deviation
lorenzogentile404 Jan 11, 2025
e75ddce
Merge branch '1679-blockhash-update' of github.com:Consensys/linea-tr…
lorenzogentile404 Jan 11, 2025
37a5d2f
changed constants from Linea to Ethereum
lorenzogentile404 Jan 11, 2025
0b821d6
fix: typo correction of LINEA to ETHEREUM switch
OlivierBBB Jan 11, 2025
3788e2e
fix: constraints commit update
OlivierBBB Jan 11, 2025
239a292
fix: constraints commit update
OlivierBBB Jan 11, 2025
cdf8377
fix: undo previous constraints commit update
OlivierBBB Jan 11, 2025
54375ee
fix: LINEA compatible BLOCKDATA tracing
OlivierBBB Jan 11, 2025
9898b92
Merge branch 'arith-dev' into 1679-blockhash-update
OlivierBBB Jan 11, 2025
70ffdc7
ras: switch to ETHEREUM tracing
OlivierBBB Jan 12, 2025
bc8997d
fix: robustly extract coinbaseWarmthAtTransactionEnd
OlivierBBB Jan 12, 2025
575aaff
fix(disgusting): we BLOCKDATA and TXNDATA store the coinbase address
OlivierBBB Jan 12, 2025
aa34ff6
ras: switch to LINEA tracing
OlivierBBB Jan 13, 2025
363c4a5
fix: missing header
OlivierBBB Jan 13, 2025
9dd25b4
Delete notes/commands.md
OlivierBBB Jan 13, 2025
93d7064
Delete arithmetization/src/test/resources/replays/8019521.mainnet.json
OlivierBBB Jan 13, 2025
a868b8b
Update ZkTracer.java
OlivierBBB Jan 13, 2025
825d482
fix: mark deliberately failing variableGasLimitTest as @Disabled
OlivierBBB Jan 14, 2025
c0c49c1
fix: constraints commit update
OlivierBBB Jan 14, 2025
364a3d3
spotless
OlivierBBB Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ public void writeToFile(final Path filename) {
header.putInt(traceMap.size());
for (ColumnHeader h : traceMap) {
final String name = h.name();
// System.out.println(name);
header.putShort((short) name.length());
header.put(name.getBytes());
header.put((byte) h.bytesPerElement());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,11 @@ private void handleGasLimit() {
data = EWord.of(blockHeader.getGasLimit());

// row i
// comparison to minimum
wcpCallToGEQ(0, data, EWord.of(LINEA_GAS_LIMIT_MINIMUM));

// row i + 1
// comparison to maximum
wcpCallToLEQ(1, data, EWord.of(Bytes.ofUnsignedLong(LINEA_GAS_LIMIT_MAXIMUM)));

if (!firstBlockInConflation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
package net.consensys.linea.zktracer.module.blockhash;

import static com.google.common.base.Preconditions.checkArgument;
import static net.consensys.linea.zktracer.module.constants.GlobalConstants.BLOCKHASH_MAX_HISTORY;
import static net.consensys.linea.zktracer.module.constants.GlobalConstants.LLARGE;

import java.nio.MappedByteBuffer;
import java.util.HashMap;
Expand All @@ -33,7 +31,6 @@
import net.consensys.linea.zktracer.module.hub.defer.PostOpcodeDefer;
import net.consensys.linea.zktracer.module.wcp.Wcp;
import net.consensys.linea.zktracer.opcode.OpCode;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.Operation;
Expand All @@ -52,20 +49,16 @@ public class Blockhash implements OperationSetModule<BlockhashOperation>, PostOp

/* Stores the result of BLOCKHASH if the result of the opcode is not 0 */
private final Map<Bytes32, Bytes32> blockHashMap = new HashMap<>();
/* Store the number of call (capped to 2) of BLOCKHASH of a BLOCK_NUMBER*/
private final Map<Bytes32, Integer> numberOfCall = new HashMap<>();

private long absoluteBlockNumber;
private short relativeBlock;
private short relBlock;
private long absBlock;

private Bytes32 opcodeArgument;
private boolean lowerBound;
private boolean upperBound;
private Bytes32 blockhashArg;

public Blockhash(Hub hub, Wcp wcp) {
this.hub = hub;
this.wcp = wcp;
this.relativeBlock = 0;
this.relBlock = 0;
}

@Override
Expand All @@ -75,31 +68,18 @@ public String moduleKey() {

@Override
public void traceStartBlock(final ProcessableBlockHeader processableBlockHeader) {
relativeBlock += 1;
absoluteBlockNumber = processableBlockHeader.getNumber();
relBlock += 1;
absBlock = processableBlockHeader.getNumber();
}

@Override
public void tracePreOpcode(MessageFrame frame) {
final OpCode opCode = OpCode.of(frame.getCurrentOperation().getOpcode());
checkArgument(opCode == OpCode.BLOCKHASH, "Expected BLOCKHASH opcode");

opcodeArgument = Bytes32.leftPad(frame.getStackItem(0));
lowerBound =
wcp.callGEQ(
opcodeArgument, Bytes.ofUnsignedLong(absoluteBlockNumber - BLOCKHASH_MAX_HISTORY));
upperBound = wcp.callLT(opcodeArgument, Bytes.ofUnsignedLong(absoluteBlockNumber));
blockhashArg = Bytes32.leftPad(frame.getStackItem(0));

hub.defers().scheduleForPostExecution(this);

/* To prove the lex order of BLOCK_NUMBER_HI/LO, we call WCP at endConflation, so we need to add rows in WCP now.
If a BLOCK_NUMBER is already called at least two times, no need for additional rows in WCP*/
final int numberOfCall = this.numberOfCall.getOrDefault(opcodeArgument, 0);
if (numberOfCall < 2) {
wcp.additionalRows.add(
Math.max(Math.min(LLARGE, opcodeArgument.trimLeadingZeros().size()), 1));
this.numberOfCall.replace(opcodeArgument, numberOfCall, numberOfCall + 1);
}
}

@Override
Expand All @@ -108,26 +88,27 @@ public void resolvePostExecution(

final OpCode opCode = OpCode.of(frame.getCurrentOperation().getOpcode());
if (opCode == OpCode.BLOCKHASH) {
final Bytes32 result = Bytes32.leftPad(frame.getStackItem(0));
operations.add(
new BlockhashOperation(
relativeBlock, opcodeArgument, absoluteBlockNumber, lowerBound, upperBound, result));
if (result != Bytes32.ZERO) {
blockHashMap.put(opcodeArgument, result);
final Bytes32 blockhashRes = Bytes32.leftPad(frame.getStackItem(0));
operations.add(new BlockhashOperation(relBlock, absBlock, blockhashArg, blockhashRes, wcp));
if (blockhashRes != Bytes32.ZERO) {
blockHashMap.put(blockhashArg, blockhashRes);
}
}
}

/**
* Operations are sorted wrt blockhashArg and the wcp module is called accordingly. We must call
* the WCP module before calling {@link #commit(List<MappedByteBuffer>)} as the headers sizes must
* be computed with the final list of operations ready.
*/
@Override
public void traceEndConflation(WorldView state) {
OperationSetModule.super.traceEndConflation(state);
sortedOperations = sortOperations(new BlockhashComparator());
if (!sortedOperations.isEmpty()) {
wcp.callGEQ(sortedOperations.getFirst().opcodeArgument(), Bytes32.ZERO);
for (int i = 1; i < sortedOperations.size(); i++) {
wcp.callGEQ(
sortedOperations.get(i).opcodeArgument(), sortedOperations.get(i - 1).opcodeArgument());
}
Bytes32 prevBlockhashArg = Bytes32.ZERO;
for (BlockhashOperation op : sortedOperations) {
op.handlePreprocessing(prevBlockhashArg);
prevBlockhashArg = op.blockhashArg();
}
}

Expand All @@ -139,13 +120,14 @@ public List<ColumnHeader> columnsHeaders() {
@Override
public void commit(List<MappedByteBuffer> buffers) {
final Trace trace = new Trace(buffers);
for (BlockhashOperation op : sortedOperations) {
final Bytes32 hash =
op.result() == Bytes32.ZERO
? this.blockHashMap.getOrDefault(op.opcodeArgument(), Bytes32.ZERO)
: op.result();

op.trace(trace, hash);
for (BlockhashOperation op : sortedOperations) {
final Bytes32 blockhashVal =
op.blockhashRes() == Bytes32.ZERO
? this.blockHashMap.getOrDefault(op.blockhashArg(), Bytes32.ZERO)
: op.blockhashRes();
op.traceMacro(trace, blockhashVal);
op.tracePreprocessing(trace);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ public class BlockhashComparator implements Comparator<BlockhashOperation> {
@Override
public int compare(BlockhashOperation o1, BlockhashOperation o2) {
// First, sort by BLOCK_NUMBER
final int blockNumberComparison = o1.opcodeArgument().compareTo(o2.opcodeArgument());
final int blockNumberComparison = o1.blockhashArg().compareTo(o2.blockhashArg());
if (blockNumberComparison != 0) {
return blockNumberComparison;
} else {
// Second, sort by RELATIVE_BLOCK
return o1.relativeBlock() - o2.relativeBlock();
return o1.relBlock() - o2.relBlock();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,78 +15,159 @@

package net.consensys.linea.zktracer.module.blockhash;

import static net.consensys.linea.zktracer.module.blockhash.Trace.BLOCKHASH_DEPTH;
import static net.consensys.linea.zktracer.module.blockhash.Trace.nROWS_PRPRC;
import static net.consensys.linea.zktracer.module.constants.GlobalConstants.EVM_INST_EQ;
import static net.consensys.linea.zktracer.module.constants.GlobalConstants.EVM_INST_LT;
import static net.consensys.linea.zktracer.module.constants.GlobalConstants.LLARGE;
import static net.consensys.linea.zktracer.module.constants.GlobalConstants.WCP_INST_LEQ;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;
import net.consensys.linea.zktracer.container.ModuleOperation;
import net.consensys.linea.zktracer.types.UnsignedByte;
import net.consensys.linea.zktracer.module.wcp.Wcp;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;

@Accessors(fluent = true)
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
@RequiredArgsConstructor
public class BlockhashOperation extends ModuleOperation {
@Getter @EqualsAndHashCode.Include private final short relativeBlock;
@Getter @EqualsAndHashCode.Include private final Bytes32 opcodeArgument;
private final long absoluteBlockNumber;
private final boolean lowerBound;
private final boolean upperBound;
@Getter private final Bytes32 result;
@Getter @EqualsAndHashCode.Include private final short relBlock;
@Getter @EqualsAndHashCode.Include private final Bytes32 blockhashArg;
private final long absBlock;
@Getter private final Bytes32 blockhashRes;
private final Wcp wcp;

private final Bytes[] exoArg1Hi = new Bytes[nROWS_PRPRC];
private final Bytes[] exoArg1Lo = new Bytes[nROWS_PRPRC];
private final Bytes[] exoArg2Hi = new Bytes[nROWS_PRPRC];
private final Bytes[] exoArg2Lo = new Bytes[nROWS_PRPRC];
private final long[] exoInst = new long[nROWS_PRPRC];
private final boolean[] exoRes = new boolean[nROWS_PRPRC];

public BlockhashOperation(
final short relBlock,
final long absBlock,
final Bytes32 blockhashArg,
final Bytes32 blockhashRes,
final Wcp wcp) {
this.relBlock = relBlock;
this.absBlock = absBlock;
this.blockhashArg = blockhashArg;
this.blockhashRes = blockhashRes;
this.wcp = wcp;
}

void handlePreprocessing(Bytes32 prevBlockhashArg) {
final Bytes prevBHArgHi = prevBlockhashArg.slice(0, LLARGE);
final Bytes prevBHArgLo = prevBlockhashArg.slice(LLARGE, LLARGE);
final Bytes currBHArgHi = blockhashArg.slice(0, LLARGE);
final Bytes curBHArgLo = blockhashArg.slice(LLARGE, LLARGE);

// NOTE: w goes from 0 to 4 because it refers to the array
// however, rows go from i+1 to i+5 because it refers the MACRO row (index i)
// row i + 1
wcpCallToLEQ(0, prevBHArgHi, prevBHArgLo, currBHArgHi, curBHArgLo);

// row i + 2
boolean sameBHArg = wcpCallToEQ(1, prevBHArgHi, prevBHArgLo, currBHArgHi, curBHArgLo);

// row i + 3
boolean res3 =
wcpCallToLEQ(
2, Bytes.of(0), Bytes.ofUnsignedInt(256), Bytes.of(0), Bytes.ofUnsignedLong(absBlock));
long minimalReachable = 0;
if (res3) {
minimalReachable = absBlock - 256;
}

// row i + 4
boolean upperBoundOk =
wcpCallToLT(3, currBHArgHi, curBHArgLo, Bytes.of(0), Bytes.ofUnsignedLong(absBlock));

// row i + 5
boolean lowerBoundOk =
wcpCallToLEQ(
4, Bytes.of(0), Bytes.ofUnsignedLong(minimalReachable), currBHArgHi, curBHArgLo);
}

@Override
protected int computeLineCount() {
return 1;
return BLOCKHASH_DEPTH;
}

public void trace(Trace trace, final Bytes32 hash) {
public void traceMacro(Trace trace, final Bytes32 blockhashVal) {
trace
.iomf(true)
.blockNumberHi(opcodeArgument.slice(0, LLARGE))
.blockNumberLo(opcodeArgument.slice(LLARGE, LLARGE))
.resHi(result.slice(0, LLARGE))
.resLo(result.slice(LLARGE, LLARGE))
.relBlock(relativeBlock)
.absBlock(absoluteBlockNumber)
.lowerBoundCheck(lowerBound)
.upperBoundCheck(upperBound)
.inRange(lowerBound && upperBound)
.blockHashHi(hash.slice(0, LLARGE))
.blockHashLo(hash.slice(LLARGE, LLARGE))
.byteHi0(UnsignedByte.of(hash.get(0)))
.byteHi1(UnsignedByte.of(hash.get(1)))
.byteHi2(UnsignedByte.of(hash.get(2)))
.byteHi3(UnsignedByte.of(hash.get(3)))
.byteHi4(UnsignedByte.of(hash.get(4)))
.byteHi5(UnsignedByte.of(hash.get(5)))
.byteHi6(UnsignedByte.of(hash.get(6)))
.byteHi7(UnsignedByte.of(hash.get(7)))
.byteHi8(UnsignedByte.of(hash.get(8)))
.byteHi9(UnsignedByte.of(hash.get(9)))
.byteHi10(UnsignedByte.of(hash.get(10)))
.byteHi11(UnsignedByte.of(hash.get(11)))
.byteHi12(UnsignedByte.of(hash.get(12)))
.byteHi13(UnsignedByte.of(hash.get(13)))
.byteHi14(UnsignedByte.of(hash.get(14)))
.byteHi15(UnsignedByte.of(hash.get(15)))
.byteLo0(UnsignedByte.of(hash.get(LLARGE + 0)))
.byteLo1(UnsignedByte.of(hash.get(LLARGE + 1)))
.byteLo2(UnsignedByte.of(hash.get(LLARGE + 2)))
.byteLo3(UnsignedByte.of(hash.get(LLARGE + 3)))
.byteLo4(UnsignedByte.of(hash.get(LLARGE + 4)))
.byteLo5(UnsignedByte.of(hash.get(LLARGE + 5)))
.byteLo6(UnsignedByte.of(hash.get(LLARGE + 6)))
.byteLo7(UnsignedByte.of(hash.get(LLARGE + 7)))
.byteLo8(UnsignedByte.of(hash.get(LLARGE + 8)))
.byteLo9(UnsignedByte.of(hash.get(LLARGE + 9)))
.byteLo10(UnsignedByte.of(hash.get(LLARGE + 10)))
.byteLo11(UnsignedByte.of(hash.get(LLARGE + 11)))
.byteLo12(UnsignedByte.of(hash.get(LLARGE + 12)))
.byteLo13(UnsignedByte.of(hash.get(LLARGE + 13)))
.byteLo14(UnsignedByte.of(hash.get(LLARGE + 14)))
.byteLo15(UnsignedByte.of(hash.get(LLARGE + 15)))
.validateRow();
.macro(true)
.ct(0)
.ctMax(0)
.pMacroRelBlock(relBlock)
.pMacroAbsBlock(absBlock)
.pMacroBlockhashValHi(blockhashVal.slice(0, LLARGE))
.pMacroBlockhashValLo(blockhashVal.slice(LLARGE, LLARGE))
.pMacroBlockhashArgHi(blockhashArg.slice(0, LLARGE))
.pMacroBlockhashArgLo(blockhashArg.slice(LLARGE, LLARGE))
.pMacroBlockhashResHi(blockhashRes.slice(0, LLARGE))
.pMacroBlockhashResLo(blockhashRes.slice(LLARGE, LLARGE))
.fillAndValidateRow();
}

public void tracePreprocessing(Trace trace) {
for (int ct = 0; ct < nROWS_PRPRC; ct++) {
trace
.iomf(true)
.prprc(true)
.ct(ct)
.ctMax(nROWS_PRPRC - 1)
.pPreprocessingExoInst(exoInst[ct])
.pPreprocessingExoArg1Hi(exoArg1Hi[ct])
.pPreprocessingExoArg1Lo(exoArg1Lo[ct])
.pPreprocessingExoArg2Hi(exoArg2Hi[ct])
.pPreprocessingExoArg2Lo(exoArg2Lo[ct])
.pPreprocessingExoRes(exoRes[ct])
.fillAndValidateRow();
}
}

// WCP calls
private boolean wcpCallToLT(
int w, Bytes exoArg1Hi, Bytes exoArg1Lo, Bytes exoArg2Hi, Bytes exoArg2Lo) {
this.exoInst[w] = EVM_INST_LT;
this.exoArg1Hi[w] = exoArg1Hi;
this.exoArg1Lo[w] = exoArg1Lo;
this.exoArg2Hi[w] = exoArg2Hi;
this.exoArg2Lo[w] = exoArg2Lo;
this.exoRes[w] =
wcp.callLT(
Bytes.concatenate(exoArg1Hi, exoArg1Lo), Bytes.concatenate(exoArg2Hi, exoArg2Lo));
return this.exoRes[w];
}

private boolean wcpCallToLEQ(
int w, Bytes exoArg1Hi, Bytes exoArg1Lo, Bytes exoArg2Hi, Bytes exoArg2Lo) {
this.exoInst[w] = WCP_INST_LEQ;
this.exoArg1Hi[w] = exoArg1Hi;
this.exoArg1Lo[w] = exoArg1Lo;
this.exoArg2Hi[w] = exoArg2Hi;
this.exoArg2Lo[w] = exoArg2Lo;
this.exoRes[w] =
wcp.callLEQ(
Bytes.concatenate(exoArg1Hi, exoArg1Lo), Bytes.concatenate(exoArg2Hi, exoArg2Lo));
return this.exoRes[w];
}

private boolean wcpCallToEQ(
int w, Bytes exoArg1Hi, Bytes exoArg1Lo, Bytes exoArg2Hi, Bytes exoArg2Lo) {
this.exoInst[w] = EVM_INST_EQ;
this.exoArg1Hi[w] = exoArg1Hi;
this.exoArg1Lo[w] = exoArg1Lo;
this.exoArg2Hi[w] = exoArg2Hi;
this.exoArg2Lo[w] = exoArg2Lo;
this.exoRes[w] =
wcp.callEQ(
Bytes.concatenate(exoArg1Hi, exoArg1Lo), Bytes.concatenate(exoArg2Hi, exoArg2Lo));
return this.exoRes[w];
}
}
Loading