Merge remote-tracking branch 'upstream/eip-4844-interop' into eip-4844-interop

pull/5091/head
Fabio Di Fabio 2 years ago
commit f438f0216e
  1. 15
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsBundleV1.java
  2. 11
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java
  3. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
  4. 36
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ssz/TransactionNetworkPayload.java
  5. 54
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
  6. 77
      evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java
  7. 4163
      evm/src/test/resources/org/hyperledger/besu/evm/precompile/trusted_setup_devnet_4.txt
  8. 6
      evm/src/test/resources/org/hyperledger/besu/evm/precompile/verifyAggregateKzgProof.json

@ -63,20 +63,23 @@ public class EngineGetBlobsBundleV1 extends AbstractEngineGetPayload {
private BlobsBundleV1 createResponse(final Block block) {
List<Bytes> kzgs =
final List<Transaction.BlobsWithCommitments> blobsWithCommitments =
block.getBody().getTransactions().stream()
.map(Transaction::getBlobsWithCommitments)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
final List<String> kzgs =
blobsWithCommitments.stream()
.flatMap(b -> b.getKzgCommitments().stream())
.map(Bytes::toString)
.collect(Collectors.toList());
List<Bytes> blobs =
block.getBody().getTransactions().stream()
.map(Transaction::getBlobsWithCommitments)
.filter(Optional::isPresent)
.map(Optional::get)
final List<String> blobs =
blobsWithCommitments.stream()
.flatMap(b -> b.getBlobs().stream())
.map(Bytes::toString)
.collect(Collectors.toList());
return new BlobsBundleV1(block.getHash(), kzgs, blobs);

@ -21,18 +21,17 @@ import java.util.List;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.apache.tuweni.bytes.Bytes;
@JsonPropertyOrder({"blockHash", "kzgs", "blobs"})
public class BlobsBundleV1 {
private final String blockHash;
private final List<Bytes> kzgs;
private final List<String> kzgs;
private final List<Bytes> blobs;
private final List<String> blobs;
public BlobsBundleV1(final Hash blockHash, final List<Bytes> kzgs, final List<Bytes> blobs) {
public BlobsBundleV1(final Hash blockHash, final List<String> kzgs, final List<String> blobs) {
this.blockHash = blockHash.toString();
this.kzgs = kzgs;
this.blobs = blobs;
@ -44,12 +43,12 @@ public class BlobsBundleV1 {
}
@JsonGetter("kzgs")
public List<Bytes> getKzgs() {
public List<String> getKzgs() {
return kzgs;
}
@JsonGetter("blobs")
public List<Bytes> getBlobs() {
public List<String> getBlobs() {
return blobs;
}
}

@ -1369,13 +1369,7 @@ public class Transaction
public List<Bytes> getBlobs() {
return blobs.getElements().stream()
.map(
blob -> {
return blob.getElements().stream()
.map(sszuInt256Wrapper -> (Bytes) sszuInt256Wrapper.getData().toBytes())
.reduce(Bytes::concatenate)
.orElseThrow();
})
.map(TransactionNetworkPayload.Blob::getBytes)
.collect(Collectors.toList());
}

@ -24,7 +24,6 @@ import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.ssz.SSZFixedSizeTypeList;
import org.apache.tuweni.ssz.SSZFixedSizeVector;
import org.apache.tuweni.ssz.SSZReadable;
import org.apache.tuweni.ssz.SSZReader;
import org.apache.tuweni.ssz.SSZVariableSizeTypeList;
@ -335,8 +334,8 @@ public class TransactionNetworkPayload implements SSZReadable, SSZWritable {
public static class AccessTuple implements SSZReadable, SSZWritable {
Bytes address;
SSZFixedSizeTypeList<SSZUInt256Wrapper> storageKeys =
new SSZFixedSizeTypeList<>(ELEMENT_SIZE, SSZUInt256Wrapper::new);
SSZFixedSizeTypeList<SSZByte32Wrapper> storageKeys =
new SSZFixedSizeTypeList<>(ELEMENT_SIZE, SSZByte32Wrapper::new);
@Override
public boolean isFixed() {
@ -359,7 +358,7 @@ public class TransactionNetworkPayload implements SSZReadable, SSZWritable {
public List<Bytes32> getStorageKeys() {
return storageKeys.getElements().stream()
.map(sszuInt256Wrapper -> sszuInt256Wrapper.getData().toBytes())
.map(sszByte32Wrapper -> sszByte32Wrapper.getData())
.collect(Collectors.toList());
}
@ -375,9 +374,9 @@ public class TransactionNetworkPayload implements SSZReadable, SSZWritable {
storageKeys.stream()
.map(
bytes32 -> {
SSZUInt256Wrapper sszuInt256Wrapper = new SSZUInt256Wrapper();
sszuInt256Wrapper.setData(UInt256.fromBytes(bytes32));
return sszuInt256Wrapper;
SSZByte32Wrapper sszByte32Wrapper = new SSZByte32Wrapper();
sszByte32Wrapper.setData(UInt256.fromBytes(bytes32));
return sszByte32Wrapper;
})
.collect(Collectors.toList()));
}
@ -480,42 +479,41 @@ public class TransactionNetworkPayload implements SSZReadable, SSZWritable {
}
public static class Blob implements SSZReadable, SSZWritable {
SSZFixedSizeVector<SSZUInt256Wrapper> vector =
new SSZFixedSizeVector<>(FIELD_ELEMENTS_PER_BLOB, ELEMENT_SIZE, SSZUInt256Wrapper::new);
Bytes bytes;
@Override
public void populateFromReader(final SSZReader reader) {
vector.populateFromReader(reader);
bytes = reader.readFixedBytes(FIELD_ELEMENTS_PER_BLOB * ELEMENT_SIZE);
}
@Override
public void writeTo(final SSZWriter writer) {
vector.writeTo(writer);
writer.writeFixedBytes(bytes);
}
public List<SSZUInt256Wrapper> getElements() {
return vector.getElements();
public Bytes getBytes() {
return bytes;
}
}
public static class SSZUInt256Wrapper implements SSZReadable, SSZWritable {
UInt256 data;
public static class SSZByte32Wrapper implements SSZReadable, SSZWritable {
Bytes32 data;
@Override
public void populateFromReader(final SSZReader reader) {
data = reader.readUInt256();
data = Bytes32.wrap(reader.readFixedBytes(32));
}
@Override
public void writeTo(final SSZWriter writer) {
writer.writeUInt256(data);
writer.writeBytes(data);
}
public UInt256 getData() {
public Bytes32 getData() {
return data;
}
public void setData(final UInt256 data) {
public void setData(final Bytes32 data) {
this.data = data;
}
}

@ -135,8 +135,7 @@ public class MainnetTransactionValidator {
return signatureResult;
}
if (transaction.getType().equals(TransactionType.BLOB)
&& transaction.getBlobsWithCommitments().isPresent()) {
if (transaction.getType().supportsBlob() && transaction.getBlobsWithCommitments().isPresent()) {
final ValidationResult<TransactionInvalidReason> blobsResult =
validateTransactionsBlobs(transaction);
if (!blobsResult.isValid()) {
@ -334,13 +333,7 @@ public class MainnetTransactionValidator {
public ValidationResult<TransactionInvalidReason> validateTransactionsBlobs(
final Transaction transaction) {
if (transaction.getBlobsWithCommitments().isEmpty()) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_BLOBS,
"transaction blobs are empty, cannot verify without blobs");
}
Transaction.BlobsWithCommitments blobsWithCommitments =
final Transaction.BlobsWithCommitments blobsWithCommitments =
transaction.getBlobsWithCommitments().get();
final long blobsLimit = gasLimitCalculator.currentDataGasLimit() / gasCalculator.dataGasCost(1);
@ -360,27 +353,28 @@ public class MainnetTransactionValidator {
"transaction blobs and commitments are not the same size");
}
List<TransactionNetworkPayload.KZGCommitment> commitments =
blobsWithCommitments.kzgCommitments.getElements();
for (TransactionNetworkPayload.KZGCommitment commitment : commitments) {
if (commitment.getData().get(0) != BLOB_COMMITMENT_VERSION_KZG) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_BLOBS,
"transaction blobs commitment version is not supported");
}
}
if (transaction.getVersionedHashes().isEmpty()) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_BLOBS,
"transaction versioned hashes are empty, cannot verify without versioned hashes");
}
List<Hash> versionedHashes = transaction.getVersionedHashes().get();
final List<Hash> versionedHashes = transaction.getVersionedHashes().get();
for (int i = 0; i < versionedHashes.size(); i++) {
TransactionNetworkPayload.KZGCommitment commitment =
final TransactionNetworkPayload.KZGCommitment commitment =
blobsWithCommitments.kzgCommitments.getElements().get(i);
Hash versionedHash = versionedHashes.get(i);
Hash calculatedVersionedHash = hashCommitment(commitment);
final Hash versionedHash = versionedHashes.get(i);
if (versionedHash.get(0) != BLOB_COMMITMENT_VERSION_KZG) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_BLOBS,
"transaction blobs commitment version is not supported. Expected "
+ BLOB_COMMITMENT_VERSION_KZG
+ ", found "
+ versionedHash.get(0));
}
final Hash calculatedVersionedHash = hashCommitment(commitment);
if (!calculatedVersionedHash.equals(versionedHash)) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_BLOBS,
@ -388,29 +382,25 @@ public class MainnetTransactionValidator {
}
}
Bytes blobs =
final Bytes blobs =
blobsWithCommitments.blobs.getElements().stream()
.map(
blob ->
blob.getElements().stream()
.map(sszuInt256Wrapper -> (Bytes) sszuInt256Wrapper.getData().toBytes())
.reduce(Bytes::concatenate)
.orElseThrow())
.map(TransactionNetworkPayload.Blob::getBytes)
.reduce(Bytes::concatenate)
.orElseThrow();
Bytes kzgCommitments =
final Bytes kzgCommitments =
blobsWithCommitments.kzgCommitments.getElements().stream()
.map(commitment -> commitment.getData())
.reduce(Bytes::concatenate)
.orElseThrow();
boolean kzgVerification =
final boolean kzgVerification =
CKZG4844JNI.verifyAggregateKzgProof(
blobs.toArrayUnsafe(),
kzgCommitments.toArrayUnsafe(),
blobsWithCommitments.blobs.getElements().size(),
blobsWithCommitments.kzgProof.getBytes().toArrayUnsafe());
if (!kzgVerification) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_BLOBS,
@ -421,7 +411,7 @@ public class MainnetTransactionValidator {
}
private Hash hashCommitment(final TransactionNetworkPayload.KZGCommitment commitment) {
SHA256Digest digest = new SHA256Digest();
final SHA256Digest digest = new SHA256Digest();
digest.update(commitment.getData().toArrayUnsafe(), 0, commitment.getData().size());
final byte[] dig = new byte[digest.getDigestSize()];

@ -28,6 +28,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import com.google.common.annotations.VisibleForTesting;
import ethereum.ckzg4844.CKZG4844JNI;
@ -38,6 +39,8 @@ import org.jetbrains.annotations.NotNull;
/** The KZGPointEval precompile contract. */
public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
private static final AtomicBoolean trustedSetupLoaded = new AtomicBoolean(false);
/** Instantiates a new KZGPointEval precompile contract. */
public KZGPointEvalPrecompiledContract() {
this(Optional.empty());
@ -49,46 +52,47 @@ public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
* @param pathToTrustedSetup the trusted setup path
*/
public KZGPointEvalPrecompiledContract(final Optional<Path> pathToTrustedSetup) {
String absolutePathToSetup;
CKZG4844JNI.Preset bitLength;
if (pathToTrustedSetup.isPresent()) {
Path pathToSetup = pathToTrustedSetup.get();
absolutePathToSetup = pathToSetup.toAbsolutePath().toString();
} else {
InputStream is =
KZGPointEvalPrecompiledContract.class.getResourceAsStream(
"mainnet_kzg_trusted_setup_4096.txt");
try {
File jniWillLoadFrom = File.createTempFile("kzgTrustedSetup", "txt");
jniWillLoadFrom.deleteOnExit();
Files.copy(is, jniWillLoadFrom.toPath(), REPLACE_EXISTING);
is.close();
absolutePathToSetup = jniWillLoadFrom.getAbsolutePath();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
try (BufferedReader setupFile =
Files.newBufferedReader(Paths.get(absolutePathToSetup), Charset.defaultCharset())) {
String firstLine = setupFile.readLine();
if ("4".equals(firstLine)) {
bitLength = CKZG4844JNI.Preset.MINIMAL;
} else if ("4096".equals(firstLine)) {
bitLength = CKZG4844JNI.Preset.MAINNET;
if (trustedSetupLoaded.compareAndSet(false, true)) {
String absolutePathToSetup;
CKZG4844JNI.Preset bitLength;
if (pathToTrustedSetup.isPresent()) {
Path pathToSetup = pathToTrustedSetup.get();
absolutePathToSetup = pathToSetup.toAbsolutePath().toString();
} else {
throw new IllegalArgumentException("provided file not a setup for either 4 or 4096 bits");
InputStream is =
KZGPointEvalPrecompiledContract.class.getResourceAsStream(
"mainnet_kzg_trusted_setup_4096.txt");
try {
File jniWillLoadFrom = File.createTempFile("kzgTrustedSetup", ".txt");
jniWillLoadFrom.deleteOnExit();
Files.copy(is, jniWillLoadFrom.toPath(), REPLACE_EXISTING);
is.close();
absolutePathToSetup = jniWillLoadFrom.getAbsolutePath();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
CKZG4844JNI.loadNativeLibrary(bitLength);
try {
CKZG4844JNI.loadTrustedSetup(absolutePathToSetup);
} catch (RuntimeException mightBeAlreadyLoaded) {
if (!mightBeAlreadyLoaded.getMessage().contains("Trusted Setup is already loaded")) {
throw mightBeAlreadyLoaded;
try (BufferedReader setupFile =
Files.newBufferedReader(Paths.get(absolutePathToSetup), Charset.defaultCharset())) {
String firstLine = setupFile.readLine();
if ("4".equals(firstLine)) {
bitLength = CKZG4844JNI.Preset.MINIMAL;
} else if ("4096".equals(firstLine)) {
bitLength = CKZG4844JNI.Preset.MAINNET;
} else {
throw new IllegalArgumentException("provided file not a setup for either 4 or 4096 bits");
}
CKZG4844JNI.loadNativeLibrary(bitLength);
try {
CKZG4844JNI.loadTrustedSetup(absolutePathToSetup);
} catch (RuntimeException mightBeAlreadyLoaded) {
if (!mightBeAlreadyLoaded.getMessage().contains("Trusted Setup is already loaded")) {
throw mightBeAlreadyLoaded;
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@ -96,6 +100,7 @@ public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
@VisibleForTesting
public void tearDown() {
CKZG4844JNI.freeTrustedSetup();
trustedSetupLoaded.set(false);
}
@Override

Loading…
Cancel
Save