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

[WIP] Attestation committees #1185

Merged
merged 14 commits into from Sep 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -129,7 +129,8 @@ public ValidatorService validatorService() {
@Bean
public ProposerService proposerService() {
if (validatorConfig().isEnabled()) {
ProposerService proposerService = new ProposerServiceImpl(beaconProposer(), beaconChain(), publisher());
ProposerService proposerService = new ProposerServiceImpl(beaconProposer(), beaconChain(),
publisher(), validatorConfig());
shardingWorldManager.setProposerService(proposerService);
return proposerService;
} else {
Expand Down Expand Up @@ -159,8 +160,9 @@ public BeaconStore beaconStore() {
public StateRepository beaconStateRepository() {
Source<byte[], byte[]> src = cachedBeaconChainSource("beacon_state");
Source<byte[], byte[]> validatorSrc = cachedBeaconChainSource("validator_set");
Source<byte[], byte[]> validatorIndexSrc = cachedBeaconChainSource("validator_index");
Source<byte[], byte[]> crystallizedSrc = cachedBeaconChainSource("crystallized_state");
return new BeaconStateRepository(src, crystallizedSrc, validatorSrc);
return new BeaconStateRepository(src, crystallizedSrc, validatorSrc, validatorIndexSrc);
}

@Bean
Expand Down Expand Up @@ -217,7 +219,7 @@ public Publisher publisher() {
@Bean
public BeaconProposer beaconProposer() {
return new BeaconProposerImpl(ethereum, publisher(), randao(), beaconStateRepository(),
BeaconChainFactory.stateTransition(validatorRepository()));
BeaconChainFactory.stateTransition(validatorRepository()), validatorConfig());
}

@Bean
Expand Down
Expand Up @@ -36,25 +36,33 @@ public class Validator {
private long withdrawalShard;
private byte[] withdrawalAddress;
private byte[] randao;
private int index = -1;

public Validator(byte[] encoded) {
RLPList list = RLP.unwrapList(encoded);

this.pubKey = list.get(0).getRLPData();
this.withdrawalShard = ByteUtil.bytesToBigInteger(list.get(1).getRLPData()).longValue();
this.withdrawalShard = ByteUtil.byteArrayToLong(list.get(1).getRLPData());
this.withdrawalAddress = list.get(2).getRLPData();
this.randao = list.get(3).getRLPData();
this.index = ByteUtil.byteArrayToInt(list.get(4).getRLPData());
}

public Validator(byte[] pubKey, long withdrawalShard, byte[] withdrawalAddress, byte[] randao) {
this(pubKey, withdrawalShard, withdrawalAddress, randao, -1);
}

public Validator(byte[] pubKey, long withdrawalShard, byte[] withdrawalAddress, byte[] randao, int index) {
this.pubKey = pubKey;
this.withdrawalShard = withdrawalShard;
this.withdrawalAddress = withdrawalAddress;
this.randao = randao;
this.index = index;
}

public byte[] getEncoded() {
return RLP.wrapList(pubKey, BigInteger.valueOf(withdrawalShard).toByteArray(), withdrawalAddress, randao);
return RLP.wrapList(pubKey, ByteUtil.longToBytes(withdrawalShard), withdrawalAddress,
randao, ByteUtil.intToBytes(index));
}

public byte[] getPubKey() {
Expand All @@ -73,6 +81,14 @@ public byte[] getRandao() {
return randao;
}

public int getIndex() {
return index;
}

public Validator withIndex(int index) {
return new Validator(pubKey, withdrawalShard, withdrawalAddress, randao, index);
}

public static final Serializer<Validator, byte[]> Serializer = new Serializer<Validator, byte[]>() {
@Override
public byte[] serialize(Validator validator) {
Expand Down
Expand Up @@ -148,7 +148,7 @@ public void setProposerService(final ProposerService proposerService) {
// start only if validator is enlisted and after sync is finished
publisher.subscribe(BeaconChainSynced.class, data -> {
if (validatorService.getState() == ValidatorService.State.Enlisted) {
proposerService.init();
proposerService.init(data.getState());
}
});
}
Expand All @@ -157,7 +157,10 @@ public void setBeaconChain(final BeaconChain beaconChain) {
// PoC mode:
// wait for validator initialization
// it's needed to be sure that the validator is registered before beacon genesis state calculation
validatorServiceInit.runAfterBothAsync(contractInit, beaconChain::init);
validatorServiceInit.runAfterBothAsync(contractInit, () -> {
beaconChain.setBestBlock(getBlockchain().getBestBlock());
beaconChain.init();
});
}

public void setPublisher(Publisher publisher) {
Expand Down
Expand Up @@ -17,6 +17,7 @@
*/
package org.ethereum.sharding.processing;

import org.ethereum.core.Block;
import org.ethereum.sharding.domain.Beacon;
import org.ethereum.sharding.processing.consensus.ScoreFunction;
import org.ethereum.sharding.processing.consensus.StateTransition;
Expand Down Expand Up @@ -52,4 +53,10 @@ public interface BeaconChain {
* @see StateTransition
*/
ProcessingResult insert(Beacon block);

/**
* A hack for PoC mode, sets genesis mainChainRef to given block.
* Thus, makes initial validator induction pass correctly.
*/
void setBestBlock(Block block);
}
Expand Up @@ -17,7 +17,9 @@
*/
package org.ethereum.sharding.processing;

import org.ethereum.core.Block;
import org.ethereum.db.DbFlushManager;
import org.ethereum.sharding.processing.consensus.GenesisTransition;
import org.ethereum.sharding.pubsub.Event;
import org.ethereum.sharding.pubsub.Publisher;
import org.ethereum.sharding.processing.consensus.ScoreFunction;
Expand Down Expand Up @@ -89,7 +91,7 @@ public void init() {
repository.get(store.getCanonicalHead().getStateHash()));

publish(onBeaconChainLoaded(canonicalHead.block));
publish(onBeaconChainSynced(canonicalHead.block));
publish(onBeaconChainSynced(canonicalHead.block, canonicalHead.state));

logger.info("Chain loaded with head: {}", canonicalHead.block);
}
Expand Down Expand Up @@ -155,13 +157,18 @@ public synchronized ProcessingResult insert(Beacon block) {
ProcessingResult res = canonicalHead.equals(newHead) ? ProcessingResult.Best : ProcessingResult.NotBest;

// publish beacon block event
publish(onBeaconBlock(block, res == ProcessingResult.Best));
publish(onBeaconBlock(block, newState, res == ProcessingResult.Best));

logger.info("Process block {}, status: {}", block.toString(), res);

return res;
}

@Override
public void setBestBlock(Block block) {
((GenesisTransition) genesisStateTransition).withMainChainRef(block.getHash());
}

private Beacon pullParent(Beacon block) {
if (canonicalHead.block.isParentOf(block))
return canonicalHead.block;
Expand Down
Expand Up @@ -34,7 +34,7 @@ public interface BeaconConstants {
/**
* Number of slots in each cycle
*/
long CYCLE_LENGTH = 64;
int CYCLE_LENGTH = 64;

/**
* Number of shards
Expand All @@ -50,4 +50,14 @@ public interface BeaconConstants {
* Validator registration deposit in wei
*/
BigInteger DEPOSIT_WEI = convert(32, EtherUtil.Unit.ETHER);

/**
* Minimal number of validators in shard attestation committee
*/
int MIN_COMMITTEE_SIZE = 128;

/**
* Slot duration for the beacon chain
*/
long SLOT_DURATION = 8 * 1000; // 8 seconds
}
@@ -1,35 +1,52 @@
/*
* Copyright (c) [2016] [ <ether.camp> ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ethereum.sharding.processing.consensus;

import org.ethereum.sharding.domain.Beacon;
import org.ethereum.sharding.processing.db.ValidatorSet;
import org.ethereum.sharding.processing.state.BeaconState;
import org.ethereum.sharding.processing.state.CrystallizedState;
import org.ethereum.sharding.processing.state.Dynasty;
import org.ethereum.sharding.processing.state.Finality;
import org.ethereum.sharding.service.ValidatorRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.ethereum.sharding.processing.consensus.BeaconConstants.CYCLE_LENGTH;
import static org.ethereum.sharding.util.BeaconUtils.cycleStartSlot;

/**
* @author Mikhail Kalinin
* @since 12.09.2018
*/
public class BeaconStateTransition implements StateTransition<BeaconState> {

StateTransition<ValidatorSet> validatorSetTransition;
private static final Logger logger = LoggerFactory.getLogger("beacon");

StateTransition<Dynasty> dynastyTransition;
StateTransition<Finality> finalityTransition;

public BeaconStateTransition(ValidatorRepository validatorRepository) {
this.validatorSetTransition = new ValidatorSetTransition(validatorRepository);
this.dynastyTransition = new DynastyTransition();
this.dynastyTransition = new DynastyTransition(new ValidatorSetTransition(validatorRepository));
this.finalityTransition = new FinalityTransition();
}

public BeaconStateTransition(StateTransition<ValidatorSet> validatorSetTransition,
StateTransition<Dynasty> dynastyTransition,
public BeaconStateTransition(StateTransition<Dynasty> dynastyTransition,
StateTransition<Finality> finalityTransition) {
this.validatorSetTransition = validatorSetTransition;
this.dynastyTransition = dynastyTransition;
this.finalityTransition = finalityTransition;
}
Expand All @@ -40,14 +57,15 @@ public BeaconState applyBlock(Beacon block, BeaconState to) {
CrystallizedState crystallized = to.getCrystallizedState();

if (block.getSlotNumber() - crystallized.getLastStateRecalc() >= CYCLE_LENGTH) {
logger.info("Calculate new crystallized state, slot: {}, prev slot: {}",
block.getSlotNumber(), crystallized.getLastStateRecalc());

Finality finality = finalityTransition.applyBlock(block, crystallized.getFinality());
ValidatorSet validatorSet = validatorSetTransition.applyBlock(block, crystallized.getDynasty().getValidatorSet());
Dynasty dynasty = crystallized.getDynasty().withValidatorSet(validatorSet);
dynasty = dynastyTransition.applyBlock(block, dynasty);
Dynasty dynasty = dynastyTransition.applyBlock(block, crystallized.getDynasty());

crystallized = crystallized
.withDynasty(dynasty)
.withLastStateRecalcIncrement(CYCLE_LENGTH)
.withLastStateRecalc(cycleStartSlot(block))
.withFinality(finality);
}

Expand Down
@@ -0,0 +1,52 @@
/*
* Copyright (c) [2016] [ <ether.camp> ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ethereum.sharding.processing.consensus;

import org.ethereum.sharding.processing.state.Committee;

/**
* An interface of committee factory.
*
* <p>
* Used to produce new shards and committees array.
*
* <p>
* in: {@code [validators]} <br/>
* out: {@code [slot: [shardId, [validators]]]}
*
*
* @see Committee
*
* @author Mikhail Kalinin
* @since 14.09.2018
*/
public interface CommitteeFactory {

/**
* Creates new committees set.
*
* @param seed seed for random shuffling
* @param validators array of active validator numbers
* @param startShard shard id that first committee in resulting array will be assigned to
*
* @return shards and committee array for each slot of cycle
*
* @see BeaconConstants#CYCLE_LENGTH
*/
Committee[][] create(byte[] seed, int[] validators, int startShard);
}
@@ -1,20 +1,66 @@
/*
* Copyright (c) [2016] [ <ether.camp> ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ethereum.sharding.processing.consensus;

import org.ethereum.sharding.domain.Beacon;
import org.ethereum.sharding.processing.db.ValidatorSet;
import org.ethereum.sharding.processing.state.Committee;
import org.ethereum.sharding.processing.state.Dynasty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.ethereum.sharding.processing.consensus.BeaconConstants.CYCLE_LENGTH;
import static org.ethereum.sharding.processing.consensus.BeaconConstants.MIN_DYNASTY_LENGTH;
import static org.ethereum.sharding.util.BeaconUtils.cycleStartSlot;

/**
* @author Mikhail Kalinin
* @since 12.09.2018
*/
public class DynastyTransition implements StateTransition<Dynasty> {

private static final Logger logger = LoggerFactory.getLogger("beacon");

StateTransition<ValidatorSet> validatorSetTransition;
CommitteeFactory committeeFactory = new ShufflingCommitteeFactory();

public DynastyTransition(StateTransition<ValidatorSet> validatorSetTransition) {
this.validatorSetTransition = validatorSetTransition;
}

@Override
public Dynasty applyBlock(Beacon block, Dynasty to) {
if (block.getSlotNumber() - to.getStartSlot() < BeaconConstants.MIN_DYNASTY_LENGTH)
if (block.getSlotNumber() - to.getStartSlot() < MIN_DYNASTY_LENGTH)
return to;

logger.info("Calculate new dynasty, slot: {}, prev slot: {}", block.getSlotNumber(), to.getStartSlot());

// validator set transition
ValidatorSet validatorSet = validatorSetTransition.applyBlock(block, to.getValidatorSet());

// committee transition
int startShard = to.getCommitteesEndShard() + 1;
int[] validators = validatorSet.getActiveIndices();
Committee[][] committees = committeeFactory.create(block.getHash(), validators, startShard);

return to.withNumberIncrement(1L)
.withCrosslinkingStartShardIncrement(1L);
.withStartSlot(cycleStartSlot(block))
.withValidatorSet(validatorSet)
.withCommittees(committees);
}
}