Skip to content

Commit

Permalink
Merge pull request #1185 from ethereum/sharding/committees
Browse files Browse the repository at this point in the history
[WIP] Attestation committees
  • Loading branch information
mkalinin committed Sep 26, 2018
2 parents 89e417c + 4613efc commit 82af2ac
Show file tree
Hide file tree
Showing 36 changed files with 1,326 additions and 214 deletions.
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);
}
}

0 comments on commit 82af2ac

Please sign in to comment.