Initialize KZG native lib at startup if Cancun is enabled (#5084)

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
pull/5118/head
Fabio Di Fabio 2 years ago committed by GitHub
parent bac7adec89
commit 53b4afce82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 1
      besu/build.gradle
  3. 54
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  4. 47
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  5. 1
      besu/src/test/resources/everything_config.toml
  6. 4163
      besu/src/test/resources/trusted_setup.txt
  7. 0
      config/src/main/resources/kzg-trusted-setups/mainnet.txt
  8. 75
      evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java
  9. 10
      evm/src/test/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompileContractTest.java
  10. 4163
      evm/src/test/resources/kzg-trusted-setups/foo.txt
  11. 11
      gradle/verification-metadata.xml
  12. 2
      gradle/versions.gradle

@ -29,6 +29,7 @@ tests are updated to use EC private keys instead of RSA keys.
- Add worldstate auto-heal mechanism [#5059](https://github.com/hyperledger/besu/pull/5059)
- Support for EIP-4895 - Withdrawals for Shanghai fork
- If a PoS block creation repetition takes less than a configurable duration, then waits before next repetition [#5048](https://github.com/hyperledger/besu/pull/5048)
- Added the option --kzg-trusted-setup to pass a custom setup file for custom networks or to override the default one for named networks [#5084](https://github.com/hyperledger/besu/pull/5084)
### Bug Fixes
- Mitigation fix for stale bonsai code storage leading to log rolling issues on contract recreates [#4906](https://github.com/hyperledger/besu/pull/4906)

@ -77,6 +77,7 @@ dependencies {
implementation 'org.springframework.security:spring-security-crypto'
implementation 'org.xerial.snappy:snappy-java'
implementation 'net.consensys.services:quorum-mainnet-launcher'
implementation 'tech.pegasys:jc-kzg-4844'
runtimeOnly 'org.apache.logging.log4j:log4j-jul'
runtimeOnly 'com.splunk.logging:splunk-library-javalogging'

@ -150,6 +150,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract;
import org.hyperledger.besu.evm.precompile.BigIntegerModularExponentiationPrecompiledContract;
import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.MetricCategoryRegistryImpl;
import org.hyperledger.besu.metrics.MetricsProtocol;
@ -542,6 +543,15 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
arity = "1")
private final BigInteger networkId = null;
@Option(
names = {"--kzg-trusted-setup"},
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description =
"Path to file containing the KZG trusted setup, mandatory for custom networks that support data blobs, "
+ "optional for overriding named networks default.",
arity = "1")
private final Path kzgTrustedSetupFile = null;
@CommandLine.ArgGroup(validate = false, heading = "@|bold GraphQL Options|@%n")
GraphQlOptionGroup graphQlOptionGroup = new GraphQlOptionGroup();
@ -1838,6 +1848,24 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
Blake2bfMessageDigest.Blake2bfDigest.disableNative();
logger.info("Using the Java implementation of the blake2bf algorithm");
}
if (getActualGenesisConfigOptions().getCancunTime().isPresent()) {
// if custom genesis provided, then trusted setup file is mandatory
if (genesisFile != null && kzgTrustedSetupFile == null) {
throw new ParameterException(
this.commandLine,
"--kzg-trusted-setup is mandatory when providing a custom genesis that support data blobs");
}
if (kzgTrustedSetupFile != null) {
KZGPointEvalPrecompiledContract.init(kzgTrustedSetupFile);
} else {
KZGPointEvalPrecompiledContract.init(network.name());
}
} else if (kzgTrustedSetupFile != null) {
throw new ParameterException(
this.commandLine,
"--kzg-trusted-setup can only be specified on networks with data blobs enabled");
}
}
private void validateOptions() {
@ -3486,16 +3514,18 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
isGoQuorumCompatibilityMode = true;
}
private GenesisConfigOptions getActualGenesisConfigOptions() {
return Optional.ofNullable(genesisConfigOptions)
.orElseGet(
() ->
GenesisConfigFile.fromConfig(
genesisConfig(Optional.ofNullable(network).orElse(MAINNET)))
.getConfigOptions(genesisConfigOverrides));
}
private void setMergeConfigOptions() {
MergeConfigOptions.setMergeEnabled(
Optional.ofNullable(genesisConfigOptions)
.orElseGet(
() ->
GenesisConfigFile.fromConfig(
genesisConfig(Optional.ofNullable(network).orElse(MAINNET)))
.getConfigOptions(genesisConfigOverrides))
.getTerminalTotalDifficulty()
.isPresent());
getActualGenesisConfigOptions().getTerminalTotalDifficulty().isPresent());
}
private void setIgnorableStorageSegments() {
@ -3505,13 +3535,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private void validatePostMergeCheckpointBlockRequirements() {
final GenesisConfigOptions genesisOptions =
Optional.ofNullable(genesisConfigOptions)
.orElseGet(
() ->
GenesisConfigFile.fromConfig(
genesisConfig(Optional.ofNullable(network).orElse(MAINNET)))
.getConfigOptions(genesisConfigOverrides));
final GenesisConfigOptions genesisOptions = getActualGenesisConfigOptions();
final SynchronizerConfiguration synchronizerConfiguration =
unstableSynchronizerOptions.toDomainObject().build();
final Optional<UInt256> terminalTotalDifficulty = genesisOptions.getTerminalTotalDifficulty();

@ -102,6 +102,7 @@ import java.io.IOException;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@ -188,6 +189,9 @@ public class BesuCommandTest extends CommandTestAbstract {
.put("bootnodes", List.of(VALID_ENODE_STRINGS))
.put("dns", DNS_DISCOVERY_URL)));
private static final JsonObject GENESIS_WITH_DATA_BLOBS_ENABLED =
new JsonObject().put("config", new JsonObject().put("cancunTime", 1L));
static {
DEFAULT_JSON_RPC_CONFIGURATION = JsonRpcConfiguration.createDefault();
DEFAULT_GRAPH_QL_CONFIGURATION = GraphQLConfiguration.createDefault();
@ -5598,4 +5602,47 @@ public class BesuCommandTest extends CommandTestAbstract {
.contains(
"PoS checkpoint sync can't be used with TTD = 0 and checkpoint totalDifficulty = 0");
}
@Test
public void kzgTrustedSetupFileRequiresDataBlobEnabledNetwork() throws IOException {
final Path genesisFileWithoutBlobs =
createFakeGenesisFile(new JsonObject().put("config", new JsonObject()));
parseCommand(
"--genesis-file",
genesisFileWithoutBlobs.toString(),
"--kzg-trusted-setup",
"/etc/besu/kzg-trusted-setup.txt");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains("--kzg-trusted-setup can only be specified on networks with data blobs enabled");
}
@Test
public void kzgTrustedSetupFileIsMandatoryWithCustomGenesisFile()
throws IOException, URISyntaxException {
final Path genesisFileWithBlobs = createFakeGenesisFile(GENESIS_WITH_DATA_BLOBS_ENABLED);
parseCommand("--genesis-file", genesisFileWithBlobs.toString());
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains(
"--kzg-trusted-setup is mandatory when providing a custom genesis that support data blobs");
}
@Test
public void kzgTrustedSetupFileLoadedWithCustomGenesisFile()
throws IOException, URISyntaxException {
final Path testSetupAbsolutePath =
Path.of(BesuCommandTest.class.getResource("/trusted_setup.txt").toURI());
final Path genesisFileWithBlobs = createFakeGenesisFile(GENESIS_WITH_DATA_BLOBS_ENABLED);
parseCommand(
"--genesis-file",
genesisFileWithBlobs.toString(),
"--kzg-trusted-setup",
testSetupAbsolutePath.toString());
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
}

@ -56,6 +56,7 @@ genesis-file="~/genesis.json"
sync-mode="fast"
fast-sync-min-peers=5
network-id=303
kzg-trusted-setup="/etc/besu/kzg-trusted-setup.txt"
# JSON-RPC
rpc-http-enabled=false

File diff suppressed because it is too large Load Diff

@ -14,15 +14,9 @@
*/
package org.hyperledger.besu.evm.precompile;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
@ -37,52 +31,55 @@ import org.jetbrains.annotations.NotNull;
public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
private static final AtomicBoolean loaded = new AtomicBoolean(false);
private final Bytes successResult;
private static Bytes successResult;
private static void init() {
CKZG4844JNI.loadNativeLibrary(CKZG4844JNI.Preset.MAINNET);
Bytes fieldElementsPerBlob =
Bytes32.wrap(Bytes.ofUnsignedInt(CKZG4844JNI.getFieldElementsPerBlob()).xor(Bytes32.ZERO));
Bytes blsModulus =
Bytes32.wrap(Bytes.of(CKZG4844JNI.BLS_MODULUS.toByteArray()).xor(Bytes32.ZERO));
/** Instantiates a new KZGPointEval precompile contract. */
public KZGPointEvalPrecompiledContract() {
this(Optional.empty());
successResult = Bytes.concatenate(fieldElementsPerBlob, blsModulus);
}
/**
* Instantiates a new KZGPointEval precompile contract.
* Init the C-KZG native lib using a file as trusted setup
*
* @param pathToTrustedSetup the trusted setup path
* @param trustedSetupFile the file with the trusted setup
* @throws IllegalStateException is the trusted setup was already loaded
*/
public KZGPointEvalPrecompiledContract(final Optional<Path> pathToTrustedSetup) {
public static void init(final Path trustedSetupFile) {
if (loaded.compareAndSet(false, true)) {
String absolutePathToSetup;
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);
}
}
CKZG4844JNI.loadNativeLibrary(CKZG4844JNI.Preset.MAINNET);
CKZG4844JNI.loadTrustedSetup(absolutePathToSetup);
init();
CKZG4844JNI.loadTrustedSetup(trustedSetupFile.toAbsolutePath().toString());
} else {
throw new IllegalStateException("KZG trusted setup was already loaded");
}
Bytes fieldElementsPerBlob =
Bytes32.wrap(Bytes.ofUnsignedInt(CKZG4844JNI.getFieldElementsPerBlob()).xor(Bytes32.ZERO));
Bytes blsModulus =
Bytes32.wrap(Bytes.of(CKZG4844JNI.BLS_MODULUS.toByteArray()).xor(Bytes32.ZERO));
}
successResult = Bytes.concatenate(fieldElementsPerBlob, blsModulus);
/**
* Init the C-KZG native lib using a resource identified by the passed network name as trusted
* setup
*
* @param networkName used to select the resource that contains the trusted setup
* @throws IllegalStateException is the trusted setup was already loaded
*/
public static void init(final String networkName) {
if (loaded.compareAndSet(false, true)) {
init();
final String trustedSetupResourceName =
"/kzg-trusted-setups/" + networkName.toLowerCase() + ".txt";
CKZG4844JNI.loadTrustedSetupFromResource(
trustedSetupResourceName, KZGPointEvalPrecompiledContract.class);
} else {
throw new IllegalStateException("KZG trusted setup was already loaded");
}
}
/** free up resources. */
@VisibleForTesting
public void tearDown() {
void tearDown() {
CKZG4844JNI.freeTrustedSetup();
loaded.set(false);
}

@ -21,9 +21,7 @@ import org.hyperledger.besu.evm.frame.MessageFrame;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@ -42,12 +40,8 @@ public class KZGPointEvalPrecompileContractTest {
@BeforeAll
public static void init() {
Path testSetupAbsolutePath =
Path.of(
KZGPointEvalPrecompileContractTest.class
.getResource("trusted_setup_4096.txt")
.getPath());
contract = new KZGPointEvalPrecompiledContract(Optional.of(testSetupAbsolutePath));
KZGPointEvalPrecompiledContract.init("foo");
contract = new KZGPointEvalPrecompiledContract();
}
@AfterAll

File diff suppressed because it is too large Load Diff

@ -5614,6 +5614,17 @@
<sha256 value="8314ff61776036dacab235bf0a225d4ef901e1555a86f91977e162780d3bbe54" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="tech.pegasys" name="jc-kzg-4844" version="0.4.0">
<artifact name="jc-kzg-4844-0.4.0.jar">
<sha256 value="1d13a463802f39614c26ba7e7fd31023e9498ddbc7adbf41a525316c135a84c5" origin="Generated by Gradle"/>
</artifact>
<artifact name="jc-kzg-4844-0.4.0.module">
<sha256 value="169ae39487b50f7e54c2745143bdb78e402c168c93e8390e59b4c641636133c0" origin="Generated by Gradle"/>
</artifact>
<artifact name="jc-kzg-4844-0.4.0.pom">
<sha256 value="1fde825ebaf0147c421c490be110c8eac48bc4069046b0fece185522a9ab0f1d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="tech.pegasys.discovery" name="discovery" version="22.2.0">
<artifact name="discovery-22.2.0.jar">
<sha256 value="0da2a8b2928aef595e9a637fa3d6595cecf744a2c63e05b815130ed658f80005" origin="Generated by Gradle"/>

@ -152,7 +152,7 @@ dependencyManagement {
}
dependency 'org.fusesource.jansi:jansi:2.4.0'
dependency 'tech.pegasys:jc-kzg-4844:0.1.0'
dependency 'tech.pegasys:jc-kzg-4844:0.4.0'
dependencySet(group: 'org.hyperledger.besu', version: '0.7.1') {
entry 'arithmetic'
entry 'ipa-multipoint'

Loading…
Cancel
Save