Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Hash32> 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<Hash32> depositProof,
BeaconChainSpec spec,
boolean isProofVerifyEnabled) {
DepositData depositDataWithoutSignature =
new DepositData(
BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())),
Expand All @@ -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;
}
Expand All @@ -104,16 +116,70 @@ public static synchronized List<Deposit> getDepositsForKeyPairs(
BeaconChainSpec spec,
Gwei initBalance,
boolean isProofVerifyEnabled) {
List<Hash32> withdrawalCredentials = generateRandomWithdrawalCredentials(rnd, keyPairs);
List<List<Hash32>> depositProofs = generateRandomDepositProofs(rnd, keyPairs);
return getDepositsForKeyPairs(
keyPairs, withdrawalCredentials, initBalance, depositProofs, spec, isProofVerifyEnabled);
}

@NotNull
public static List<Deposit> getDepositsForKeyPairs(
List<BLS381.KeyPair> keyPairs,
List<Hash32> withdrawalCredentials,
Gwei initBalance,
List<List<Hash32>> depositProofs,
BeaconChainSpec spec,
boolean isProofVerifyEnabled) {
List<Deposit> 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<Hash32> depositProof = depositProofs.get(i);
deposits.add(getDepositForKeyPair(
keyPair, credentials, initBalance, depositProof, spec, isProofVerifyEnabled));
}

return deposits;
}

@NotNull
public static List<List<Hash32>> generateRandomDepositProofs(
Random rnd, List<BLS381.KeyPair> keyPairs) {
List<List<Hash32>> depositProofs = new ArrayList<>();
for (BLS381.KeyPair keyPair : keyPairs) {
List<Hash32> depositProof = Collections.singletonList(Hash32.random(rnd));
depositProofs.add(depositProof);
}
return depositProofs;
}

@NotNull
public static List<Hash32> generateRandomWithdrawalCredentials(
Random rnd, List<BLS381.KeyPair> keyPairs) {
List<Hash32> withdrawalCredentials = new ArrayList<>();
for (BLS381.KeyPair keyPair : keyPairs) {
withdrawalCredentials.add(Hash32.random(rnd));
}
return withdrawalCredentials;
}

/**
* Generate withdrawal credentials according to mocked start spec.
* @See <a href="https://github.com/ethereum/eth2.0-pm/tree/master/interop/mocked_start#generate-deposits"/>
*/
public static List<Hash32> generateInteropCredentials(
UInt64 blsWithdrawalPrefix, List<BLS381.KeyPair> keyPairs) {
List<Hash32> 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<Deposit>, List<BLS381.KeyPair>> generateRandomDeposits(
UInt64 startIndex, Random rnd, BeaconChainSpec spec, int count, boolean isProofVerifyEnabled) {
List<BLS381.KeyPair> validatorsKeys = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <a
* href="https://github.com/ethereum/eth2.0-pm/tree/master/interop/mocked_start#pubkeyprivkey-generation">
* Pubkey/privkey generation</a>
*
* @param count - amount of key parirs to generate
* @return the generated key pairs
*/
public static List<BLS381.KeyPair> generateInteropKeys(int count) {
List<BLS381.KeyPair> 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<BLS381.KeyPair> generateRandomKeys(int seed, int start, int count) {
Random random = new Random(seed);
for (int i = 0; i < start; i++) {
Bytes32.random(random);
}
List<BLS381.KeyPair> ret = new ArrayList<>();
for (int i = 0; i < count; i++) {
ret.add(BLS381.KeyPair.create(BLS381.PrivateKey.create(Bytes32.random(random))));
}
return ret;
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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<String> keys;

Expand Down
Original file line number Diff line number Diff line change
@@ -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 {

Expand All @@ -12,6 +15,19 @@ public class EmulatorContract extends Contract {

private Integer balance;
private List<ValidatorKeys> 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;
Expand All @@ -36,4 +52,20 @@ public List<ValidatorKeys> getKeys() {
public void setKeys(List<ValidatorKeys> 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;
}
}
50 changes: 32 additions & 18 deletions start/node/src/main/java/org/ethereum/beacon/node/ConfigUtils.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -17,13 +16,15 @@
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;
import org.ethereum.beacon.emulator.config.main.conract.EmulatorContract;
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;
Expand Down Expand Up @@ -66,15 +67,11 @@ public static List<KeyPair> 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<KeyPair> 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());
}
Expand All @@ -89,23 +86,40 @@ public static DepositContract createDepositContract(Contract config, BeaconChain
eConfig.getBalance() != null
? Gwei.ofEthers(eConfig.getBalance())
: spec.getConstants().getMaxEffectiveBalance();
List<Deposit> deposits =
SimulateUtils.getDepositsForKeyPairs(
UInt64.ZERO, random, keyPairs, spec, amount, verifyProof);

List<Deposit> deposits;
if (eConfig.isInteropCredentials()) {
// depostis with mocked start credentials for interop
List<Hash32> withdrawalCredentials =
SimulateUtils.generateInteropCredentials(
spec.getConstants().getBlsWithdrawalPrefix(), keyPairs);
// keep random proofs for now
List<List<Hash32>> 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<Integer, DepositData> 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());
Expand Down
Loading