diff --git a/start/common/src/main/java/org/ethereum/beacon/start/common/util/SimulateUtils.java b/start/common/src/main/java/org/ethereum/beacon/start/common/util/SimulateUtils.java index 8619f21b5..d875290e5 100644 --- a/start/common/src/main/java/org/ethereum/beacon/start/common/util/SimulateUtils.java +++ b/start/common/src/main/java/org/ethereum/beacon/start/common/util/SimulateUtils.java @@ -9,13 +9,12 @@ import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.crypto.BLS381; import org.ethereum.beacon.crypto.BLS381.PrivateKey; +import org.ethereum.beacon.crypto.Hashes; import org.ethereum.beacon.crypto.MessageParameters; import org.javatuples.Pair; +import org.jetbrains.annotations.NotNull; import tech.pegasys.artemis.ethereum.core.Hash32; -import tech.pegasys.artemis.util.bytes.Bytes32; -import tech.pegasys.artemis.util.bytes.Bytes4; -import tech.pegasys.artemis.util.bytes.Bytes48; -import tech.pegasys.artemis.util.bytes.Bytes96; +import tech.pegasys.artemis.util.bytes.*; import tech.pegasys.artemis.util.uint.UInt64; import java.util.ArrayList; @@ -53,7 +52,20 @@ public static Deposit getDepositForKeyPair(Random rnd, public static synchronized Deposit getDepositForKeyPair(Random rnd, BLS381.KeyPair keyPair, BeaconChainSpec spec, Gwei initBalance, boolean isProofVerifyEnabled) { - Hash32 withdrawalCredentials = Hash32.random(rnd); + Hash32 credentials = Hash32.random(rnd); + List depositProof = Collections.singletonList(Hash32.random(rnd)); + return getDepositForKeyPair( + keyPair, credentials, initBalance, depositProof, spec, isProofVerifyEnabled); + } + + @NotNull + private static Deposit getDepositForKeyPair( + BLS381.KeyPair keyPair, + Hash32 withdrawalCredentials, + Gwei initBalance, + List depositProof, + BeaconChainSpec spec, + boolean isProofVerifyEnabled) { DepositData depositDataWithoutSignature = new DepositData( BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())), @@ -73,11 +85,11 @@ public static synchronized Deposit getDepositForKeyPair(Random rnd, Deposit deposit = Deposit.create( - Collections.singletonList(Hash32.random(rnd)), + depositProof, new DepositData( - BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())), - withdrawalCredentials, - spec.getConstants().getMaxEffectiveBalance(), + depositDataWithoutSignature.getPubKey(), + depositDataWithoutSignature.getWithdrawalCredentials(), + depositDataWithoutSignature.getAmount(), signature)); return deposit; } @@ -104,16 +116,70 @@ public static synchronized List getDepositsForKeyPairs( BeaconChainSpec spec, Gwei initBalance, boolean isProofVerifyEnabled) { + List withdrawalCredentials = generateRandomWithdrawalCredentials(rnd, keyPairs); + List> depositProofs = generateRandomDepositProofs(rnd, keyPairs); + return getDepositsForKeyPairs( + keyPairs, withdrawalCredentials, initBalance, depositProofs, spec, isProofVerifyEnabled); + } + @NotNull + public static List getDepositsForKeyPairs( + List keyPairs, + List withdrawalCredentials, + Gwei initBalance, + List> depositProofs, + BeaconChainSpec spec, + boolean isProofVerifyEnabled) { List deposits = new ArrayList<>(); - for (BLS381.KeyPair keyPair : keyPairs) { - deposits.add(getDepositForKeyPair(rnd, keyPair, spec, initBalance, isProofVerifyEnabled)); + for (int i = 0; i < keyPairs.size(); i++) { + BLS381.KeyPair keyPair = keyPairs.get(i); + Hash32 credentials = withdrawalCredentials.get(i); + List depositProof = depositProofs.get(i); + deposits.add(getDepositForKeyPair( + keyPair, credentials, initBalance, depositProof, spec, isProofVerifyEnabled)); } return deposits; } + @NotNull + public static List> generateRandomDepositProofs( + Random rnd, List keyPairs) { + List> depositProofs = new ArrayList<>(); + for (BLS381.KeyPair keyPair : keyPairs) { + List depositProof = Collections.singletonList(Hash32.random(rnd)); + depositProofs.add(depositProof); + } + return depositProofs; + } + + @NotNull + public static List generateRandomWithdrawalCredentials( + Random rnd, List keyPairs) { + List withdrawalCredentials = new ArrayList<>(); + for (BLS381.KeyPair keyPair : keyPairs) { + withdrawalCredentials.add(Hash32.random(rnd)); + } + return withdrawalCredentials; + } + + /** + * Generate withdrawal credentials according to mocked start spec. + * @See + */ + public static List generateInteropCredentials( + UInt64 blsWithdrawalPrefix, List keyPairs) { + List withdrawalCredentials = new ArrayList<>(); + for (BLS381.KeyPair keyPair : keyPairs) { + MutableBytes32 credentials = + Hashes.sha256(keyPair.getPublic().getEncodedBytes()).mutableCopy(); + credentials.set(0, blsWithdrawalPrefix.toBytes8().get(0)); + withdrawalCredentials.add(Hash32.wrap(credentials.copy())); + } + return withdrawalCredentials; + } + private static synchronized Pair, List> generateRandomDeposits( UInt64 startIndex, Random rnd, BeaconChainSpec spec, int count, boolean isProofVerifyEnabled) { List validatorsKeys = new ArrayList<>(); diff --git a/start/common/src/main/java/org/ethereum/beacon/start/common/util/SimulationKeyPairGenerator.java b/start/common/src/main/java/org/ethereum/beacon/start/common/util/SimulationKeyPairGenerator.java new file mode 100644 index 000000000..ee9114e2b --- /dev/null +++ b/start/common/src/main/java/org/ethereum/beacon/start/common/util/SimulationKeyPairGenerator.java @@ -0,0 +1,56 @@ +package org.ethereum.beacon.start.common.util; + +import com.google.common.primitives.Bytes; +import org.ethereum.beacon.crypto.BLS381; +import org.ethereum.beacon.crypto.Hashes; +import org.ethereum.beacon.crypto.bls.bc.BCParameters; +import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Key pair generation utilities for simulation purposes. + */ +public class SimulationKeyPairGenerator { + private static BigInteger CURVE_ORDER = BCParameters.ORDER; + + /** + * Generate public/private key pairs according to mocked start spec. + * @see + * Pubkey/privkey generation + * + * @param count - amount of key parirs to generate + * @return the generated key pairs + */ + public static List generateInteropKeys(int count) { + List ret = new ArrayList<>(); + for (int i = 0; i < count; i++) { + byte[] res = BigInteger.valueOf(i).toByteArray(); + Bytes.reverse(res); + BytesValue wrap = BytesValue.wrap(Bytes.ensureCapacity(res, 32, 0)); + byte[] res2 = Hashes.sha256(wrap).extractArray(); + Bytes.reverse(res2); + + BigInteger privKey = new BigInteger(1, res2).mod(CURVE_ORDER); + ret.add(BLS381.KeyPair.create(BLS381.PrivateKey.create(privKey))); + } + return ret; + } + + public static List generateRandomKeys(int seed, int start, int count) { + Random random = new Random(seed); + for (int i = 0; i < start; i++) { + Bytes32.random(random); + } + List ret = new ArrayList<>(); + for (int i = 0; i < count; i++) { + ret.add(BLS381.KeyPair.create(BLS381.PrivateKey.create(Bytes32.random(random)))); + } + return ret; + } +} diff --git a/test/src/test/java/org/ethereum/beacon/test/type/SpecConstantsDataMerged.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecConstantsDataMerged.java similarity index 95% rename from test/src/test/java/org/ethereum/beacon/test/type/SpecConstantsDataMerged.java rename to start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecConstantsDataMerged.java index 686cd332e..c47ef7407 100644 --- a/test/src/test/java/org/ethereum/beacon/test/type/SpecConstantsDataMerged.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecConstantsDataMerged.java @@ -1,7 +1,8 @@ -package org.ethereum.beacon.test.type; +package org.ethereum.beacon.emulator.config.chainspec; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonUnwrapped; +import org.ethereum.beacon.emulator.config.Config; import org.ethereum.beacon.emulator.config.chainspec.DepositContractParametersData; import org.ethereum.beacon.emulator.config.chainspec.GweiValuesData; import org.ethereum.beacon.emulator.config.chainspec.HonestValidatorParametersData; @@ -14,7 +15,7 @@ import org.ethereum.beacon.emulator.config.chainspec.TimeParametersData; @JsonIgnoreProperties(ignoreUnknown = false) -public class SpecConstantsDataMerged extends SpecConstantsData { +public class SpecConstantsDataMerged extends SpecConstantsData implements Config { @JsonUnwrapped private DepositContractParametersData depositContractParameters; @JsonUnwrapped private HonestValidatorParametersData honestValidatorParameters; @JsonUnwrapped private InitialValuesData initialValues; diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/main/ValidatorKeys.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/main/ValidatorKeys.java index ee1de7a5e..eb86a2b26 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/main/ValidatorKeys.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/main/ValidatorKeys.java @@ -9,6 +9,7 @@ @JsonSubTypes.Type(value = ValidatorKeys.Generate.class, name = "generate"), @JsonSubTypes.Type(value = ValidatorKeys.Private.class, name = "private"), @JsonSubTypes.Type(value = ValidatorKeys.Public.class, name = "public"), + @JsonSubTypes.Type(value = ValidatorKeys.InteropKeys.class, name = "interop"), }) public abstract class ValidatorKeys { @@ -42,6 +43,18 @@ public void setStartIndex(int startIndex) { } } + public static class InteropKeys extends ValidatorKeys { + private int count; + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + } + public static class ExplicitKeys extends ValidatorKeys { private List keys; diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/main/conract/EmulatorContract.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/main/conract/EmulatorContract.java index 96a9350be..e4463e340 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/main/conract/EmulatorContract.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/main/conract/EmulatorContract.java @@ -1,9 +1,12 @@ package org.ethereum.beacon.emulator.config.main.conract; import com.fasterxml.jackson.annotation.JsonFormat; +import org.ethereum.beacon.emulator.config.main.ValidatorKeys; +import tech.pegasys.artemis.util.bytes.Bytes32; + +import java.util.Arrays; import java.util.Date; import java.util.List; -import org.ethereum.beacon.emulator.config.main.ValidatorKeys; public class EmulatorContract extends Contract { @@ -12,6 +15,19 @@ public class EmulatorContract extends Contract { private Integer balance; private List keys; + private String eth1BlockHash = createInteropEth1BlockHash(); + private boolean interopCredentials = true; + + /** + * @return HEX String representation of a hash32 consisting of 32 0x42 bytes, which is the interop + * default. + */ + private static String createInteropEth1BlockHash() { + byte ch = 0x42; + byte[] res = new byte[32]; + Arrays.fill(res, ch); + return Bytes32.wrap(res).toString(); + } public Date getGenesisTime() { return genesisTime; @@ -36,4 +52,20 @@ public List getKeys() { public void setKeys(List keys) { this.keys = keys; } + + public String getEth1BlockHash() { + return eth1BlockHash; + } + + public void setEth1BlockHash(String eth1BlockHash) { + this.eth1BlockHash = eth1BlockHash; + } + + public boolean isInteropCredentials() { + return interopCredentials; + } + + public void setInteropCredentials(boolean interopCredentials) { + this.interopCredentials = interopCredentials; + } } diff --git a/start/node/src/main/java/org/ethereum/beacon/node/ConfigUtils.java b/start/node/src/main/java/org/ethereum/beacon/node/ConfigUtils.java index d0705756b..657f446f2 100644 --- a/start/node/src/main/java/org/ethereum/beacon/node/ConfigUtils.java +++ b/start/node/src/main/java/org/ethereum/beacon/node/ConfigUtils.java @@ -1,6 +1,5 @@ package org.ethereum.beacon.node; -import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.stream.Collectors; @@ -17,6 +16,7 @@ import org.ethereum.beacon.emulator.config.main.Signer.Insecure; import org.ethereum.beacon.emulator.config.main.ValidatorKeys; import org.ethereum.beacon.emulator.config.main.ValidatorKeys.Generate; +import org.ethereum.beacon.emulator.config.main.ValidatorKeys.InteropKeys; import org.ethereum.beacon.emulator.config.main.ValidatorKeys.Private; import org.ethereum.beacon.emulator.config.main.ValidatorKeys.Public; import org.ethereum.beacon.emulator.config.main.conract.Contract; @@ -24,6 +24,7 @@ import org.ethereum.beacon.pow.DepositContract; import org.ethereum.beacon.start.common.util.SimpleDepositContract; import org.ethereum.beacon.start.common.util.SimulateUtils; +import org.ethereum.beacon.start.common.util.SimulationKeyPairGenerator; import org.ethereum.beacon.validator.crypto.BLS381Credentials; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes32; @@ -66,15 +67,11 @@ public static List createKeyPairs(ValidatorKeys keys) { .collect(Collectors.toList()); } else if (keys instanceof Generate) { Generate genKeys = (Generate) keys; - Random random = new Random(genKeys.getSeed()); - for (int i = 0; i < genKeys.getStartIndex(); i++) { - Bytes32.random(random); - } - List ret = new ArrayList<>(); - for (int i = 0; i < genKeys.getCount(); i++) { - ret.add(KeyPair.create(PrivateKey.create(Bytes32.random(random)))); - } - return ret; + return SimulationKeyPairGenerator.generateRandomKeys( + genKeys.getSeed(), genKeys.getStartIndex(), genKeys.getCount()); + } else if (keys instanceof InteropKeys) { + InteropKeys interopKeys = (InteropKeys) keys; + return SimulationKeyPairGenerator.generateInteropKeys(interopKeys.getCount()); } else { throw new IllegalArgumentException("Unknown ValidatorKeys subclass: " + keys.getClass()); } @@ -89,23 +86,40 @@ public static DepositContract createDepositContract(Contract config, BeaconChain eConfig.getBalance() != null ? Gwei.ofEthers(eConfig.getBalance()) : spec.getConstants().getMaxEffectiveBalance(); - List deposits = - SimulateUtils.getDepositsForKeyPairs( - UInt64.ZERO, random, keyPairs, spec, amount, verifyProof); + + List deposits; + if (eConfig.isInteropCredentials()) { + // depostis with mocked start credentials for interop + List withdrawalCredentials = + SimulateUtils.generateInteropCredentials( + spec.getConstants().getBlsWithdrawalPrefix(), keyPairs); + // keep random proofs for now + List> depositProofs = + SimulateUtils.generateRandomDepositProofs(random, keyPairs); + deposits = + SimulateUtils.getDepositsForKeyPairs( + keyPairs, withdrawalCredentials, amount, depositProofs, spec, verifyProof); + } else { + deposits = + SimulateUtils.getDepositsForKeyPairs( + UInt64.ZERO, random, keyPairs, spec, amount, verifyProof); + } + ReadList depositDataList = ReadList.wrap( deposits.stream().map(Deposit::getData).collect(Collectors.toList()), Integer::new, 1L << spec.getConstants().getDepositContractTreeDepth().getIntValue()); + Hash32 blockHash = + eConfig.getEth1BlockHash() == null || eConfig.getEth1BlockHash().length() == 0 + ? Hash32.random(random) + : Hash32.wrap(Bytes32.fromHexString(eConfig.getEth1BlockHash())); Eth1Data eth1Data = new Eth1Data( - spec.hash_tree_root(depositDataList), - UInt64.valueOf(deposits.size()), - Hash32.random(random)); + spec.hash_tree_root(depositDataList), UInt64.valueOf(deposits.size()), blockHash); ChainStart chainStart = new ChainStart(Time.of(eConfig.getGenesisTime().getTime() / 1000), eth1Data, deposits); - SimpleDepositContract depositContract = new SimpleDepositContract(chainStart); - return depositContract; + return new SimpleDepositContract(chainStart); } else { throw new IllegalArgumentException( "This config class is not yet supported: " + config.getClass()); diff --git a/start/node/src/main/java/org/ethereum/beacon/node/Node.java b/start/node/src/main/java/org/ethereum/beacon/node/Node.java index 7ef7a62ef..5ba769354 100644 --- a/start/node/src/main/java/org/ethereum/beacon/node/Node.java +++ b/start/node/src/main/java/org/ethereum/beacon/node/Node.java @@ -91,6 +91,13 @@ public class Node implements Runnable { ) private String genesisTime; + @CommandLine.Option( + names = "--spec-constants", + paramLabel = "spec-constants", + description = "Path to a spec constants file in yaml format (flat format)" + ) + private String specConstantsFile; + public String getName() { return name; } @@ -111,6 +118,10 @@ public String getGenesisTime() { return genesisTime; } + public String getSpecConstantsFile() { + return specConstantsFile; + } + public static void main(String[] args) { try { CommandLine commandLine = new CommandLine(new Node()); diff --git a/start/node/src/main/java/org/ethereum/beacon/node/NodeCommandLauncher.java b/start/node/src/main/java/org/ethereum/beacon/node/NodeCommandLauncher.java index 9430172f7..8eabcc51b 100644 --- a/start/node/src/main/java/org/ethereum/beacon/node/NodeCommandLauncher.java +++ b/start/node/src/main/java/org/ethereum/beacon/node/NodeCommandLauncher.java @@ -32,6 +32,8 @@ import org.ethereum.beacon.emulator.config.ConfigBuilder; import org.ethereum.beacon.emulator.config.ConfigException; import org.ethereum.beacon.emulator.config.chainspec.SpecBuilder; +import org.ethereum.beacon.emulator.config.chainspec.SpecConstantsData; +import org.ethereum.beacon.emulator.config.chainspec.SpecConstantsDataMerged; import org.ethereum.beacon.emulator.config.chainspec.SpecData; import org.ethereum.beacon.emulator.config.main.MainConfig; import org.ethereum.beacon.emulator.config.main.Signer.Insecure; @@ -45,10 +47,15 @@ import org.ethereum.beacon.schedulers.Schedulers; import org.ethereum.beacon.start.common.NodeLauncher; import org.ethereum.beacon.start.common.util.MDCControlledSchedulers; +import org.ethereum.beacon.util.Objects; import org.ethereum.beacon.validator.crypto.BLS381Credentials; import org.ethereum.beacon.wire.net.ConnectionManager; import org.ethereum.beacon.wire.net.netty.NettyClient; import org.ethereum.beacon.wire.net.netty.NettyServer; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Paths; public class NodeCommandLauncher implements Runnable { private static final Logger logger = LogManager.getLogger("node"); @@ -206,6 +213,18 @@ public NodeCommandLauncher build() { ConfigBuilder specConfigBuilder = new ConfigBuilder<>(SpecData.class).addYamlConfigFromResources("/config/spec-constants.yml"); + + if (cliOptions != null + && cliOptions.getSpecConstantsFile() != null + && cliOptions.getSpecConstantsFile().length() > 0) { + SpecData chainSpec = config.getChainSpec(); + SpecConstantsDataMerged specConstantsYaml = + loadSpecConstantsDataMerged(cliOptions.getSpecConstantsFile()); + SpecConstantsData mergedConstants = + mergeSpecConstantsData(chainSpec.getSpecConstants(), specConstantsYaml); + chainSpec.setSpecConstants(mergedConstants); + config.setChainSpec(chainSpec); + } if (config.getChainSpec().isDefined()) { specConfigBuilder.addConfig(config.getChainSpec()); } @@ -333,6 +352,27 @@ public NodeCommandLauncher build() { logLevel); } + @NotNull + private static SpecConstantsData mergeSpecConstantsData(SpecConstantsData specConsts, SpecConstantsDataMerged specConstsYaml) { + if (specConsts == null) { + return specConstsYaml; + } else { + try { + return Objects.copyProperties(specConsts, specConstsYaml); + } catch (IllegalAccessException| InvocationTargetException e) { + throw new RuntimeException( + String.format("Failed to merge config %s into main config", specConsts), e); + } + } + } + + private static SpecConstantsDataMerged loadSpecConstantsDataMerged(String specConstants) { + ConfigBuilder specConstsBuilder = + new ConfigBuilder<>(SpecConstantsDataMerged.class); + specConstsBuilder.addYamlConfig(Paths.get(specConstants).toFile()); + return specConstsBuilder.build(); + } + public Builder withConfigFromFile(File file) { this.config = new ConfigBuilder<>(MainConfig.class).addYamlConfig(file).build(); return this; diff --git a/start/node/src/main/resources/config/default-node-config.yml b/start/node/src/main/resources/config/default-node-config.yml index fb3625c0c..dad4809a9 100644 --- a/start/node/src/main/resources/config/default-node-config.yml +++ b/start/node/src/main/resources/config/default-node-config.yml @@ -5,11 +5,13 @@ config: validator: contract: !emulator - balance: 55 + # balance: 55 keys: - - !generate + - !interop count: 16 - seed: 0 + # seed: 0 + interopCredentials: true + # eth1BlockHash: 0x4242424242424242424242424242424242424242424242424242424242424242 # signer: !insecure # keys: # - !generate @@ -40,4 +42,6 @@ chainSpec: blsVerifyProofOfPossession: false blsSign: false enableCache: false + # for interop, genesis time should be overridden with the specified value, so ignore computation + computableGenesisTime: true diff --git a/test/src/test/java/org/ethereum/beacon/test/TestUtils.java b/test/src/test/java/org/ethereum/beacon/test/TestUtils.java index 4d789c4e4..62c5fc733 100644 --- a/test/src/test/java/org/ethereum/beacon/test/TestUtils.java +++ b/test/src/test/java/org/ethereum/beacon/test/TestUtils.java @@ -9,6 +9,7 @@ import org.ethereum.beacon.core.spec.SpecConstantsResolver; import org.ethereum.beacon.emulator.config.chainspec.SpecBuilder; import org.ethereum.beacon.emulator.config.chainspec.SpecConstantsData; +import org.ethereum.beacon.emulator.config.chainspec.SpecConstantsDataMerged; import org.ethereum.beacon.emulator.config.chainspec.SpecData; import org.ethereum.beacon.emulator.config.chainspec.SpecDataUtils; import org.ethereum.beacon.emulator.config.chainspec.SpecHelpersData; @@ -17,7 +18,6 @@ import org.ethereum.beacon.ssz.SSZBuilder; import org.ethereum.beacon.ssz.SSZSerializer; import org.ethereum.beacon.test.type.DataMapperTestCase; -import org.ethereum.beacon.test.type.SpecConstantsDataMerged; import org.ethereum.beacon.test.type.TestCase; import org.ethereum.beacon.test.type.ssz.SszGenericCase; import org.ethereum.beacon.test.type.ssz.SszStaticCase; diff --git a/versions.gradle b/versions.gradle index 6e33972a9..73d0030f3 100644 --- a/versions.gradle +++ b/versions.gradle @@ -38,7 +38,7 @@ dependencyManagement { dependency "info.picocli:picocli:3.9.4" dependency "io.netty:netty-all:4.1.36.Final" - dependency "org.rocksdb:rocksdbjni:5.5.1" + dependency "org.rocksdb:rocksdbjni:6.2.2" dependency "com.googlecode.concurrent-locks:concurrent-locks:1.0.0" } }